Design system

These are the foundations, controls and composition rules used to build this desktop. Explore the examples, then open their usage notes for the exact implementation.

Using this reference

This page and its reference data are the canonical design-system contract. Explicit direction from Sylvain takes precedence. Production components and tokens implement the contract; discrepancies must be reconciled rather than copied as new conventions.

Shared components are reusable implementations. Shared CSS requires the documented native markup. Compositions describe relationships rather than universal components. Demonstrations explain behaviour and do not establish a new site-wide control. Journal experiments are not production conventions unless explicitly adopted here.

  1. Find the matching entry and inspect its production source before building. Reuse shared components and CSS; preserve the documented HTML and accessibility behaviour.
  2. Use the listed component aliases. Theme files change tokens, not component selectors. Keep surface and text colours paired; never substitute approximate local colours.
  3. Keep bespoke compositions specific to their feature. Reuse an established pattern before extracting a new abstraction; there is no universal card.
  4. When a recurring convention changes, update the production implementation, this reference and its checks together. A code change alone does not approve a new design convention.
  5. Verify direct routes, browser history, keyboard focus, reduced motion, narrow screens and contrasting themes. Review screenshots against the approved design; do not automatically accept new visual baselines.

Reference data (JSON) is generated from the same records as these notes.

Find a component or pattern
Existing page compositions

Use the owning feature when extending a page. These compositions retain their individual layouts.

Desktop and route panels

Use the shell's panel slot and existing activePanel values. Preserve direct routes and the existing Astro navigation lifecycle; do not add another router.

src/components/DesktopShell.astro
Launcher tiles

Each tile in src/components/launcher owns its composition. Shared tokens connect them; a universal card would erase their differences.

src/components/launcher/WorkLauncher.astro
Journal articles

Use the article layout, journal-posts data and the relevant study component. Experimental specimens do not become production conventions automatically.

src/components/JournalPostLayout.astro
Work entries

Use work-items data and its existing presentation choices. Tool pages retain their dedicated components and direct routes.

src/pages/work/[slug].astro
Context notes

Reuse the existing contextual-note structure and theme-note aliases when the same inline disclosure pattern is needed.

src/components/ContextNote.astro
Media collections

Use the appropriate existing media feature: ArtefactCarousel, TypeArchive or the 3D Work implementation. Their behaviour is feature-specific.

src/components/ArtefactCarousel.astro

Themes

Usage and source · Foundation

One token system powers the entire interface. The preview can follow the site or explore a local variation.

  • Reuse ThemeControls for the theme panel and its existing saved-state behaviour. Do not build another preference store.
  • The specimen presets and its buttons affect only the embedded preview. Its field layout and Reset fields button are demonstration UI, not general-purpose production components.
  • System preferences apply until explicitly overridden. Reset restores the authored preference behaviour. Theme changes must preserve reduced motion.
Source
tokens.csssrc/styles/base-theme.csssrc/data/theme-controls.tssrc/components/launcher/ThemeControls.astrosrc/scripts/theme-controls.ts
Token hooks
--theme-hue--theme-lightness--theme-chroma--surface-distance--contrast-low--contrast-high
States to preserve
Site · Local preview · Light and dark · High contrast · Reset

Foundations

Colour and contrast

Base

Primary

Supporting

Sunken

Primary

Supporting

Usage and source · Foundation

Derive surfaces from the colour axis and use the ink generated for each surface.

  • Component CSS consumes its own aliases from tokens.css, not source colour tokens or literal colours.
  • Use high ink for primary content and supporting ink for small readable labels. Low ink is available for lower-emphasis decoration; it is not a substitute for supporting text.
  • Keep borders, focus and selection token-controlled. Do not use the accent as a text-bearing fill without a verified matching foreground.
Source
tokens.csssrc/styles/base-theme.csssrc/scripts/color-contrast-fallback.ts
Token hooks
--color-surface-base--color-surface-sunken--color-text-base-high--color-text-base-supporting--color-text-sunken-high--contrast-supporting
States to preserve
Base · Sunken · Dark · Chromatic · High contrast
In use
Desktop

Typography

Display

Room to think.

Panel title

A clear starting point

Reading

A little space makes the important things easier to see.

Body

Use familiar words, a comfortable measure and a consistent rhythm.

Supporting

Details that help without competing.

Usage and source · Foundation

42dot Sans and a shared modular scale give each text role a consistent size.

  • Map feature aliases to semantic type roles; do not invent local font sizes for an existing role.
  • Heading levels describe document structure, not visual size. Keep one page h1 and a meaningful heading order.
  • Keep rem-based sizing and allow text to wrap when the visitor increases their text size. The scale slider here is a local demonstration.
Source
tokens.csssrc/lib/type-scale.tssrc/scripts/type-scale-fallback.ts
Token hooks
--font-sans--type-base--type-ratio--type-rounding--font-size-body--font-size-supporting
States to preserve
Display · Panel title · Reading · Body · Supporting · Larger text
In use
Profile

Radius and padding

Inner radius —
Usage and source · Composition

A nested curve follows the outside curve, its padding and the border between them.

  • For inset shapes, subtract padding and border from the outside radius and clamp at zero.
  • Keep corner shape and radius controlled by the owning component aliases. The geometry sliders illustrate the relationship; their values are not saved site settings.
Source
tokens.csssrc/styles/segmented-control.css
Token hooks
--segment-radius--segment-option-radius--segment-padding--segment-border-width
States to preserve
Square · Rounded · Visible border

Radius and gap

Collection
First itemSecond itemThird item
Joining radius —
Usage and source · Composition

A header and body share an outside silhouette with smaller corners where they meet.

  • Use the existing cap geometry: joining corners follow half the outside radius, bounded by the shared maximum. Preserve the independent gap.
  • Apply the feature's surface and edge aliases. Do not turn Work, Journal and the other bespoke compositions into one configurable card.
Source
tokens.csssrc/styles/surface-edge.csssrc/components/launcher/WorkLauncher.astrosrc/styles/work-panels.css
Token hooks
--launcher-cap-radius--launcher-cap-gap--surface-cap-radius-max--surface-cap-radius-factor
States to preserve
Small and large radii · Visible border · Narrow screen

Iconography

Message
Settings
Folder
Usage and source · Foundation

Use the site's prepared Lucide SVGs and the owning control's dimensions.

  • Import prepared SVGs from src/icons. Decorative icons are hidden from assistive technology; icon-only actions require an accessible name.
  • Use currentColor and component size aliases. Do not restore the archived custom-icon generator or introduce an icon runtime.
Source
src/icons/README.mdsrc/icons/SOURCE.jsonsrc/components/PanelAction.astro
Token hooks
--panel-action-icon-size
States to preserve
Labelled · Icon-only · Keyboard focus
In use
Work

Motion

Selection

Hover and focus

Collection highlight

Reveal

Collection details
Notes

12 items · Updated today

Usage and source · Shared CSS

Motion explains selection and position; the same state remains clear without animation.

  • Reuse SegmentedControl for moving selection and data-hover-list with the existing helper for list highlights.
  • Keep focus visible independently of hover. Respect prefers-reduced-motion before starting scripted animation and when it changes.
  • The disclosure example and usage notes share native details/summary and the same CSS content reveal and chevron motion. Opening and closing animate where supported, and become immediate with reduced motion; the collection content is illustrative.
Source
src/styles/segmented-control.csssrc/styles/hover-list.csssrc/scripts/hover-list.tssrc/scripts/desktop-shell.tssrc/styles/design-system.css
Token hooks
--segment-duration--hover-list-duration--hover-list-ease--ds-motion-duration--ds-motion-ease
States to preserve
Hover · Keyboard focus · Selected · Reduced motion
In use
Journal

Example inside DesktopShell. Adjust import paths to the calling file.

<ul data-hover-list=".collection-link">
  <li><a class="collection-link" href="/work">Work</a></li>
</ul>

Components

