Shape Set

A shape set is the proposed way to expose a shape library. For every interface, you publish the available shapes and the themes they support — giving consumers a complete map of what's available.

Below is the shape set for intershapes.com, built with Astro. Switch themes to inspect every shape across all four token sets.

22 interfaces 30 shapes 10 primitives 4 themes
theme

Primitives

Atomic building blocks used across shapes. Styled with @scope([data-primitive]). No formal interface file — props defined inline.

Layout

primitive PageSection
tight
standard
hero
<PageSection size="standard">…</PageSection>
primitive PageContainer
7xl
lg
sm
<PageContainer width="7xl">…</PageContainer>
primitive Grid
3 × 3
<Grid cols={3} gap="sm">…</Grid>
primitive Cluster
A B C D E
flex · wrap
<Cluster gap="md" wrap={true}>…</Cluster>

Content

primitive Avatar
AW AW AW
sm · md · lg
<Avatar initials="AW" size="md" />
primitive Badge
Admin Member New
<Badge text="Admin" />
primitive Timestamp
<Timestamp text="2 hours ago" size="sm" />
primitive ColorDot
interface
shape
ink
white
green
<ColorDot color="interface" />  <!-- 'interface' | 'shape' | 'white' | 'green' | 'ink' -->
primitive NumberCircle
1 2 3
<NumberCircle number={1} color="interface" />
primitive BackLink
<BackLink href="/" label="Back to Intershapes" />

Profile

3 shapes for the UserProfile interface.

export interface UserProfile {
  name: string
  initials: string
  role: string
  joinedAt?: string
}
profile Horizontal
AW

Alan White

Admin
<ProfileHorizontal data={user} />
profile Vertical
AW

Alan White

Admin
<ProfileVertical data={user} />
profile Inline

Written by AW Alan White in the design channel.

Written by <ProfileInline data={user} /> in the channel.

Communication

Chat messages, comments, and notifications.

ChatMessage

export interface ChatMessage {
  role: 'user' | 'ai'
  content: string
  color?: 'interface' | 'shape'
}
chatmessage User
You

How should I render a UserProfile in a sidebar?

<ChatMessageUser data={{ content: "How should I render a UserProfile?" }} theme="light" />
chatmessage AI reasoning

Considering the sidebar context, a horizontal profile with compact spacing works best.

<ChatMessageAI data={{
  content: "Use ProfileHorizontal with dark theme.",
  variant: "done"  <!-- 'reasoning' | 'sub' | 'done' -->
}} theme="light"   <!-- 'light' | 'dark' | 'brand' | 'elevated' -->
/>
chatmessage AI done

Use ProfileHorizontal with the dark theme for sidebar context.

<ChatMessageAI data={{ content: "Use ProfileHorizontal...", variant: "done" }} />

Comment

export interface Comment {
  body: string
  timestamp: string
}
comment Thread
Sarah Kim

This looks great, love the separation of concerns here.

<CommentThread data={{ body: "Looks great!", timestamp: "2 hours ago" }} theme="light">
  <span slot="author">Sarah Kim</span>
</CommentThread>
comment Compact
Marcus Jones

Agreed, the interface/shape split makes this much cleaner.

<CommentCompact data={{ body: "Agreed.", timestamp: "45 min ago" }} theme="light">
  <span slot="author">Marcus Jones</span>
</CommentCompact>

Notification

export interface Notification {
  title: string
  body: string
  timestamp: string
  type?: 'info' | 'success' | 'warning' | 'error'
}
notification Card info
Info

New shape available

ProfileVertical has been added to the shape library.

<NotificationCard data={{
  title: "New shape available",
  body: "ProfileVertical has been added.",
  timestamp: "Just now",
  type: "info"  <!-- 'info' | 'success' | 'warning' | 'error' -->
}} />
notification Card success
Success

Theme deployed

The dark theme has been published.

<NotificationCard data={{ title: "Theme deployed", body: "...", timestamp: "5 min ago", type: "success" }} />
notification Card warning
Warning

Token mismatch

The brand theme is missing --code-bg.

<NotificationCard data={{ title: "Token mismatch", body: "...", timestamp: "1 hour ago", type: "warning" }} />
notification Card error
Error

Build failed

Shape compilation failed.

<NotificationCard data={{ title: "Build failed", body: "...", timestamp: "2 hours ago", type: "error" }} />
notification Row info

Interface updated

UserProfile v2 is now available.

<NotificationRow data={{
  title: "Interface updated",
  body: "UserProfile v2 is now available.",
  timestamp: "3 min ago",
  type: "info"
}} />
notification Row error

Validation error

Required field 'name' is missing.

<NotificationRow data={{ title: "Validation error", body: "...", timestamp: "10 min ago", type: "error" }} />

Content

Cards, callouts, code panels, principle cards, interface cards, and stat boxes.

Card

export interface Card {
  title: string
  accent?: 'interface' | 'shape' | 'ink'
}
card Default interface

Interface layer

The stable contract that shapes implement.

<CardDefault data={{ title: "Interface layer", accent: "interface" }}>
  <p>Content goes here.</p>
