Skip to content
Onome Osika

Design system

Every token and block this site uses, rendered live. Values update when you switch theme.

Principles

  • Motion explains, never decorates

    Animation shows where something came from or went. If it doesn’t, it goes. Reduced motion is respected everywhere.

  • Mobile is the design, not the fallback

    Every component is designed at 360px first and earns its wider layouts through container queries.

  • Typography does the heavy lifting

    A calm, editorial base so the one generative moment and the work itself stand out.

  • Accessible by construction

    Alt text and contrast are enforced by the build. Every hover state has a tap or visible equivalent.

Colour

  • --color-bg

    --color-bg
  • --color-surface

    --color-surface
  • --color-surface-2

    --color-surface-2
  • --color-fg

    --color-fg
  • --color-muted

    --color-muted
  • --color-border

    --color-border
  • --color-accent

    --color-accent
  • --color-positive

    --color-positive

Type

Fluid scale using clamp(): sizes grow smoothly with the viewport instead of jumping at breakpoints.

  • --step-6Calm, typographic, fast
  • --step-5Calm, typographic, fast
  • --step-4Calm, typographic, fast
  • --step-3Calm, typographic, fast
  • --step-2Calm, typographic, fast
  • --step-1Calm, typographic, fast
  • --step-0Calm, typographic, fast
  • --step--1Calm, typographic, fast

Space

  • --space-2xs
  • --space-xs
  • --space-s
  • --space-m
  • --space-l
  • --space-xl
  • --space-2xl
  • --space-3xl

Shape & motion

  • --radius-s

    --radius-s
  • --radius-m

    --radius-m
  • --radius-l

    --radius-l
--duration-fast
--duration-fast
--duration-base
--duration-base
--duration-slow
--duration-slow
--ease-out
--ease-out
--ease-in-out
--ease-in-out

Components

Blocks available in every project’s MDX. Assets are resolved relative to the project folder.

Shared blocks

<Section>

Consistent spacing and an anchored heading; feeds the table of contents.

<Section title="The problem">
  Markdown content…
</Section>

Example section

Sections become TOC entries automatically.

<Callout>

A highlighted insight or lesson learned.

<Callout tone="lesson">
  Measure on a mid-range Android first.
</Callout>

<Media>

Image or video with caption. AVIF/WebP, blur placeholder, lazy loaded.

<Media src="screen.png" alt="…" caption="…" />
Example landscape image used to demonstrate the block
A caption sits under the media.

<DeviceFrame>

Desktop and mobile screenshots side by side.

<DeviceFrame desktop={{ src, alt }} mobile={{ src, alt }} />
Example desktop screenshot
Example mobile screenshot

<Timeline>

Project phases or process steps.

<Timeline items={[{ label: "Week 1", title: "Discovery" }]} />
  1. Week 1

    Discovery

    Interviews and audit.

  2. Week 3

    Prototype

  3. Week 6

    Ship

<Quote>

A client or user testimonial. Real, attributable quotes only.

<Quote cite="Name" role="Title, Company">…</Quote>
“Format example only. Real, attributed quotes are used in case studies.”
Name, Role, organisation

Engineering blocks

<MetricRow>

Before/after numbers.

<MetricRow items={[{ label: "LCP", before: "3.1s", value: "1.2s" }]} />
LCP
from 3.1sto 1.2s
JS
from 310 KBto 96 KB

<DecisionLog>

Decision → options → choice → trade-off.

<DecisionLog decision="…" options={["…"]} choice="…" tradeoff="…" />

Decision

Where should search run?

Options
  • Hosted search service
  • Build-time static index
Chose
Build-time static index
Trade-off
Index size grows with content; fine below a few hundred entries.

<ArchitectureDiagram>

SVG or image diagram; tap to open full-screen with pinch zoom on mobile.

<ArchitectureDiagram src="diagram.svg" alt="…" />
Example image standing in for a system diagram

Pinch to zoom

Example image standing in for a system diagram

<CodeCompare>

Before/after code; scrolls horizontally inside its container.

<CodeCompare lang="ts" before={`…`} after={`…`} />
Before
const data = await fetch(url).then(r => r.json())
After
const data = await fetch(url, { next: { revalidate: 3600 } }).then(r => r.json())

<LiveDemo>

Lazy interactive embed; static poster until tapped on mobile.

<LiveDemo src="https://…" title="…" poster="poster.jpg" posterAlt="…" />
Example poster image for a live demo

Design blocks

<BeforeAfter>

Draggable comparison slider, touch and keyboard operable.

<BeforeAfter before={{ src, alt }} after={{ src, alt }} />
Example after state, blue
Example before state, orange

<Palette>

Colour swatches with hex values and contrast ratios.

<Palette colors={[{ name: "Ink", hex: "#161614" }]} />
  • Aa

    Ink

    #161614

    18.1:1 on white ✓ · 1.2:1 on black

  • Aa

    Paper

    #fbfaf7

    1.0:1 on white · 20.1:1 on black ✓

  • Aa

    Signal

    #2f4bd8

    6.7:1 on white ✓ · 3.1:1 on black

<TypeSpecimen>

Typeface showcase with weights and scale.

<TypeSpecimen name="Instrument Serif" family="var(--font-display)" />
Instrument Serif
400

Sphinx of black quartz, judge my vow

Sphinx of black quartz, judge my vow

Sphinx of black quartz, judge my vow

Sphinx of black quartz, judge my vow

<Iterations>

Sequence of explorations ending in the final design.

<Iterations items={[{ src, alt, label }]} />
  1. Example exploration one

    01 · Sketch

  2. Example exploration two

    02 · Direction

  3. Example final design

    03 · Refined · Final

<PrototypeEmbed>

Figma or video prototype; click to load.

<PrototypeEmbed src="https://www.figma.com/proto/…" title="…" poster="…" posterAlt="…" />
Example poster image for a prototype