Specification
0. About this specification
This page is the specification and a specimen of it at once. The colors, type and components in the first half are read from the site’s own stylesheet when the site is built, so they cannot drift from the code: if the page names a token the stylesheet no longer has, the build fails.
The rules below are the lessons from designing the site, written down so the next change starts from them instead of rediscovering them.
- Must is a rule the site keeps today. A change that breaks one changes the rule first, here.
- Should is the default. Leaving it needs a reason.
- Gap marks a place where the site doesn’t keep its own rule yet.
How it improves. Every rule has an id (P1, C2…) and, where it came from a mistake or a decision, an origin. A rule enters when a pattern repeats or a mistake teaches one, and leaves when it stops earning its place. Each revision raises the version and adds a line to the changelog (§ 12). The known gaps (§ 11) are where the next revision starts.
1. Principles
- P1. Found before invented. An identity must be looked for in what already exists before one is proposed. The sun yellow (
hsl(42 95% 50%)), Jost and Fira Code all came from Leon’s first site, from 2022. Origin: a first proposal, typographic and terracotta, was made without looking, and replaced the same day. - P2. One idea, carried everywhere. The site has one image: a sunflower made of data, with order at the center and entropy at the edge, information organized against noise. Every motif is a smaller form of it: the mark, the favicon, the topic dots, the yellow under the links. A new motif must read as part of that idea, or it isn’t added.
- P3. A simple concept, done with care. Depth goes into behavior, not into more elements. Leon, on the first sunflower: “looking nice for a simple concept.”
- P4. Every reader gets a whole site. Without JavaScript, without motion, without the web fonts, the site must still be complete. Enhancement only adds.
- P5. Nothing leaves the domain. No third-party fonts, scripts or analytics. Fonts are bundled from Fontsource at build time.
- P6. The content outlives the design. Texts are plain Markdown in
content/, outside the code. The design must never need markup inside a text; the site has already been Gatsby and Next.js, and the texts must survive the next change of tool. - P7. Provenance is part of the design. Every text says which language Leon wrote it in and where it came from. The translation note is a designed element, not small print.
- P8. Proved, not judged. A design claim is checked with something that can fail: contrast is computed (the table above), animation is measured (S7), links are counted after each build.
2. Color
The palette is ten named colors; the components use roles. A theme is only a change of roles.
- C1. Roles, not colors. Components must use role tokens (
--bg,--ink,--muted…). Palette names appear only inside role definitions and in the brand pair (C3). - C2. Sun yellow is light, not ink. On a light background the yellow must never carry text: it reaches 1.8:1 there. It is a surface: the header band, the highlighter under links, the focus ring, markers. In the dark theme, where it reaches 9.7:1, it becomes the color of the name.
- C3. The brand pair is fixed. Brown on sun (8.8:1) is the same in both themes: link hover, the skip link, the essay badge.
- C4. Ochre is for large things. Ochre reaches 3.6:1 on the light background: it may color numerals, list markers, headings on hover and other large or decorative marks, never running text.
- C5. Dark is warm. The dark theme is brown, never neutral grey or black, and its text is cream, never pure white. The light background is warm white for the same reason.
- C6. Topics keep their color. Meaning is sun, modeling is ochre, organization is moss, fundamentals is the second brown (light brown in the dark), careers is sage, each a
--topic-*token. A topic has the same dot everywhere. A dot always sits beside its label, so it needs no 3:1, but it must stay visible: at least 1.5:1 on its surface, measured in the contrast table. Origin: the fundamentals dot was 1.3:1 on the dark chips, and dead CSS hid the ring meant to save it. - C7. Contrast is computed. Text pairs must reach WCAG AA (4.5:1) in both themes; large text and marks, 3:1. The table above is calculated from the stylesheet on every build.
- C8. The sunflower follows the theme. Its colors come from
--dot-1to--dot-4, resolved live through a hidden probe element (a canvas can’t readlight-dark()), so switching theme recolors it without a reload. - C9. One line per role. Each role is defined once, as
light-dark(<light>, <dark>); a theme is nothing butcolor-scheme. Origin: v0.1 wrote every dark value twice, once for the system and once for the toggle. Cost:light-dark()needs a browser from 2024 or later; an older one falls back to its default colors, plain but readable (P4).
3. Type
- T1. Two voices. Jost is the human voice: reading, headings, the name. Fira Code is the data voice: dates, labels, badges, metadata, code. What describes a text (its date, kind, language) is set in mono; the text itself is in Jost.
- T2. Labels are mono, weight 500, uppercase, letter-spacing 0.06em, at
--step--1, in--muted. - T3. The scale. Body is
--step-0(1.1875rem) at line-height 1.65. Headings sit at line-height 1.1 with -0.02em tracking. The fluid display size,--step-3, belongs to the name on the home page; page titles use--step-2. - T4. Measure. Running text must stay within
--measure(40rem). Index pages use 48rem; only the home page uses--wide(68rem). - T5. Sections in prose begin with a sun
§. A text has no H1 in its body: the page shows the title.
4. Layout and space
- L1. One wrapper.
.wrap, up to--wide, with--gutter(1.25rem) on each side. - L2. Three breakpoints, in rem so they follow the reader’s font size: 34rem (phone: lists become one column, the header stacks), 44rem (the hero becomes one column, the sun above the text), 52rem (the home page’s two columns become one).
- L3. Rhythm. Margins, padding and gaps should come from the scale
--space-1to--space-6(0.5, 1, 1.5, 2.5, 3.5, 5rem). Sections sit--space-5apart; items in a group,--space-2to--space-3. A value off the scale needs a reason; the ones left from before the scale move onto it when their rule is touched. - L4. Bands. The header is the hero surface (yellow in light, brown in dark). The footer is dark brown in both themes and carries the motto in sun.
5. Motifs and components
- K1. The mark is a sun disc with a dark core: the sunflower at sixteen pixels. The favicon is the same disc on brown.
- K2. Links are a highlighter: a band of
--markunder the lower third of the text. On hover it fills with sun and the text turns brown (C3). Navigation and headings drop the band: navigation underlines, headings change color. - K3. Focus is a 3px sun ring, 3px away, on everything focusable.
- K4. Badges (kind, draft) are mono, 0.68rem, uppercase, with a 4px radius. Essay is the brand pair; note is quiet (chip fill, hairline); draft is moss with white.
- K5. Chips (topics, the concept index) are pills on
--chip-bg, with the topic’s dot when they stand for a topic. - K6. Pebbles (the three beliefs on the home page, the community card) are
--chip-bgwith an uneven radius, a pebble and not a box, numbered in mono ochre. On hover a pebble lifts 4px and tilts by less than a degree. Origin: 0.4; until then a card with a 12px radius. - K7. The language pill shows the languages a page exists in, the current one inverted. It never offers a language the page doesn’t have.
- K8. The theme toggle is three icons (system, light, dark) with
aria-pressedon the current one. - K9. Dividers. A 1px
--rulebetween list items. In prose, a short 4px sun bar. - K10. The character is Leon as a soft 3D cartoon (generated with Gemini from his photos, cut out to WebP with transparency by
scripts/cutout.py). One scene per idea of the site, never decoration alone: the hero stands before the sunflower, each belief has its scene on a soft blob (sun, sage, sun). Every scene has a real alternative text, in each language. Scenes float slowly (6 to 7 s, 6px) and stand still under reduced motion. Origin: 0.4, when Leon published his likeness (2026-11-03). - K11. Hills close a section: one soft curve, drawn once, in the color of what comes after it (the hero into
--bg, the page into--footer-bg). Decorative,aria-hidden.
6. The sunflower
Gravity as consciousness, gathering data (Leon). About 900 seeds on a Fibonacci sphere, seen from a pole that leans toward the reader, turning slowly. At rest the core is dense and the edge scatters as loose data that floats under the title. When the pointer nears the center the seeds fall into place with mass: they accelerate, overshoot a little, spiral and settle, and the Fibonacci spirals (21 and 34) appear as thin lines. It breathes, and a wave of light runs from the pole to the edge every few seconds.
- S1. Motion means something. Order follows attention: only the pointer near the center orders the data. Motion must not be decoration alone.
- S2. Time, not frames. Smoothing and physics must be functions of elapsed time (
1 − e^(−k·dt)), and physics runs in steps of at most 1/120 s, so the sun behaves the same at 30, 60 or 120 Hz. Origin: smoothing per frame was a bug; the sun ran faster on faster screens. - S3. Pause when unseen. The loop stops while the canvas is off screen.
- S4. Three levels. Without JavaScript: a flat SVG of 560 points, generated at build time, in the same place. With reduced motion: one still frame of the 3D version. Otherwise the live canvas, fading in over the SVG.
- S5. Placed by CSS. Position and size come from
--sun-x,--sun-yand--sun-don the container; the script reads them through the flat SVG, so layout stays in the stylesheet. - S6. Tuned in one place. The parameters (
N,CAP,TILT,SPIN,NEAR,FAR,BREATH,WAVE) sit at the top of the script, named and commented. - S7. Measured, not watched. Animation is tested by simulating the pointer and counting frames. Origin: the app’s browser pane sometimes reports reduced motion, and stops animating when its window is off screen; looking at it proved nothing.
7. Theme
- M1. Three states: system (the default), light, dark. The choice lives in the reader’s browser (
localStorage, keytheme) and becomesdata-themeon<html>, which only setscolor-scheme(C9). - M2. No flash. An inline script in
<head>restores the choice before the first paint. - M3. Everything themes through roles, the sunflower and the browser’s
theme-colorincluded; the meta tags read--hero-bgfrom the stylesheet at build time.
8. Language and voice
- V1. Three languages: English at
/, Portuguese at/pt/, Spanish at/es/. Interface words live insrc/i18n.ts; everything else is content. - V2. Leon’s voice is never invented. Saci organizes, cuts, links and translates. Ideas Saci adds are marked and told to Leon. First person that isn’t Leon’s stays a draft.
- V3. Every text shows its origin: “Written in …” or “Translated from … with Saci”, and the source.
- V4. Quotes from others stay under fifteen words, with the author’s name.
- V5. The frame speaks plainly: short sentences, no hype. The site argues for fundamentals over hype; its own words must not sell.
- V6. Accessible names speak the page’s language, like every other word of the frame: they live in
src/i18n.ts. - V7. Translations keep up. This specification is written in English and translated with Saci into Portuguese and Spanish, one file per language in
src/brand/spec/. Each file declares the version it says; a translation behind the original fails the build, so no reader gets older rules than another.
9. Accessibility
- A1. A skip link is the first thing to focus.
- A2. Landmarks and groups of controls have names.
- A3. Contrast follows C7; focus follows K3; motion follows S4.
- A4. Decorative graphics (the sunflower, the mark, the topic dots) are hidden from assistive technology.
- A5. Forced colors (Windows high contrast) replace backgrounds, so links get their underline back and badges and chips a border; the mark and the topic dots keep their colors.
- A6. Print is the text in ink on paper: no bands, no sun, no controls; code turns to ink and wraps.
10. How design decisions are made here
- D1. “No preference” is not carte blanche. Before choosing for Leon, look at what Leon already made. Origin: the stack was chosen before reading the history of the site; the history changed the question.
- D2. Carte blanche is still a proposal. “Be creative” (Leon) meant: propose, show, refine together in small steps, and record who decided what.
- D3. Decisions live where they last: the why in the project’s note in the Mind, the how in the repository, the rules on this page.
- D4. Structure comes from use. No new token, component or rule until a pattern repeats.
11. Known gaps
Where v0.5 starts.
- Forced colors are written, not proved (A5): the browsers at hand can’t emulate them. They need a look on Windows with a contrast theme.
- Two navigations share one name: the language pill and the footer’s language list are both “Language”.
- Spacing literals off the scale (3rem, 2rem, 0.75rem and others) remain from before L3.
- Two topic dots pass narrowly on light chips: meaning at 1.6:1 and careers at 1.9:1, against a floor of 1.5.
- The scenes are 800px captures of the Gemini window, not full-size downloads: fine at the sizes used, soft on large screens. Full size comes from Chrome (K10).
- K10 and K11 have no specimen on this page yet, only on the home.
12. Changelog
- 0.4 · 2026-11-03. The home with the character goes live: Leon’s likeness, his choice. New rules K10 (the character) and K11 (hills); K6 cards become pebbles. The scenes are built by Astro’s
<Image>(sizes andsrcset). - 0.3 · 2026-11-02. The page in three languages: the rules in
src/brand/spec/<lang>.md, the page’s words insrc/brand/ui.ts, and a build check that keeps translations at the original’s version (V7). - 0.2 · 2026-11-02. Closed the gaps of 0.1. Every role is one
light-dark()line (C9). Topic colors became tokens; the fundamentals dot is visible in the dark again (C6), and the dead CSS around it is gone. Accessible names are translated (V6).theme-colorreads the tokens (M3). A spacing scale (L3, proved to change no value). Rules for forced colors and print (A5, A6); print checked by printing to PDF. - 0.1 · 2026-11-02. First version, extracted from the sessions that built the site: the identity, the sunflower, the theme toggle.