</CardDefault>
card Default shape

Shape layer

Visual expressions that come and go freely.

<CardDefault data={{ title: "Shape layer", accent: "shape" }}>
  <p>Visual expressions that come and go freely.</p>
</CardDefault>
card Default ink

Theme layer

Colour tokens injected by the nearest ancestor.

<CardDefault data={{ title: "Theme layer", accent: "ink" }}>
  <p>Colour tokens injected by the nearest ancestor.</p>
</CardDefault>

Callout

export interface Callout {
  title?: string
  body: string
  variant?: 'default' | 'interface' | 'muted'
}
callout Box default

Key concept

Interfaces are stable contracts. Shapes are replaceable.

<CalloutBox data={{
  title: "Key concept",
  body: "Interfaces are stable contracts.",
  variant: "interface"  <!-- 'default' | 'interface' | 'muted' -->
}} />
callout Box interface

Interface tip

Keep interfaces minimal.

<CalloutBox data={{ title: "Interface tip", body: "Keep interfaces minimal.", variant: "interface" }} />
callout Box muted

Themes own colour. Shapes own spacing.

<CalloutBox data={{ body: "Themes own colour...", variant: "muted" }} />

CodePanel

export interface CodePanel {
  label: string
  dotColor?: 'interface' | 'shape' | 'white' | 'green'
  code: string
}
codepanel Block
Interface &mdash; Button
interface Button {
  label: string
  variant: "primary" | "secondary"
}
<CodePanelBlock data={{
  label: "Interface — Button",
  dotColor: "interface",  <!-- 'interface' | 'shape' | 'white' | 'green' -->
  code: highlightedHtml
}} theme="dark"          <!-- 'light' | 'dark' | 'brand' | 'elevated' -->
/>
codepanel Block shape dot
Shape &mdash; Card
const CardShape = () => (
  <article><Avatar /><Name /></article>
)
codepanel Inline

The UserProfile interface defines the data contract.

The <CodePanelInline code="UserProfile" /> interface defines the contract.

Principle

export interface Principle {
  number: number
  title: string
  description: string
  accent?: 'interface' | 'shape'
}
principle Card interface
01

Interfaces are canon

The type contract is the stable foundation.

<PrincipleCard data={{
  number: 1,
  title: "Interfaces are canon",
  description: "The type contract is the stable foundation.",
  accent: "interface"  <!-- 'interface' | 'shape' -->
}} />
principle Card shape
02

Shapes are replaceable

Visual representations come and go freely.

<PrincipleCard data={{ number: 2, title: "Shapes are replaceable", description: "...", accent: "shape" }} />

InterfaceCard

export interface InterfaceCard {
  name: string
  category: 'atom' | 'molecule' | 'organism' | 'template'
  description: string
  code: string
}
interfacecard Full atom
Atom

UserProfile

Core user identity data.

UserProfile.ts
interface UserProfile {
  name: string
  role: string
}
<InterfaceCardFull data={{
  name: "UserProfile",
  category: "atom",  <!-- 'atom' | 'molecule' | 'organism' | 'template' -->
  description: "Core user identity data.",
  code: highlightedHtml
}} />
interfacecard Full molecule
Molecule

Notification

Alert or status message.

Notification.ts
interface Notification {
  title: string
  type: "info" | "error"
}
<InterfaceCardFull data={{ name: "Notification", category: "molecule", description: "...", code: html }} />

StatBox

export interface StatBox {
  value: string
  label: string
  detail?: string
}
statbox Centered
22

Interfaces

Stable contracts

<StatBoxCentered data={{ value: "22", label: "Interfaces", detail: "Stable contracts" }} />
statbox Centered
30

Shapes

Visual expressions

<StatBoxCentered data={{ value: "30", label: "Shapes", detail: "Visual expressions" }} />
statbox Centered
4

Themes

<StatBoxCentered data={{ value: "4", label: "Themes" }} />

Controls

Filters, options, and result previews.

FilterBar

export interface FilterBar {
  filters: { label: string; value: string }[]
  active: string
}
filterbar Pill
<FilterBarPill data={{
  filters: [{ label: 'All', value: 'all' }, { label: 'Atoms', value: 'atom' }],
  active: "all"
}} />

ContextOption

export interface ContextOption {
  label: string
  description: string
  active?: boolean
}
contextoption Card inactive
<ContextOptionCard data={{
  label: "Dashboard sidebar",
  description: "Compact card for team lists"
}} />
contextoption Card active
<ContextOptionCard data={{ label: "Profile page", description: "Full vertical layout", active: true }} />
contextoption Card inactive
<ContextOptionCard data={{ label: "Inline mention", description: "Minimal inline reference" }} />

ResultPreview

export interface ResultPreview {
  label: string
  shape: string
  theme: string
}
resultpreview Panel
Horizontal + Light
AW

Alan White

Admin
<ResultPreviewPanel label="Horizontal + Light">
  <ProfileHorizontal data={user} />
</ResultPreviewPanel>
resultpreview Panel dark
Vertical + Dark
AW

