Conversation
Ports ~/Documents/diffs into src/playgrounds/diffs, rebuilt on react-two.js components. Replaces the mutable Registry and frame-driven layout cursors with one pure buildModel(), and derives highlight state instead of mutating the scene graph and DOM. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduce a new Diffs playground that compares multiple texts by shared vocabulary. This adds the rendering scene, model/tokenization/stemming pipeline, progressive reveal and tween hooks, localStorage-backed session state, legend/stat line components, and playground registration. The change also updates test setup and adds focused tests for the diffs model, canvas rendering, reveal behavior, stat-line interactions, storage, and tokenization, plus the new tween/stemmer dependencies needed by the feature.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
LocalStorage loading and shared-word display selection have confirmed edge-case bugs that can crash or misrepresent output and should be addressed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a new “Diffs” playground to the demo app, porting the original imperative Two.js diffs visualizer into the repo’s declarative react-two.js component style with a testable pure model + progressive reveal.
Changes:
- Introduces the
src/playgrounds/diffs/feature (model, hooks, components, storage) and registers it in the playground registry. - Adds a comprehensive Vitest suite covering tokenization/stopwords, model merge/layout, reveal math, storage, and key SVG-render behavior.
- Updates docs and dev dependencies to support stemming (
wink-porter2-stemmer) and tweening (@tweenjs/tween.js).
File summaries
| File | Description |
|---|---|
| tests/diffsTokenize.test.ts | Tokenize + stopwords tests |
| tests/diffsStorage.test.ts | localStorage persistence tests |
| tests/diffsStatLine.test.tsx | StatLine interaction + baseline tests |
| tests/diffsReveal.test.ts | Progressive reveal chunk tests |
| tests/diffsModel.test.ts | Model merge/sort/layout tests |
| tests/diffsCanvas.test.tsx | Canvas integration tests |
| src/vite-env.d.ts | Stemmer module typing |
| src/test-setup.ts | jsdom matchMedia polyfill |
| src/playgrounds/registry.ts | Registers Diffs playground |
| src/playgrounds/diffs/types.ts | Diffs domain types |
| src/playgrounds/diffs/storage.ts | Diffs localStorage helpers |
| src/playgrounds/diffs/stopwords.ts | Stopwords set + helper |
| src/playgrounds/diffs/model/tokenize.ts | Tokenization logic |
| src/playgrounds/diffs/model/stem.ts | Porter2 stem + cache |
| src/playgrounds/diffs/model/merge.ts | Cross-text shared-word merge |
| src/playgrounds/diffs/model/layout.ts | Layout + coordinates builder |
| src/playgrounds/diffs/model/analyze.ts | Per-text analysis + sorting |
| src/playgrounds/diffs/hooks/useTweenTick.ts | Frame-driven TWEEN.update() |
| src/playgrounds/diffs/hooks/useProgressiveReveal.ts | Frame-driven reveal counter |
| src/playgrounds/diffs/hooks/usePrefersDark.ts | Media-query theme hook |
| src/playgrounds/diffs/hooks/useMeasuredHeight.ts | ResizeObserver height hook |
| src/playgrounds/diffs/hooks/useDiffsModel.ts | Deferred model memoization |
| src/playgrounds/diffs/DiffsPlayground.tsx | DOM chrome + orchestration |
| src/playgrounds/diffs/DiffsCanvas.tsx | ZUI + reveal + camera tween |
| src/playgrounds/diffs/constants.ts | Shared diffs constants |
| src/playgrounds/diffs/components/TextColumn.tsx | Text pane + highlight mode |
| src/playgrounds/diffs/components/StatLine.tsx | Stat line rendering + hit handling |
| src/playgrounds/diffs/components/Legend.tsx | Legend rendering + theming |
| src/playgrounds/diffs/components/GraphLine.tsx | Graph line + highlight ticks |
| src/playgrounds/diffs/components/DiffsScene.tsx | Scene composition + reveal slices |
| src/playgrounds/diffs/components/Arc.tsx | Arc path + tween reveal |
| package.json | Adds tween + stemmer deps |
| package-lock.json | Locks new dependencies |
| docs/superpowers/specs/2026-08-12-diffs-playground-design.md | Diffs design spec |
| docs/superpowers/plans/2026-08-09-zui-hook.md | ZUI implementation plan doc |
| CLAUDE.md | Adds diffs playground notes |
| .claude/launch.json | Dev launch config |
Review details
- Files reviewed: 35/37 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Move SORT_MODES array to types.ts; derive SortMode from it; add isSortMode() guard - Use isSortMode() in loadStoredState() to avoid crashing buildModel on unknown stored modes - Fix mergeTexts to take the shared line's display word from the earliest-index occurrence, not always occurrences[0] - Silence console.error on localStorage write/clear failures (Safari private mode, quota limits) - Add tests covering the display-word fix, the unknown-mode fallback, and the silent-failure paths
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.
Ported a new Playground example into declarative React Two.js style