Skip to content

Launch GaugeGap viral simulation foundry on BrainSNN#86

Merged
slavazeph-coder merged 5 commits into
mainfrom
feature/gaugegap-viral-foundry
Jul 10, 2026
Merged

Launch GaugeGap viral simulation foundry on BrainSNN#86
slavazeph-coder merged 5 commits into
mainfrom
feature/gaugegap-viral-foundry

Conversation

@slavazeph-coder

Copy link
Copy Markdown
Owner

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 /app and the research workspace.

Viral loop built into the first experiment

  • Live Lorenz attractor rendered in-browser
  • Four interactive controls and four presets
  • Chaos / beauty / discovery scoring
  • Challenge URLs that preserve the exact parameter state
  • Native share with clipboard fallback
  • One-click PNG poster export
  • Six-second WebM clip recording from the simulation canvas
  • Reset-only-the-initial-condition mechanic to demonstrate sensitive dependence

Public experience

  • New entertainment-first hero and challenge
  • Play → Discover → Publish product loop
  • Foundry lab cards bridging GaugeGap, the existing soliton research lab, BrainSNN content autopsy and claim-boundary work
  • Explicit research/assumption positioning beneath the entertainment layer
  • Fully responsive dedicated visual system
  • Updated SEO, Open Graph and structured metadata

Deployment

The repository's Railway workflow deploys on push to main. This PR is intentionally CI-gated before merge.

Validation requested

  • Typecheck
  • Deterministic test suite
  • Production Vite/Express build
  • MCP smoke test
  • Manual mobile check of the canvas controls and share/export buttons

@slavazeph-coder slavazeph-coder merged commit 42f0188 into main Jul 10, 2026
1 check passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +74 to +77
function scrollToPlayground() {
track('gaugegap_hero_play_clicked');
document.getElementById('playground')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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' });
}

Comment on lines +145 to +146
const passes = Math.max(4, Math.floor(12 * active.speed));
const dt = 0.0048 * active.speed;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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;

Comment on lines +178 to +181
return () => {
observer.disconnect();
window.cancelAnimationFrame(frameId);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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:

  1. Define the refs at the top of the component:
const recordTimeoutRef = useRef(null);
const recorderRef = useRef(null);
const streamRef = useRef(null);
  1. 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);
  1. Clean them up in the useEffect cleanup 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());
  }
};

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +582 to +584
.gg-attractor-canvas {
width: 100%;
height: 100%;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +201 to +205
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();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant