Launch GaugeGap viral simulation foundry on BrainSNN#86
Conversation
There was a problem hiding this comment.
Code Review
This pull request transitions the application from "BrainSNN" to "GaugeGap Foundry", introducing a new interactive landing page (GaugeGapLanding) and a live Lorenz attractor simulation playground (AttractorPlayground). Feedback on the changes includes utilizing the existing React ref (playgroundRef) instead of direct DOM queries for scrolling, correcting a quadratic scaling issue with the simulation speed slider by keeping the integration step size (dt) constant, and preventing potential memory leaks by properly cleaning up the recording timeout, recorder, and stream refs if the playground component unmounts during a clip recording.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| function scrollToPlayground() { | ||
| track('gaugegap_hero_play_clicked'); | ||
| document.getElementById('playground')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); | ||
| } |
There was a problem hiding this comment.
You have already defined playgroundRef on line 67 and attached it to the wrapper div on line 171. Instead of querying the DOM directly with document.getElementById('playground'), which is an anti-pattern in React, you should use the existing playgroundRef to scroll to the playground.
| function scrollToPlayground() { | |
| track('gaugegap_hero_play_clicked'); | |
| document.getElementById('playground')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| } | |
| function scrollToPlayground() { | |
| track('gaugegap_hero_play_clicked'); | |
| playgroundRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| } |
| const passes = Math.max(4, Math.floor(12 * active.speed)); | ||
| const dt = 0.0048 * active.speed; |
There was a problem hiding this comment.
The simulation speed scales quadratically (proportional to active.speed^2) because both the number of integration passes per frame and the integration step size dt are multiplied by active.speed. This makes the speed slider highly non-linear and potentially unstable at higher speeds. To achieve linear speed scaling, consider keeping dt constant (e.g., 0.0048) and only scaling passes, or keeping passes constant and only scaling dt.
| const passes = Math.max(4, Math.floor(12 * active.speed)); | |
| const dt = 0.0048 * active.speed; | |
| const passes = Math.max(4, Math.floor(12 * active.speed)); | |
| const dt = 0.0048; |
| return () => { | ||
| observer.disconnect(); | ||
| window.cancelAnimationFrame(frameId); | ||
| }; |
There was a problem hiding this comment.
If the component unmounts while a clip is being recorded, the 6-second timeout and the MediaRecorder will continue to run in the background. When the timeout completes, it will attempt to stop the recorder and update the state of an unmounted component, causing memory leaks and React state update warnings.
To prevent this, you should track the active recording timeout, recorder, and stream in refs and clean them up when the component unmounts:
- Define the refs at the top of the component:
const recordTimeoutRef = useRef(null);
const recorderRef = useRef(null);
const streamRef = useRef(null);- Store the references inside
recordClip:
const stream = canvas.captureStream(30);
streamRef.current = stream;
...
recorderRef.current = recorder;
...
recordTimeoutRef.current = window.setTimeout(() => {
if (recorder.state !== 'inactive') recorder.stop();
}, 6000);- Clean them up in the
useEffectcleanup function:
return () => {
observer.disconnect();
window.cancelAnimationFrame(frameId);
if (recordTimeoutRef.current) window.clearTimeout(recordTimeoutRef.current);
if (recorderRef.current && recorderRef.current.state !== 'inactive') {
recorderRef.current.stop();
}
if (streamRef.current) {
streamRef.current.getTracks().forEach((track) => track.stop());
}
};There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be9b354061
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .gg-attractor-canvas { | ||
| width: 100%; | ||
| height: 100%; |
There was a problem hiding this comment.
Give the attractor canvas a definite height
With the panel only setting min-height, this height: 100% does not have a definite containing height to resolve against in the auto-sized grid row, so the canvas can lay out at its intrinsic height while the panel remains much taller. Because ResizeObserver sizes the drawing buffer from the canvas rect, the live attractor ends up rendered in a short strip instead of filling the 690px experiment area; set a real height on the panel or absolutely inset the canvas.
Useful? React with 👍 / 👎.
| function getShareUrl() { | ||
| const url = new URL(window.location.href); | ||
| url.searchParams.set('run', [params.sigma, params.rho, params.beta, params.speed].map((value) => round(value, 3)).join(',')); | ||
| url.hash = 'playground'; | ||
| return url.toString(); |
There was a problem hiding this comment.
Preserve the initial condition in shared runs
The share URL only serializes sigma,rho,beta,speed, but the playground also lets users change the initial condition and the simulation state is randomized in resetField(). After using “Change only the initial condition” (or sharing a run for its current visual trajectory), the recipient loads the default initial state instead of the run that was shared, so the advertised exact/shareable run state cannot be reproduced.
Useful? React with 👍 / 👎.
What this ships
Repositions the public BrainSNN homepage as GaugeGap Foundry: a playable science, publishing and entertainment front door, while preserving the existing BrainSNN application at
/appand the research workspace.Viral loop built into the first experiment
Public experience
Deployment
The repository's Railway workflow deploys on push to
main. This PR is intentionally CI-gated before merge.Validation requested