Alan White

Admin
<ResultPreviewPanel data={{ label: "Vertical + Dark" }}>
  <ProfileVertical data={user} />
</ResultPreviewPanel>

Process

Step-by-step flow shapes.

Step

export interface Step {
  number: number
  title: string
  body: string
  color?: 'interface' | 'shape' | 'ink'
}
step Block with slot
1

Define the interface

The interface is a TypeScript type that describes the data contract.

Interface
interface Button {
  label: string
  variant: "primary" | "secondary"
}
<StepBlock data={{ number: 1, title: "Define the interface", body: "...", color: "interface" }}>
  <CodePanelBlock data={{ label: "Interface", dotColor: "interface", code: html }} />
</StepBlock>
step Flow interface
1

Define

Create the interface contract.

<StepFlow data={{ number: 1, title: "Define", body: "Create the interface.", color: "interface" }} />
step Flow shape
2

Build shapes

Create visual representations.

<StepFlow data={{ number: 2, title: "Build shapes", body: "...", color: "shape" }} />
step Flow ink
3

Surface

Choose the right shape for context.

<StepFlow data={{ number: 3, title: "Surface", body: "...", color: "ink" }} />

Data

Comparison tables for structured data display.

ComparisonRow

export interface ComparisonRow {
  aspect: string
  values: Record<string, string>
}
comparisonrow TableRow
Aspect TraditionalIntershapes
Component count 24 variants1 interface + N shapes
Theme support Props or CSS-in-JSdata-theme tokens
AI-readable No standardTypeScript interface
<ComparisonTableRow data={{
  headers: ['Traditional', 'Intershapes'],
  rows: [{ aspect: 'Theming', values: { Traditional: 'Baked in', Intershapes: 'Injected' } }],
  highlightColumn: "Intershapes"
}} />

Page Sections

Full-width shapes for navigation, heroes, headings, CTAs, and footers.

NavBar

export interface NavBar {
  logo: string
  logoHref: string
  links: { label: string; href: string }[]
}
navbar Fixed
<NavBarFixed data={{ logo: "Intershapes", logoHref: "/", links: [{ label: 'Themes', href: '/themes' }] }} />

SectionHeading

export interface SectionHeading {
  id: string
  title: string
  subtitle?: string
  number?: number
  accent?: 'interface' | 'shape' | 'ink'
}
sectionheading Default

The Intershapes model

Separate what from how. Inject the look.

<SectionHeadingDefault data={{ title: "The model", subtitle: "Separate what from how." }} />
sectionheading Default with number
01

Define the interface

The type contract is the stable foundation.

<SectionHeadingDefault data={{
  id: "step-1",
  title: "Define the interface",
  subtitle: "The type contract is the stable foundation.",
  number: 1,
  accent: "interface"
}} />

SubpageHero

export interface SubpageHero {
  title: string
  titleAccent?: string
  subtitle: string
  backHref?: string
}
subpagehero Standard
Back to Intershapes

Shapes & Themes

How shapes implement interfaces.

<SubpageHeroStandard data={{ title: "Shapes &", titleAccent: "Themes", subtitle: "...", backHref: "/" }} />
subpagehero WithCode
Back to Intershapes

Code Examples

Live code demonstrations.

Example
hello world
<SubpageHeroWithCode data={{ title: "Code", titleAccent: "Examples", subtitle: "...", backHref: "/" }}>
  <CodePanelBlock data={{ ... }} />
</SubpageHeroWithCode>

Hero

export interface Hero {
  title: string
  titleAccent?: string
  subtitle: string
  attribution?: string
  actions?: { label: string; href: string; variant: 'primary' | 'secondary' }[]
}
hero Full

Interfaces are canon.Shapes are skins.

A methodology for component design.

by Alan White

<HeroFull data={{ title: "inter", titleAccent: "shapes", subtitle: "What will you shape today?", actions: [...] }} />

CTA

export interface CTA {
  heading: string
  body: string
  actions: { label: string; href: string; variant: 'primary' | 'secondary'; external?: boolean }[]
}
cta Banner

Start building with Intershapes

Separate what from how. Ship components that scale.

<CTABanner data={{
  heading: "Start building",
  body: "Separate what from how.",
  actions: [{ label: 'Go', href: '#', variant: 'primary' }]
}} />

WireframeViewer

export interface WireframeViewer {
  layers: number
  label: string
}
wireframeviewer Sticky
Interface / Shape / Theme

The three layers visualised as an exploded wireframe.

<WireframeViewerSticky data={{ layers: 3, label: "Interface / Shape / Theme" }}>
  <p>Content here</p>
</WireframeViewerSticky>

SiteFooter

export interface SiteFooter {
  columns: { heading: string; links: { label: string; href: string; external?: boolean }[] }[]
  attribution: string
  copyright: string
}
sitefooter Sitemap
<SiteFooterSitemap data={{
  columns: [{ heading: 'Resources', links: [...] }],
  attribution: "Built with Intershapes",
  copyright: "2024 Intershapes"
}} />