- Three new Lottie companions: Wiggle Dog (摇尾狗), Butterfly (蝴蝶),
Parrot (鹦鹉). Parrot is mirrored via a new `flip` flag on Companion,
threaded through LottiePlayer (scaleX(-1)) since the asset faces left.
- Mascot size now scales with the viewport: --petal-companion-size
clamp(10rem, 17vw, 20rem); art, emoji fallback, and the sleep "z" all
derive from it.
- Larger, more legible tip bubble (1.4rem zh / 1.15rem en, wider bubble).
- Bubbles linger longer for a bilingual ESL read: baseline 9s→14s,
cheer 6s→9s, per-char 45→55ms, cap 20s→32s.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Replace the synthesized WAV blips with curated mp3 effects:
- error ("haiya") plays on LLM-down/timeout and save failures, debounced
and on-transition-only, with a reassuring bilingual bubble
- milestone (Chinese fanfare) now fires every 100 words
- all other notifications draw from a rotating pop pool that never repeats
the last sound, so batches of suggestions/tips stay lively
playPop() replaces the per-suggestion-type sound map; thread llmDown through
PetalCompanion -> useCompanion for the error cue. Old synth WAVs removed.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Add a fixed, GPU-driven petal layer that drifts soft blossoms over the
page (sparse, translucent, paused when hidden, skipped under
prefers-reduced-motion). Add a synthesized cute sound palette — bubble
pop, water droplet, soft bell, sparkle, cheer — generated as embedded
WAV assets (scripts/gen_sounds.py) and played through a quiet Web Audio
bus with soft-clipping and a persisted mute toggle in the status bar.
Sounds fire per suggestion type when fresh advice arrives (staggered,
old pending advice stays silent) and on companion bubbles by tone.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Replace the kitten's random generic tips with a deterministic, LLM-free
prose checker that reads the actual document and surfaces one gentle,
bilingual note at a time — quoting a slice of her own sentence so the
advice is clearly about *this* draft.
Rules (all conservative, tuned for a Mandarin-native ESL writer):
run-ons, comma splices, unclear antecedents, Oxford comma, a/an,
uncountable plurals, capitalize languages/days/months, subject-verb
agreement, plural-after-number, double determiner, "there is" + plural,
its/it's, than/then, comma-after-transition, doubled words, lowercase
"i", sentence capitals, and spacing around punctuation.
Each rule is paired with false-positive guards (e.g. "a university",
"After dinner, I went home and read", existing Oxford lists) and pinned
by a 45-case Vitest suite (npm test).
Also: bubbles now linger proportional to how much there is to read
(zh+en) and pause-on-hover, so denser advice no longer vanishes mid-read.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Companion: bump the corner mascot ~12% (128→144) and make animation
resolution robust — fall back to the idle clip when a mood has no clip of
its own, and pin the always-asleep cat to one pose so its Lottie never
reloads. This stops a bare emoji from replacing the cute companion on idle.
Update notifications: serve a build id at /api/version (a hash of the
embedded dist/index.html, which changes on every frontend deploy). The
client records its load-time id, polls every 90s (and on tab focus), and
floats a Mandarin-first "new version available" banner offering a refresh
when the id changes.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
- Mascot badge 64→128px (Lottie 56→112, emoji fallback 32→64); zzz glyph
scaled + repositioned to match. It read too small on screen.
- Awake companions (no sleeping clip, e.g. Happy Dog) no longer show a 😴
face or drifting "z" when the engine naps them — they hold their idle pose
via a renderMood redirect. Only the always-asleep cat (real sleep clip)
keeps the zzz, preserving that gag.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
Click the mascot to open a bilingual picker and switch between the Sleepy Cat
(always asleep, still talks in her sleep) and the Happy Dog (awake/bouncy).
Choice persists in localStorage.
- companions.ts is the roster; add one by dropping a pure-vector Lottie JSON
in animations/ and appending a COMPANIONS entry.
- napping = companion.alwaysAsleep || mood === 'sleeping' drives the sway/zzz.
- Removed the old single MOOD_ANIMATIONS map (animations/index.ts).
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
- LottiePlayer now auto-crops each asset to its content bbox (union getBBox
across 6 frames -> square viewBox), so stock files with empty artboard
padding fill the badge instead of floating tiny in the middle.
- Wire sleeping-cat.json to every mood: she's always asleep in the corner yet
still mumbles tips and cheers through the bubble. napping hardcoded true so
she keeps the calm sway + drifting zzz even while "talking".
- happy-dog.json parked in the folder as an awake-mascot alternate.
- Enable resolveJsonModule for the JSON imports.
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd
A cozy bottom-right mascot that reacts to the writing session: cheers on
accepted suggestions and word-count milestones, drops Mandarin-first writing
tips, suggests screen breaks after long stretches, and naps when idle.
- useCompanion: library-agnostic behavior engine (priority + cooldown paced
so it never nags); tips.ts holds all copy, bilingual zh-first.
- LottiePlayer wraps lottie-web's light build (offline, no eval/CDN) so it
bundles into the Go binary. Ships with an emoji-kitten placeholder per mood;
dropping a Lottie cat JSON into animations/index.ts is the only swap needed.
- Speech bubble uses the CJK-first font stack (spec Note #17).
Claude-Session: https://claude.ai/code/session_016Yr6jELuRc7hyzYLccQKZd