labsly Style Guide

The portfolio's visual + interaction grammar. This page is generated at build time from STYLE.md — the canonical source.

Source of truth for visual + interaction grammar across the labsly portfolio. Every labsly app implements its own DesignSystem that conforms to this guide. No shared Swift package in 2026 — this doc is the contract.

Published at https://labsly.com/style-guide.

See PLANS/06_LABSLY_SUBSTRATE.md and PLANS/07_LABSLY_BRAND.md for context.


Two Visual Tracks

Track A — labsly tools

Used by: Systema, Witness, Dais, Atlas, VoidRepublic, Meridian. Vibe: Mac-native restraint. Linear / Things / Fantastical references. Dark-mode-first. Lots of whitespace.

Track B — labsly craft

Used by: NovelWriter, future creative-craft apps. Vibe: Literary warmth. Scrivener / Ulysses / iA Writer references. Light-mode-first (with dark option). Paper textures. Reading-first.


Brand Mark — the Lissajous figure

The labsly mark is a Lissajous figure: the curve produced when two oscillations at different frequencies are plotted against each other — what an oscilloscope draws when you feed it two tones. The master figure is the 3:2 ratio.

It is a trace of a behaviour, not a drawing of an object, which is what keeps it from collapsing into a globe, an atom or a stack of layers. Two independent signals, plotted against each other, resolving into a stable pattern.

One figure, three cuts

Cut Where it goes
Screen The glowing phosphor icon. App icon and large sizes — the bloom needs room.
Flat The same figure with no glow and no graticule. Lockups and small UI.
Line One colour, no container. Print, mono, inline.

The glow never goes in a lockup. Beside a flat solid wordmark it reads as a different material, and at lockup size the bloom and graticule become noise. This is the same mismatch that made the previous mark sit badly against the wordmark.

The lockup uses the line cut, not the tile. A contained mark reads heavier than the type beside it — the tile's edges add mass the wordmark has no answer for. The bare figure sits with the letterforms instead of competing with them. logo-tile*.svg keeps the contained version for places that want it.

Geometry (240-unit square)

Element Value
Figure x = sin(3t + π/2), y = sin(2t), centred on 120,120
Amplitude rx 72, ry 68 (rx 76 / ry 72 for the line cut, which has no container)
Screen inset 18 from the tile edge
Tile radius 52

The screen inset is 18, not 28. The wider margin shrank the figure to roughly half the mark's height, so at lockup size the tile's outer box matched the line cuts while the figure inside them did not.

Denser ratios (5:4, 3:4, 7:4 …) are reserved for per-product variants — each product takes its own ratio and phosphor colour. The master mark is deliberately the simplest of the family. Ratios much denser than 3:2 turn to mush below 40px.

Assets

All files in public/brand/labsly/ are generated — never hand-edit them.

File Use
icon.svg Phosphor screen. App icon; apple-touch-icon
favicon.svg Simplified cut for 16–28px — no graticule, fatter trace. Mirrored to public/favicon.svg
logo-dark.svg / logo.svg Primary lockup — line cut, for dark / light backgrounds
logo-tile-dark.svg / logo-tile.svg Alternate lockup, for places that want the mark contained
mark-dark.svg / mark.svg Flat tile alone, for dark / light backgrounds
mono-ink.svg / mono-paper.svg / mono.svg Line cut, single colour (mono.svg uses currentColor)
wordmark.svg / wordmark-dark.svg Wordmark alone (hand-authored, not generated)

The -dark variants carry a hairline rim so the near-black tile separates from a dark surface. public/brand/lb01/ holds LB-01, the previous mark, kept as a mascot for docs, empty states and the build-in-public feed — not as identity.

Lockup alignment

Rule Value
Mark height 0.96 × ascender
Vertical centred on the cap block (ascender top → baseline)
Gap 0.40 × ascender, from the true silhouette edge

Measure the wordmark, do not read its viewBox. wordmark.svg declares -4.6 -78.1 271.7 107.1, but its real ink is x 5.40..258.12, y -67.83..19.80 — roughly 9 units of padding on the bottom and right. Laying out against the declared box desyncs the vertical centring and shifts the whole lockup left.

Four alignment rules were tried and rejected before this one, so do not re-derive them:

  • bottom on the baseline — written for LB-01's tall portrait chassis; makes a square tile float high
  • centre on the ink block — corrects placement, which was never the problem
  • span the full ink block — sizes the mark at 1.29 × ascender and overpowers the wordmark
  • any rule that leaves the mark overhanging the type at both ends — it then shares no edge with anything and reads adrift however precisely it is centred

Size was the defect, not placement. Verify changes by rendering the lockup and measuring the result, not by trusting the arithmetic.

To change the mark, edit scripts/build-brand.mjs and run:

npm run brand:build

Typography

Track A (tools)

  • Font: SF Pro (system font, automatic on macOS)
  • Display weight: Semibold (600)
  • Body weight: Regular (400)
  • Emphasis weight: Medium (500)
  • Tracking: -0.5% on display, 0 on body
  • Numerics: Tabular for data, proportional for prose

Track B (craft)

  • Body font: Charter or New York (serif); Iowan Old Style fallback
  • Display font: Same family; can use New York Display variant
  • Sizes: 16–18pt body minimum (writers spend hours)
  • Per-document overrides: Allow user to pick typeface, size, line-height

Type scale (both tracks)

Token Size (px) Use
display-xl 56–72 Hero pages, splash
display-lg 36–44 Page titles
display 28 Section titles
heading 20 Subsection titles
body-lg 17 Lead paragraphs
body 15 Default body
caption 13 Labels, hints
micro 11 Tertiary info, badges

Color Tokens

Track A (tools — dark-mode-first)

  • Background: SF system materials (vibrancy + blur where appropriate); fallback #0A0A0A
  • Foreground: #F5F5F5
  • Muted foreground: #9A9A9A
  • Borders: rgba(255,255,255,0.05) / rgba(255,255,255,0.1) for hover

Track A (tools — light-mode fallback)

  • Background: #FAFAFA
  • Foreground: #1A1A1A
  • Muted foreground: #6A6A6A

Track B (craft — light-mode-first)

  • Background: #FAF7F2 (warm cream)
  • Foreground: #2A2520 (warm charcoal)
  • Muted: #8A7F70
  • Sage accent: #7A8B6E
  • Ink red accent: #9B2D2D

Track B (craft — dark-mode option)

  • Background: #1F1B16 (warm dark)
  • Foreground: #E8E4DD (warm cream-on-dark)

Per-app accent colors

App Accent
Systema #5856D6 (indigo)
Atlas #B87333 (bronze)
Service Design #0FB5BA (teal)
Witness #FF6B6B (coral)
Dais #7B2DBE (royal purple)
NovelWriter #9B2D2D (ink red)
VoidRepublic #5B2D8B (cosmic violet)
Meridian #2D8B5B (forest green)

Semantic colors (both tracks, Apple-compatible)

  • Positive: #34C759 (green)
  • Warning: #FF9F0A (amber)
  • Critical: #FF453A (red)

Spacing Scale

4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96 (px). Stick to scale; no arbitrary values.


Radii

Token Value (px) Use
sm 4 Inputs, small buttons
md 8 Cards, modals
lg 12 Large cards
xl 16 Panels
xxl 20 Hero blocks

Shadows / Elevation

Three tiers per track. Use sparingly.

Track A (tools, dark)

  • Subtle: 0 1px 0 rgba(255,255,255,0.05) inset
  • Card: 0 4px 16px rgba(0,0,0,0.3)
  • Modal: 0 16px 48px rgba(0,0,0,0.5)

Track B (craft, light)

  • Subtle: 0 1px 2px rgba(0,0,0,0.04)
  • Card: 0 4px 12px rgba(0,0,0,0.06)
  • Modal: 0 16px 32px rgba(0,0,0,0.12)

Motion

Track A (tools)

  • Easings: standard ease-in-out, spring for natural interactions
  • Durations: 0.15–0.3s typical; 0.4s for navigation transitions
  • No bouncing, no over-the-top entrance animations

Track B (craft)

  • Easings: organic, longer (page-turn-like)
  • Durations: 0.3–0.5s
  • Effects: typewriter scrolling option

Required Patterns (cross-app, non-negotiable)

FadingScrollView (memory: feedback_scroll_hint.md)

Every scrollable modal MUST use a bottom fade hint to indicate more content. No exceptions.

Fullscreen toggle (memory: project_canvas_fullscreen.md)

Every canvas (CLD, stakeholder map, journey map, blueprint, Wardley map) MUST have a fullscreen toggle. No exceptions.

Persona output labeling (epistemic honesty)

Any AI-generated content surfacing personas, predictions, or analysis MUST display:

  • Confidence indicator (visual or numeric)
  • Source label (stated / inferred / synthesized / observed)
  • Optional evidence/citations on hover or expand

This operationalizes the labsly anti-synthetic-persona positioning across the whole portfolio.


Voice & Tone

See PLANS/07_LABSLY_BRAND.md for full voice guidance.

Use: structured, rigor, leverage, system, signal, evidence, judgment, craft, epistemic, provenance, confidence Avoid: "supercharged," "revolutionary," "AI-powered," "smart," "magic," "seamless," "intuitive," "next-gen"


Last updated: 2026-08-27. Updates RFC-style: post it in public, gather feedback, ratify.