The Keel animation library
Every animation in Keel, playable, with its static fallback, plus the tokens and engineering notes behind them. It reads the same tokens as the app, so the theme switch changes everything here too. Color, type and components live in the design system.
Color
Semantic tokens, shown with the values the current theme resolves to. 60% canvas, 30% surface, 10% accent; status colors never use the lime.
Type, space and shape
- Reading date · Switzer 400, 52px
- Oct 25
- Page title · Switzer 400, 30 to 34px
- This stretch
- Body · Switzer 400, 14 to 17px
- Keel looks at your bills, your paydays and your usual spending.
- Amounts · Switzer 500, tabular
- $1,240.00 · $142.00 · $17.00
- Radii
--r-sm 6pxchips ·--r-md 10pxbuttons and inputs ·--r-lg 16pxpanels and sheets- Elevation
- A 1px hairline first;
--liftshadow only for things that float (sheets, the device frame) - Targets
- 44px minimum for every control; switches use an invisible hit area around a 28px visual
Motion: Keel Motion Language
Settle, reveal, connect, respond, reassure. Every animation must answer: what does this movement help someone understand?
| Token | Value now | Use |
|---|
Reduced motion (the OS setting, or the switch on the case study) resolves every duration to 0ms. Refresh this table with it on to see.
Animation library
Twelve hand-authored Lottie animations and four data-bound SVG charts. Each Lottie has a light and a dark file with identical keyframes, and a static SVG fallback of its settled frame. Nothing plays until you ask.
Rive library
Keel’s four Rive state machines are authored and running. They’re written in code by source/rive/build_rive.py (light and dark artboards in each file, 24 KB for all four) and run live in the case study (see them): the Equilibrium Indicator (steadinessValue, ghostValue, isInteracting, isLoading, hasUpdated), the Interactive Savings Goal, the Onboarding Equilibrium and the Scenario Visualization. Number inputs drive 1D blend states between poses keyed at each end of the range, so values draw exactly. The app ships the web implementations, which use the same input names, because the Rive runtime alone outweighs the app’s first load. One more .riv on the case study is a CC BY community toggle by ashishb, recolored to these tokens. Read the specification.
Engineering
- Components:
assets/js/keel-lottie.js(player),assets/js/keel-charts.js(data-bound charts),assets/css/components.css(rows, chips, chart parts). The app and the case study both use them. - Loading: lottie-web loads on first need; each JSON is fetched once and only within 300px of the viewport; playback pauses off-screen and in hidden tabs.
- Budget: every Lottie under 20 KB raw; all 24 files total 30 KB gzipped.
- Accessibility: named animations are
role="img"with a label; decorative ones are hidden; every animation has a static end state; charts have text equivalents. - Build:
python3 source/lottie/build.pyregenerates the library;node source/lottie/gen_specs.cjsregenerates the specs. - Reports: QA, accessibility and performance · Animation specifications and storyboards