# Design record *tilde.style — initiated 2026-06-17. Rebuilt as a three-style switcher 2026-07-21 (see Provenance).* ## Design intention 1. **What is this site for?** The homepage for the tilde.style toolkit itself — its job is to demonstrate what the toolkit produces, not to commit to one metaphor the way a real tilde site would. 2. **Who tends it?** Torsten — alone. 3. **What physical space does it remind you of?** Not one space — three, shown side by side: a pond garden, a bonfire clearing, a glider aloft. A visitor picks one and the whole page becomes it. 4. **What should a visitor feel in the first 10 seconds?** That these are real, distinct, lived-in design languages — not palette swatches. The photo strip under each gallery card exists to prove that at a glance. 5. **What would feel completely wrong here?** Corporate design language, scale-first vocabulary, anything that feels like a product launch. Also wrong: treating the switcher itself as license to mix seasons/styles *silently* anywhere else — see `tend.md`'s season-mixing section, which names this page as the one deliberate, declared exception. ## Active configuration: theme switcher, not a single style This page is the specific, named exception in the toolkit's own guidance (`skill/reference/tend.md`): *"build a real theme switcher only when a site's actual job is to demonstrate the style system itself... not as the default answer to a season-mixing bug."* A real tilde site should still commit to one style. This one is the toolkit's own kitchen sink. Three styles ship, each fully documented — and fully self-contained — in its own directory. This file no longer duplicates their palettes/typography/ components, and neither does the CSS: - **Gardening** — `styles/gardening/style.md` + `styles/gardening/style.css` - **Bonfire** — `styles/bonfire/style.md` (+ `style-v0.1.md` for the pre-grounded original) + `styles/bonfire/style.css` - **Sailplane** — `styles/sailplane/style.md` + `DESIGN.md` + `styles/sailplane/style.css` `index.html` links all four stylesheets (`site.css` + the three `styles/{name}/style.css`). This is genuinely just CSS's own cascade doing the work — the browser merges everything it loads into one rule set before resolving conflicts, regardless of how many files it came from, so there was never a need to hand-concatenate them into one `site.css`. Each style's tokens are scoped to its own `[data-theme="…"]` selector (not a shared `:root`), so two styles could even reuse a token name without collision — confirmed non-colliding by name anyway, but the scoping makes that guaranteed rather than just currently-true. `site.css` itself now owns only what's unique to *this* page and nothing style-specific: the reset, the gallery/contact-sheet layout, the switcher chrome, and the `.theme-panel` show/hide toggle. Adding a fourth style is: write `styles/newstyle/style.css`, add one `` line, add one gallery card + panel + switcher button — no existing file needs editing. ## Tooling (added 2026-07-21): `./wiggle` + `./wiggle-verify` That last paragraph used to be a recipe a human followed by hand. It's now code: two Cobra CLIs, source under `tools/cmd/wiggle/` and `tools/cmd/wiggle-verify/` (a Go module — `go.work` at the repo root wires it into the workspace), built via `make build` (see the repo-root `Makefile`; both compiled binaries are gitignored). **Named `wiggle`, not `toolkit` or `tilde-style-tools`.** `~` is informally called "squiggle"/"wiggle" for its wavy shape, so the name is grounded in the actual tilde character this whole project is about — and as a verb it describes what using it does: click a different style, the whole page wiggles into a new shape (matching the homepage's own framing: "click one to see the whole page become it"). Styles get noun/gerund names (Gardening, Bonfire, Sailplane, things); the tool that operates on them gets a verb. Modeled loosely on [hmans/beans](https://github.com/hmans/beans)' CLI structure (the same `beans` this project's own `.beans/` tracking already runs on) — thin `main.go` per binary, Cobra subcommands, one binary per weight class. Credit where due: reading its actual source (not just its README) is where the two-binary split and the `PersistentPreRunE` shared-init pattern came from. **Two binaries, split by dependency weight** (same reasoning as `beans` splitting `beans-serve`/`beans-tui` out from core `beans`): `verify` needs `chromedp` — a full headless-Chrome automation stack — while `add`/`link` need almost nothing. Splitting them means the everyday tool (`./wiggle`, ~6MB) never links in a browser-automation dependency it doesn't use; `./wiggle-verify` (~13MB) carries that weight alone, and isn't needed for the common case of just adding a style. - **`./wiggle add `** — scaffolds `styles//style.css` with loud placeholder-magenta tokens: scaffolded, not designed. Never touches `index.html`. The toolkit's own central constraint ("you bring the design intention, the AI executes it") still applies to filling it in — this only removes the copy-paste, never invents a metaphor. - **`./wiggle link `** — wires an *existing* `styles//style.css` into `index.html` at four marker comments (`` etc. — see `index.html` itself): ``, gallery card, switcher button, placeholder panel. Requires the file from `add` to already exist. Splitting `add`/`link` means a style can be drafted and iterated on before it's wired into the live page at all, or a style built by `/tilde-style language` some other way can be linked in without re-scaffolding it. ``` ./wiggle add morphing # ... design it for real, replace the placeholder tokens ... ./wiggle link morphing --tagline "Transition as content, not decoration." --chip easing ``` - **`./wiggle-verify`** — the regression harness, driving real Chrome via `chromedp` (Go's equivalent of Playwright/Puppeteer, CDP-based). No subcommand layer — this binary only ever does one thing. Discovers every style straight from the live DOM (no hardcoded theme list — a new style added by `add`/`link` or by hand is covered automatically), clicks each switcher button for real, and asserts: exactly one panel visible, a non-transparent computed background, the gallery-card/switcher-button three-way sync, and that the choice survives a reload (the localStorage contract). `--screenshots ` optionally drops a full-page PNG per theme — chromedp already drives the browser, so an artifact per theme is one more action, not a separate manual step. ``` ./wiggle-verify --screenshots /tmp/tilde-style-shots ``` The background-transparency check exists because of a real incident: a stray `*/` inside a CSS comment (`styles/*/`, meaning "each style's own directory") closed the comment early and silently dropped tilde.style's entire `:root` token block, so every `var(--token)` background resolved to nothing. It was caught by eye, from a screenshot, after the fact. `verify` would have caught it the moment it shipped. ## Page structure - **`#gallery`** — a static strip of 3 `.gallery-card` buttons (not a rotating carousel — deliberately simultaneous, so all three are visible at once). Each card carries its own colors, a real named component as a chip (Lernhappen / kindling / Variometer), and a **contact-sheet photo strip**: two small real photographs the style's palette was sampled from, so the "grounded in a real photo, not a mood board" claim is checkable at a glance, not just asserted in prose. - **`#style-switcher`** — sticky nav, three buttons, mirrors the gallery's selection. - **Three `.theme-panel[data-theme]` blocks** — full page (header/main/footer) per style, `display:none` unless `.active`. Only the selected panel's markup is visible; the other two stay in the DOM (simplest correct approach for a small, single-page site — no need for lazy mounting). - **`setTheme()`** — one shared JS function syncs switcher buttons, gallery cards, and panels together, persists the choice to `localStorage['tilde-style-theme']`, and restores it on load. ## Photo provenance (added 2026-07-21) Every style's palette is sampled from real photographs, not invented — copied into the project as durable assets rather than left as session scratch files or external URLs: | Style | Photos | Source | |---|---|---| | Gardening | `styles/gardening/photos/pond-teich-morgen.jpg`, `pond-overview.jpg` | The literal pond behind chatbot-garden's Teich-Morgen palette (also used in `~/chatbot-garden/backend/ui/assets/pond/`) | | Bonfire | `styles/bonfire/photos/funkenflug-sparks.jpg`, `erntetag-gathering.jpg` | A long-exposure night shot of sparks (Funkenflug) and a real Erntedank harvest-festival bonfire in daylight (Erntetag) | | Sailplane | `styles/sailplane/photos/dusk-tideline.jpg`, `aloft-cloud-deck.jpg` | Dusk on the Vancouver tideline, and the view above the cloud deck from an actual glider flight | All resized to a max 900px edge and stripped of EXIF before committing (originals were camera-resolution, up to 8MB — unnecessary for a 56px thumbnail). Referenced both as the gallery cards' contact-sheet strip and named explicitly in each panel's own Styles section copy, so the claim appears at both the point of proof (thumbnail) and the point of assertion (prose). ## Anti-patterns - **Corporate chrome** — Stripe gradients, Notion toggles, Linear dark mode out of context - **Scale-first vocabulary** — no "users", "growth", "engagement", "onboarding" - **Product launch aesthetics** — no countdown CTAs, no "Get started free", no hero animations - **Cold palette without warmth** — no slate-and-teal, no purple gradients - **Infinite scroll** - **Authorless generation** — no AI output without recorded intention in this file or a style's own `style.md` - **Silent season/style mixing anywhere but here** — this page is the named exception; a real tilde site commits to one style - **Letting the switcher become an excuse to skip grounding** — every style added here must still pass through `/tilde-style language` and get its own real metaphor + (ideally) real photos, not just a plausible palette ## Motion - Minimal. Panel switching is instant (no crossfade) — deliberate, since a transition between three unrelated visual worlds reads as a glitch, not polish. - Hover transitions on cards/links: `150ms–300ms ease` max. - All animations have a `prefers-reduced-motion: reduce` counterpart. ## Known gaps - Mobile nav pattern for `#style-switcher` not yet stress-tested beyond the existing gallery breakpoint at 720px. - Only 2 photos shown per style; more exist for Bonfire/Sailplane (Immich, `~/Pictures/sailing/`) if a deeper "provenance" page is ever built. - No defined grid for multi-column layouts beyond what each style's own `style.md` specifies. ## Provenance - **v0.1** (2026-06-17–2026-07-20) — single-style homepage, Bonfire only, night-first, no `dawn` mode built. Superseded, not deleted: preserved as `styles/bonfire/style-v0.1.md`. - **v0.2** (2026-07-21) — rebuilt as the three-style gallery + switcher described above, once Gardening and a properly-grounded Sailplane/Bonfire v0.2 all existed as real, documented, contributed styles worth showing side by side. Photo contact-sheets added same day, after the initial switcher build shipped without them.