Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
7.3 KiB
Add motion, haptic and sound tokens to the unified design system
findings (3, ranked by value over effort)
- No motion token exists in any stack — greenfield. Every app that wants an animation currently invents its own number, and one already has.
- No haptic vocabulary exists — the highest-value gap, because
HapticFeedbackneeds no dependency, so three of four apps can adopt it the day this lands. tokens.mdis 260 lines against a 250 cap — it cannot absorb a new section, so motion needs a sibling file.
what
The shared design system has colour, spacing, radius, type and shadow tokens —
and no motion tokens at all. Verified 2026-08-16: no Duration, Curve,
--duration-*, --ease-*, or haptic constant exists in any stack copy. There is
not even a prose position that motion is out of scope.
Consequence across kuhy's Flutter fleet: exactly one animation exists in four
apps — a lone AnimatedContainer(duration: Duration(milliseconds: 200)) with an
inline magic number. Every other transition is a Flutter/browser default.
Create the motion token layer so the per-app prompts (03–09) have something canonical to consume instead of each inventing durations.
where
Repo: ~/src/utils (git repo, has CI + the file-length gate wired).
Create ~/src/utils/unified-design-system/motion.md — the prose freeze.
Do NOT append to ~/src/utils/unified-design-system/tokens.md. It is 260 lines
and the cap is 250, so it already fails the gate; adding to it makes that worse.
screen-size.md was split out of it for exactly this reason — follow that
precedent and add a pointer line in tokens.md only if you can do so without
growing it (i.e. by shortening another line).
Then mirror the tokens into the three code stacks:
| Stack | File | Form |
|---|---|---|
| Flutter/Dart | ~/src/utils/design_system/lib/src/tokens.dart |
class AppDuration / class AppCurve |
| web/React | ~/src/utils/web_ui/src/tokens.css |
--duration-*, --ease-* custom props |
| Python/Tkinter | ~/src/utils/gatelock/gatelock/_window.py (class LockConfig) |
int ms fields — only if meaningful; see must not |
There are three code stacks plus the prose freeze. Do not go hunting for a fourth — it does not exist.
must
-
Define a small scale. Recommended, but use judgement:
instant 0ms · fast 120ms · base 200ms · slow 320ms, and easingstandard (0.2, 0, 0, 1)·decelerate (0, 0, 0, 1)·accelerate (0.3, 0, 1, 1). Justify each value inmotion.mdin one line — the file is a freeze, so the reasoning has to survive without you. -
Include a haptic vocabulary mapped to Flutter's
HapticFeedbackAPI: which semantic event getsselectionClickvslightImpactvsmediumImpact. This is the highest-value part —HapticFeedbackneeds no dependency, so three of four apps can adopt it immediately. -
Include a sound vocabulary: named semantic cues (
confirm,complete,error) with the rule that sound ships on (opt-out) per app, and that each app owns its own asset files. -
State the reduced-motion contract in
motion.md: web uses@media (prefers-reduced-motion: reduce), Flutter usesMediaQuery.of(context).disableAnimations. Motion tokens collapse to0msunder it; haptics and sound are unaffected (they are not motion). -
Keep every file at or under 250 lines (
~/src/utils/file_length/config.py,MAX_LINES = 250)..mdand.pyare capped;.cssis not. -
Cut tags at the end — this is the step that makes the work reach consumers:
design_system-v0.2.0(consumed by~/src/todo, currently onv0.1.0)web_ui-v0.3.2(consumed by~/src/dufs-cloud/web, currently onv0.3.1) Print both tag names at the end of the session; prompts 06, 07 and 08 need them.
-
must not: add motion values to the Tkinter
LockConfigjust for symmetry. Tkinter has no animation framework. If a duration has no meaning there, mark the rown/a (tk)inmotion.mdand leave the Python alone. An honestn/abeats a dead constant. -
must not: express any motion token as a hex-looking value. The existing
palette_check.pyparses#RRGGBBand would either ignore it or trip on it. -
must not: touch any colour token, or add a colour alongside the motion work. That would break
palette_check.py's completeness half. -
must not: add
# noqaortype: ignoreanywhere. -
optional: a
prefers-reduced-motionhelper in~/src/utils/design_system/lib/src/and/orweb_ui/src/so consumers get the collapse behaviour without reimplementing it. Nice, not required.
done
All four hold:
~/src/utils/unified-design-system/motion.mdexists, is ≤250 lines, and defines duration, easing, haptic and sound vocabularies with a one-line rationale each.python3 ~/src/utils/file_length/check.py(or~/src/utils/scripts/check_file_length.sh --all) reports no new violations.tokens.md(260),nielsen-audit.md(258) andREADME.md(257) are pre-existing failures — do not fix them here, but do not add a fourth.python3 ~/src/utils/unified-design-system/scripts/palette_check.pystill exits 0.- Both tags exist:
git -C ~/src/utils tag | grep -E 'design_system-v0.2.0|web_ui-v0.3.2'prints two lines.
verify
Desktop, any way you like — this prompt ships no UI. Run the two gate commands in
done and paste their output. Then confirm the token names you chose are what
prompts 03–09 will reference by printing the Dart class and the CSS custom-prop
block.
read first
~/src/utils/unified-design-system/tokens.md— the existing freeze; match its table format and tone exactly. Note its length problem before editing.~/src/utils/unified-design-system/screen-size.md— the precedent for a sibling file split out oftokens.md(32 lines; short and self-contained).~/src/utils/design_system/lib/src/tokens.dart—AppPalette,AppSpacing,AppRadius,AppTextSize. YourAppDuration/AppCurvesit alongside these.~/src/utils/web_ui/src/tokens.css— the full custom-prop list.~/src/utils/design_system/lib/src/feedback.dart—showToast/showErrorand_show.confirm.dartnext to it already importspackage:flutter/services.dart, soHapticFeedbackis one call away with no new import. This is the natural home for a shared haptic helper.~/src/utils/unified-design-system/scripts/palette_check.py— read the fourparse_*regexes to see why motion tokens are invisible to it. Prompt 02 builds the checker that covers them; do not extend this script here.
context you would otherwise rediscover
- Green CI does not mean no drift for these tokens.
palette_check.pyonly matches#RRGGBB, so a--duration-fast: 120msis invisible to every one of its parsers.palette_map.py:159claims structural values are "checked by the scale check" — no such script exists. Prompt 02 writes it. ~/src/utils/gatelock/is a package inside the~/src/utilsmonorepo, not a standalone repo. It is consumed as a pinned git dependency.- Only
~/src/tododepends ondesign_system; diet-guard, workout_app and wake_alarm hand-transcribe the token values into locallib/ui/theme.dartcopies. So tokens added here reach exactly one app automatically — the others are handled per-prompt.
REMOVE ME AFTER FINISH