feat: GPU Lab — simulation worksheet cells + public gallery (roadmap #6)#81
Merged
Conversation
Move the 11-preset InitialConditionType union and grid generator out of the PDE studio page into a pure shared module so the worksheet simulation cell can reuse the exact same preset library. No behavior change; the relocated numeric hot-path keeps its scoped biome noNonNullAssertion override (decision-#21a pattern). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SimulationCell { sim, preset, params } — serializable presets/params
ONLY (plain numbers/strings, never GPU buffers); runtime state stays
component-local
- SIM_REGISTRY param specs/presets for pde-heat/wave/laplace, lorenz,
and direction-field (per-preset param specs + CPU f/g mirroring the
WGSL evalSystem cases)
- updateSimulation action (kind switch resets preset/params to registry
defaults), importFromJSON accepts 'simulation'
- hydrate({ fork }) detaches non-owner loads (worksheetId null,
version 0) so edits create a new worksheet instead of 409-spamming
- visibility metadata in store for the publish toggle
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Additive readonly [number, number] override for the built-in eqParams defaults so worksheet sliders can bind Lotka-Volterra a/b, Van der Pol mu, spiral alpha, pendulum gamma. 32-byte uniform layout unchanged (f32 offsets 6/7); effect deps use the destructured numbers to avoid tuple identity churn. Existing ode page call sites unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SimulationCellContent mounts the three EXISTING renderers as-is: - pde-* -> WebGPUHeatmap (internal WebGPU compute solver + WebGL fallback), IC grids from the shared preset library, gpuSolverEnabled bound to local play/pause state - lorenz -> Lorenz3DRenderer fed by LorenzAttractor.simulate through useDeferredValue(params) so slider drags stay responsive - direction-field -> GpuDirectionField with the new params prop; mounted only while playing so GPU resources init/dispose cleanly detectBestBackend() drives the WebGL2 fallback banner and the no-GPU message card (lorenz + canvas2d). Cell wired into cell.tsx kindMeta + body (dynamic import) and all three add-cell surfaces; toolbar gains the Publish-to-Gallery toggle (useActionState). No manual memoization (React Compiler); strings via worksheet.simulation i18n namespace. Documented the deferred GIF/clip export follow-up design (canvas.captureStream + MediaRecorder WebM, zero deps). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SetWorksheetVisibilitySchema (PUBLIC|PRIVATE) in lib/validations - setWorksheetVisibility server action: auth-gated atomic ownership update (same P2025 shape as saveWorksheet), revalidates /gpu-lab - loadWorksheet result gains isOwner + visibility - client-wrapper hydrates with fork: true for non-owners so a shared worksheet's first edit autosaves as a NEW worksheet owned by the viewer (no version conflicts against the owner's row) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-slider Play/Pause with loop -> bounce -> once mode cycling and 0.5x/1x/2x/4x speed cycling. ONE component-level rAF driver whose tick is a React 19.3 useEffectEvent reading the latest sliders/anims without re-subscribing; values advance (max-min)/4000ms * dt * speed through the existing handleValueChange path so onChange -> re-evaluate keeps firing. loop wraps to min, bounce flips direction at bounds, once stops at max and clears its entry (rAF loop stops when no sliders animate). prefers-reduced-motion: nothing auto-plays and flipping the OS setting mid-animation pauses all sliders. All user-visible strings migrated to the plots.sliders i18n namespace. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- GPU_LAB_WORKSHEETS_QUERY typed document (content JSON included) + regenerated codegen artifacts; resolver already serves a 60s PUBLIC cache hint - RSC gallery page via the in-process SchemaLink client: filters nodes whose content contains a simulation cell, renders glass-morphism cards with sim-kind badges, author (UserSummary fragment unmask), views and relative updated time via next-intl getFormatter - loading.tsx skeleton; command-palette GPU Lab entry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
77 new keys (plots.sliders.*, worksheet.simulation.* incl. params/presets, worksheet.publish*, gpuLab.*, nav.gpuLab) with real translations in en/ru/es/uk/de/fr/ja/zh — correct plural categories per locale (ru/uk one/few/many, ja/zh other-only). No English placeholders; remaining identical strings are cognates/proper nouns (Sigma, Van der Pol, de/fr 'Simulation'/'Pause', fr min/max). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The <span> wrapping the Eye icon + view count had aria-label set, but a plain span's implicit "generic" role does not support ARIA naming (biome lint/a11y/useAriaPropsSupportedByRole). Move the accessible name into a visually-hidden sr-only sibling instead of naming the generic container, and mark the visible count aria-hidden so screen readers read the sr-only text exactly once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… gallery filter Fills the test gap on the GPU Lab feature branch — all four Wave 1 review items get real vitest coverage instead of shipping untested: - lib/simulation/registry.ts: structural invariants over SIM_REGISTRY and DIRECTION_FIELD_PRESETS (min<=default<=max, presets/params resolve real en.json label keys, direction-field f/g never reference an undeclared param key, getSimParams/DEFAULT_PARAMS/DEFAULT_PRESET behavior). - components/worksheet/simulation-cell.tsx: renders the right sliders per SIM_REGISTRY entry, propagates a slider change through the real worksheet store into the mounted (mocked) GPU renderer, atomic preset+params reset on direction-field preset switch, hides the preset select for single-preset kinds, and the unknown-sim-kind fallback renders instead of crashing. GPU renderers, ui/slider, and detectBestBackend are mocked — jsdom has no WebGPU/WebGL. - components/plot/variable-sliders.tsx: extracted the rAF tick's per-frame math into a pure, exported `stepSliderValue()` (loop wrap / bounce-and-flip / once-and-finish) so the animation behavior is covered without driving a fake requestAnimationFrame loop through a real component. No behavior change — the component's tick effect event now just calls the extracted function. - app/[locale]/gpu-lab/page.tsx: extracted the "only show worksheets with a simulation cell" rule into lib/simulation/gallery.ts (isSimulationCellData / simKindsOf / filterGalleryWorksheets) so it's unit-testable without a database or RSC rendering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Worksheet content is untrusted input — forked/public gallery worksheets arrive as author-controlled JSON, and the sliders only clamp values written locally. A crafted lorenz `steps` (e.g. 1e9) previously drove an unbounded CPU trajectory loop on open; NaN/out-of-range params reached the GPU renderers unchecked. sanitizeSimParams() clamps every declared spec key to [min, max] and replaces non-finite values with the spec default before any compute or render. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… feat/wave1-gpu-lab Union-merged the 8 locale files (disjoint key sets across the five wave-1 namespaces). Verified: typecheck clean, 486 web tests green, biome clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
publicWorksheetsquery showing only worksheets containing a simulation cell; worksheet PUBLIC/PRIVATE visibility action (atomic ownership check) + fork-on-open for non-ownerscaptureStream/MediaRecorder design)Adversarial-review fix included
stepspreviously drove an unbounded CPU loop on openVerification
web 350 tests (73 new for registry/sim-cell/slider-animation/gallery filter) — green; typecheck + biome clean. Wave-1 roadmap item #6 + unranked slider-animation polish.
🤖 Generated with Claude Code