2026 overhaul#74
Merged
Merged
Conversation
The pnpm migration's fresh resolve bumped deps within their semver ranges; chroma-js 2.1.2->2.6.0 broke swampPalette (new chroma() no longer constructable), crashing the swamp scene. Pin all direct deps to their pre-migration (yarn.lock) versions so the pnpm baseline is behavior-identical, and assert the canvas is attached rather than visible so the smoke test does not depend on asset load time.
…cument smoke scope Address final-review findings: assert info-specific content (.info-subheader) instead of a non-empty #app tautology; set reuseExistingServer to !CI; note in the checklist that the smoke test does not exercise asset/audio loading.
Adds the regression baseline and migrates the package manager to pnpm with all direct deps pinned to pre-migration versions. Smoke 5/5 green; final review clean.
Replace react-scripts with Vite 6 (dev server :3000, output to build/). Move index.html to repo root, swap process.env.REACT_APP_*/PUBLIC_URL for import.meta.env, point Playwright webServer at Vite. Fixes required to make the migration actually run: - esbuild jsx loader for .js files (this codebase keeps JSX in .js) - replace require(app-config.json) with an ESM import (Vite is ESM-only) Also remove stale committed CRA build artifacts from public/ (bundle.js, styles.css + maps). React 17 and three r108 unchanged; build OK, smoke 5/5.
Replace the CRA react-app preset and .eslintrc.json with eslint.config.js (react-hooks + react-refresh), drop eslint-plugin-prettier, bump Prettier to 3.
CRA is gone, so pnpm no longer needs a flat node_modules. Strict mode reinstall surfaced no phantom dependencies; build and smoke stay green.
Prettier 3 was installed but unwired after dropping eslint-plugin-prettier; add a 'format' script so it is runnable standalone (per the P1 plan).
…radually The stop branch used gsap.to(strokeDashoffset: 0), which reads its start value lazily. The active->stopped re-render sets the resting offset to 0 first, so gsap animated 0->0 (a no-op) and the ring appeared instantly. Use gsap.fromTo from the full offset, symmetric with the start sweep, so it always fills in.
Driving the svg strokeDashoffset off the live `active` prop made React reset it on the active->stopped re-render, racing gsap: with gsap.to it snapped full (React set 0 before gsap read it); with gsap.fromTo it flashed full for a frame (React painted 0 before gsap's first tick). Seed the resting offset from the mount-time active state only, so React never re-applies it and gsap owns the property — gsap.to now reads the real current offset and fills smoothly.
Integrate ~25 commits of quality work (perf-review merge, CDN/CI changes, and the vanilla-extract + cx styling refactor) into the studio branch. Conflict resolutions keep the studio cleanups on top of quality's refactor: - ToggleButton: kept the ToggleButtonView extraction; carried quality's scoped toggleButton/svgCircle classes (via cx) into ToggleButtonView. - LoadingIcon/LoadingScreen/CustomSongIcons.css: kept the dead loading-state removal; dropped quality's now-unused loadingButton style/import. - SocialIcons: kept the instagram removal on quality's cx-refactored rows. Studio updated for quality's newly-scoped classes: SongIconsStory uses songSelectionPanel/songLink, MenuStory uses flexPanel; menu e2e selector .menu-button-parent -> .menu-button-child.
- StudioSidebar: compose classes with cx and dedup groups via Set - Add root CLAUDE.md noting the cx className convention - Studio: redirect unknown/bare storyId to the default story's URL - Document /studio dev-server coupling in the e2e spec - Rename ToggleButtonView active prop to initialActive (write-once contract) Claude-Session: https://claude.ai/code/session_011utsEBGPQyyYstVH2HdAxR
Add dev-only /studio component playground
Quality refactor
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
mracette
commented
Jun 27, 2026
Correctness:
- mathUtils.normalize: branches were inverted and the `clamp` param
shadowed the clamp helper, so the default path threw and clamp=true
never clamped (FOV escaped its range on extreme aspect ratios).
- ToggleButtonGroup randomize: clamp the target count to the voice
count so the de-dupe loop can't spin forever / index past the end.
Reducer removal (also clears the lone react-refresh warning):
- Replace LandingPage useReducer + landingPageReducer with useState and
a song lookup; rename the `dispatch({type})` prop to `onSelect(id)`
across the song icons, LandingPageMobile, and the story.
Simplification / reuse:
- Collapse the solo/mute and background-mode conditionals.
- Dedupe the store reset/randomize callback registries; export and
reuse VoiceState instead of a duplicate PlayerState union.
- Reuse mathUtils.clamp/lerp and a new audioUtils.averageVolume helper;
drop a dead Stars.lerp method, dead rotateZ params, and a
commented-out Redux button.
- Widen cx() to accept null.
Twin of the MusicPlayer change: the trailing else-if (!backgroundMode) is always true, so collapse it to else.
Add "type":"module" and rewrite the last require/module.exports holdouts (eslint + playwright configs, e2e specs and helpers) as import/export so the whole package is uniformly ESM. Clears the ts(80001) suggestions.
Replace the hand-rolled chroma-js shim with @types/chroma-js (the official types are complete), and drop the ~25 `(chroma as any)` casts plus the non-idiomatic `new chroma(...)` calls. Type the EXT_disjoint_timer_query extension and the OfflineAudioContext vendor fallback instead of casting to any, add easeQuad to the d3-ease shim, use rest params over `arguments`, ignore _-prefixed unused vars, and drop a dead `vh` import. Remaining 20 are intentional: ~11 three.js casts (types pinned at @types/three 0.103 vs three 0.108 runtime) and 9 React Compiler advisory diagnostics on deliberate imperative escape hatches.
Delete unused shaders/birds.ts and the stale LandingPage.vert/.frag (the landing-page shaders are inlined in LandingPageParticles.ts). Replace the hand-rolled d3-color/d3-ease/d3-scale-chromatic shims with @types/d3-* @3.
The remaining any casts are all in the viz layer, bridging the @types/three@0.103 vs three@0.108 runtime gap. Scope the rule off to src/viz so those stop warning while the rest of the codebase keeps the guard.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.