system
400.wtf

400.wtf / system / docs · docs/ADR/0006-schema-driven-config-panel.md

ADR-0006 — Schema-driven artifact config panel with localStorage persistence

Status: Accepted (documents the existing decision)

Context

Artifacts are parameterized systems (leg counts, forces, colors). Exposing parameters to visitors turns viewers into players — a core memorability lever — and gives the author a live tuning tool during development.

Problem

Give every artifact tunable controls without every artifact hand-building forms, and persist visitor tweaks without a backend.

Decision

A declarative schema (ArtifactConfigSchema: typed fields, groups, defaults, schema version) drives a generic floating panel (ArtifactConfigPanel → ArtifactConfigForm → shared inputs). useArtifactConfig persists state per artifact in localStorage under artifact:<id>:config:v<version>, merging stored values against the current schema so field additions/removals degrade gracefully; bumping version abandons stale state wholesale.

Alternatives considered

  • leva / tweakpane / dat.gui: mature, but React-bound (leva), visually foreign (dat.gui), and all would fight the site’s styling; the panel is also a branding surface.
  • Hand-rolled controls per artifact: n× the work, n× the inconsistency.
  • URL-only state (no localStorage): shareable but forgetful; the roadmap adds URL on top (permalinks, artifacts.md R4) rather than instead.

Tradeoffs

  • (+) New artifact controls = one schema object; persistence and grouping are free.
  • (+) Version key gives a clean migration story (abandonment is a migration strategy at this scale).
  • (−) Stringly typed: config: Record<string, any> — no compile-time link between schema and usage (code-quality R5 plans a generic fix).
  • (−) Panel discoverability is poor (collapsed gear); no URL sharing yet; isDraggable prop is advertised but unimplemented (delete list).
  • (−) No validation on read: corrupt/hand-edited localStorage JSON can throw and brick the artifact page (code-quality R7 adds guards).

Consequences

  • The schema is becoming artifact metadata in its own right: the index preview mode, config permalinks, and OG variations will all read it. Keep it serializable and UI-agnostic.
  • Shared input components (Slider, ColorInput, …) are the seed of the site’s design system — style them once, on brand (branding R1/R6), and everything inherits.

Future evolution

  • URL permalinks (?c=) layered over localStorage (artifacts.md R4).
  • Typed generic schema (code-quality R5).
  • Possible extraction as a Vue package — future-ideas.md, maintenance-tax warning applies.