intershapes
What will you shape today?
Interfaces are canon. Shapes are skins.
A methodology for component design that separates what data a component needs from how it looks — enabling intelligent composition, AI-driven surfacing, and true design system scalability.
The problem
Component design today conflates two distinct concerns.
When you build a UserCard component, two concerns are fused together: what data it needs and how it renders. The interface and the visual presentation are one and the same.
This makes it surprisingly hard to do things that should be simple. Showing the same data in a different layout means building a new component. Letting an AI suggest an appropriate rendering means the AI has to understand visual code, not just data contracts. Scaling a design system means scaling components, not concepts.
The result is variant hell. A Button needs a size, a variant, a state, an icon option. Multiply the dimensions together and you get dozens of named components — each with its own props, its own documentation, its own tests. Add a new dimension and the count multiplies again. The growth is exponential, not linear.
Atomic design gave us a vocabulary — atoms, molecules, organisms — but it didn't give us separation of concerns between the data contract and its visual expression. Intershapes does.
The Intershapes model
Separate what from how. Inject the look. Let intelligence connect them.
An interface is the canonical type contract for a component. It defines what data is consumed — think TypeScript types, GraphQL schemas, or any structured contract. The interface is the source of truth. It is stable, versioned, and machine-readable.
A shape is a visual representation that conforms to an interface. It takes in the data described by the interface and renders it. Shapes are ephemeral — they come and go. Multiple shapes can satisfy the same interface: a card, a profile page, an inline mention. Each is a different expression of the same data. Add a new one, retire an old one, swap them freely.
A theme is an injectable set of design tokens that controls how a shape looks. Colours, spacing, typography, shadows — these are not baked into the shape. They are injected. Shapes define structure. Themes define appearance.
Surfacing is the act of selecting the right shape and theme for a given interface in context. It can be done by a human designer, a rules engine, or an AI system. Because interfaces are machine-readable contracts, any system can reason about which combination fits best.
One interface defines the data contract. Multiple shapes render it differently. The surfacing layer selects the right shape for the context.
Principles
The ideas that underpin Intershapes.
Interfaces are canon
The type contract is the stable foundation. It defines what data flows through a component, not how it looks. Interfaces are versioned, shared, and machine-readable.
Shapes are ephemeral
Visual representations come and go. They are different structural expressions of the same data — a card, a row, a mention. Add new ones, retire old ones, swap freely. The interface stays stable. Shapes don't have to.
Themes are how it looks
Design tokens — colours, spacing, typography — are not baked into shapes. They are injected. The same shape can wear a light theme, a dark theme, or a brand theme. Shapes define structure. Themes define appearance.
Separation enables intelligence
When you separate what from how, AI can reason about both independently. It can match data to the best visual expression for any context, device, or user preference.
Composition over inheritance
Interfaces compose into larger interfaces. Shapes compose into layouts. Build up, don't branch out. Complexity is managed through composition, not proliferation.
Prior art as protocol
By publishing interfaces openly, they become shared contracts. Others can build shapes for your interfaces. Your shapes can render their data. The ecosystem grows.
How it works
Define an interface. Build shapes. Surface them intelligently.
Define the interface
The interface is a TypeScript type that describes the data contract. Nothing about presentation. Pure data shape.
interface UserProfile {
name: string
avatar: string
role: "admin" | "member" | "guest"
joinedAt: Date
} Create shapes
Each shape implements the same interface but renders it differently. A card for dashboards, a profile for detail views, an inline mention for text. Shapes are disposable — create new ones whenever the context demands it.
const CardShape = ({
data: UserProfile
}) => (
<Card>
<Avatar />
<Name />
<Role />
</Card>
) const ProfileShape = ({
data: UserProfile
}) => (
<Profile>
<LargeAvatar />
<FullName />
<Details />
</Profile>
) const MentionShape = ({
data: UserProfile
}) => (
<Inline>
<SmallAvatar />
<Name />
<Badge />
</Inline>
) Inject a theme
Themes supply the visual layer — colours, spacing, typography, shadows. They are injected into shapes at render time using CSS @scope. The same card shape can look minimal and light, dense and dark, or bold and branded. The HTML stays the same. The tokens change.
<article>
<img src="avatar.jpg" alt="Alan White" />
<h3>Alan White</h3>
<span>Admin</span>
<time>January 2024</time>
</article> @scope (article) {
:scope {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: var(--space-4);
}
h3 { color: var(--ink) }
span { color: var(--ink-muted) }
img { border-radius: var(--radius-full) }
} @scope (article) {
:scope {
background: var(--surface-dark);
border: 1px solid var(--border-dark);
border-radius: var(--radius-lg);
padding: var(--space-4);
}
h3 { color: var(--ink-inverse) }
span { color: var(--ink-muted-dark) }
img { border-radius: var(--radius-sm) }
} Same markup. Different tokens. The shape never changes — only the theme does.
Alan White
AdminIdentical shape. Two themes. The structure didn't change — the tokens did.
Same shape, different emphasis
Multiple instances of the same shape can appear on one page, each wearing a different theme. A comment thread is a good example — every comment uses the same CommentShape, but your comment gets a prominent theme to stand out. No new component needed. Same shape. Different tokens.
This looks great, love the direction. Should we add a loading state to the card?
Good call — the interface already has an optional loading?: boolean field. We just need a shape that handles it.
Makes sense. Same contract, the shape just renders a skeleton when loading is true.
@scope (.comment) {
:scope {
background: var(--surface);
}
} @scope (.comment.mine) {
:scope {
background: var(--surface-highlight);
border-left: 3px solid var(--accent);
}
.author { color: var(--accent) }
}
Every comment is the same shape. The "you" theme just injects different tokens — a highlighted background, an accent border, a bolder author colour. No MyComment vs OtherComment components. One shape. Two themes. Context decides.
Surface intelligently
Given an interface and a context, the surfacing layer figures out which shape and theme to use — and which fields matter. This can be a developer making the call, a rules engine, or an AI. Pick a context and watch the reasoning.
Waiting for context...
How it compares
Intershapes builds on existing ideas but adds a critical separation.
| Aspect | Traditional Components | Design Tokens | Intershapes |
|---|---|---|---|
| Data contract | Implicit in props | N/A | Explicit interface |
| Visual variation | Component variants | Theme values | Independent shapes + injectable themes |
| Structure | Coupled to styling | N/A | Immutable HTML — markup never changes |
| Theming | Baked into each variant | Global token swaps | Injected per shape at render time |
| AI compatibility | Low | Low | High — machine-readable contracts |
| Reusability | Per-component | Per-token | Per-interface across shapes and themes |
| Scalability | Exponential variant growth | Theme-bound | Linear — new shapes and themes compose |
Build a shape.
Publish an interface.
Join the conversation.
Intershapes is public domain. The methodology belongs to everyone. Define interfaces, create shapes, and help build an AI-first design system vocabulary that scales.