Actions and links

Return to a list
Dismiss a panel
Open an item
Unavailable action

Examples stay on this page.

Usage and source · Shared component

Reuse PanelAction for Back, Close and Open controls. Navigation uses links; local actions use buttons.

  • The default is a link and requires href. Use as="button" only for an action, never to imitate navigation.
  • Supply text for the Back treatment, or label for an icon-only control. The icon choices are close and arrow.
  • The buttons here provide local feedback so the examples keep you on this page. Production navigation still uses real destinations. This is not a generic submit-button component.
Source
src/components/PanelAction.astrosrc/styles/panel-action.css
Token hooks
--panel-action-background--panel-action-color--panel-action-radius--panel-action-focus-color
States to preserve
Back · Close · Open · Disabled button · Keyboard focus

Example inside DesktopShell. Adjust import paths to the calling file.

---
import PanelAction from "../components/PanelAction.astro";
---
<PanelAction href="/work" text="Work" />
<PanelAction href="/" label="Close panel" />
<PanelAction as="button" icon="arrow" label="Next item" />

Study fields and selects

Demo form · nothing is sent.

Usage and source · Shared component

StudyFrame supplies the real field and button treatment used in Journal studies. Native selects share their own CSS.

  • Use StudyFrame around a Journal study; as="div" is available when figure semantics do not fit. Label every input and connect feedback with aria-describedby.
  • Use native select elements with class native-select. StudyFrame maps the closed select to the same background and foreground as its other fields; the open menu keeps its own surface pair. Keep feature mappings to --select-*; native browser fallback remains available.
  • Contact and tool fields have their own feature contracts. Do not copy the reference page's ds__field or ds__button helpers into a feature, or apply study styling to unrelated forms.
Source
src/components/StudyFrame.astrosrc/styles/study-frame.csssrc/styles/native-select.css
Token hooks
--study-control-background--study-card-color--study-control-radius--select-field-background--select-field-color
States to preserve
Editable · Disabled · Invalid · Reset · Keyboard focus

Example inside DesktopShell. Adjust import paths to the calling file.

---
import StudyFrame from "../components/StudyFrame.astro";
---
<StudyFrame>
  <label for="view"><span>View</span>
    <select id="view" class="native-select"><option>List</option><option>Grid</option></select>
  </label>
</StudyFrame>

Selection

Usage and source · Shared component

SegmentedControl renders native radios. Checkboxes and the theme switch use established native markup and shared CSS.

  • Give each radio group a unique name, a label, two to eight uniquely valued options and a matching selected value. Use disabled for an unavailable group. Named slots can provide option icons.
  • Keep native radio keyboard behaviour. The selected value must remain distinguishable with motion disabled.
  • Checkboxes use a primitive-study ancestor and data-study-checkbox. Theme switches use the ThemeControls markup and theme-toggle classes, following the range input: off slightly darkens its unfilled track, on uses its filled track, and the solid thumb shares the range thumb fill and dimensions. High contrast uses the range track directly. Keep the thumb flush, without an inset ring. Thumb borders are reserved for high contrast; keyboard focus remains visible in every mode. Neither requires a custom JavaScript state library.
Source
src/components/SegmentedControl.astrosrc/styles/segmented-control.csssrc/styles/primitive-study.csssrc/styles/theme-controls.csssrc/components/launcher/ThemeControls.astro
Token hooks
--segment-background--segment-selected-background--segment-radius--study-checkbox-background--theme-control-switch-background--theme-control-switch-thumb-background--theme-control-switch-thumb-inset
States to preserve
Checked and unchecked · Selected · Disabled · Keyboard arrows · Reduced motion

Example inside DesktopShell. Adjust import paths to the calling file.

---
import SegmentedControl from "../components/SegmentedControl.astro";
---
<SegmentedControl name="collection-view" label="Collection view" value="list"
  options={[{ value: "list", label: "List" }, { value: "grid", label: "Grid" }]} />

Ranges

Usage and source · Shared CSS

