# 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.