Native range inputs share the site's track, thumb, focus and progress treatment.

  • Use a labelled input[type=range] with explicit bounds and an associated output. Keep arrow-key operation native.
  • The shell installs range enhancement. Call syncRangeInput when feature code sets a value programmatically.
  • The amount meter is an illustrative output, not a reusable progress component.
Source
src/styles/range-input.csssrc/scripts/range-input.tssrc/scripts/desktop-shell.ts
Token hooks
--range-track-background--range-thumb-background--range-focus-color
States to preserve
Minimum · Maximum · Disabled · Keyboard adjustment
In use
Theme

Example inside DesktopShell. Adjust import paths to the calling file.

<label for="amount">Amount <output for="amount">50%</output></label>
<input id="amount" type="range" min="0" max="100" value="50" />

Patterns

Panel navigation

These links open Work and the desktop, just as they do in a panel.

Usage and source · Shared component

PanelNavigation groups real Back and Close links, with a slot for contextual actions.

  • Supply label and closeLabel. Supply backHref and backText together when the panel has a parent.
  • Use the default slot for contextual actions. Enable cap only for a split-stage header; it changes the surrounding stage geometry.
  • Keep navigation as anchors so Back, Forward, opening in a new tab and copying a link remain available.
Source
src/components/PanelNavigation.astrosrc/components/PanelAction.astrosrc/styles/panel-navigation.css
Token hooks
--panel-navigation-gap--panel-navigation-cap-background--panel-navigation-cap-radius
States to preserve
Back and Close · Contextual action · Cap variant · Keyboard focus

Example inside DesktopShell. Adjust import paths to the calling file.

---
import PanelNavigation from "../components/PanelNavigation.astro";
---
<PanelNavigation label="Collection navigation" backHref="/work" backText="Work" closeLabel="Close collection" />

Toolbar and collection

Collections · 4
  • Notes12 entries
  • Studies6 experiments
  • Projects4 projects
  • Archive28 items
Usage and source · Demonstration

This composition demonstrates a shared selector with a local list/grid arrangement.

  • Reuse the selector, not the demo collection as a universal layout. Production collections retain their own feature source.
  • The ds-collection classes and sample data belong to this demonstration. List/grid changes must retain readable order, keyboard control and a reduced-motion state.
Source
src/components/design-system/Patterns.astrosrc/components/SegmentedControl.astrosrc/styles/design-system.css
Token hooks
--ds-collection-duration--ds-collection-ease
States to preserve
List · Grid · Narrow screen · Reduced motion

Overflow and edge fades

  1. Item 01Supporting detail
  2. Item 02Supporting detail
  3. Item 03Supporting detail
  4. Item 04Supporting detail
  5. Item 05Supporting detail
  6. Item 06Supporting detail
  7. Item 07Supporting detail
  8. Item 08Supporting detail

Scroll to reveal more. A soft blur and fade mark remaining content and clear at each end.

Usage and source · Shared component

ScrollFade marks remaining content and clears each edge when there is nothing more to scroll.

  • Place data-scroll-fade on the direct scrollable child of ScrollFade. The shell initialises the helper and handles teardown.
  • Provide a keyboard-focusable, labelled scroll region when its content needs keyboard scrolling. The feature owns its height and overflow styling.
  • Use normal end padding; do not add empty clearance for the fade. Keep content available without JavaScript and respect reduced motion.
Source
src/components/ScrollFade.astrosrc/styles/scroll-fade.csssrc/scripts/scroll-fade.tssrc/scripts/desktop-shell.ts
Token hooks
--scroll-fade-start-distance
States to preserve
Start · Middle · End · No overflow · Keyboard scrolling

Example inside DesktopShell. Adjust import paths to the calling file.

---
import ScrollFade from "../components/ScrollFade.astro";
---
<ScrollFade>
  <div class="collection-scroll" data-scroll-fade tabindex="0" role="region" aria-label="Collection">
    <!-- Feature content; collection-scroll owns height and overflow-y: auto. -->
  </div>
</ScrollFade>