Skip to content

Expand GaugeGap into a four-experiment science arcade#88

Merged
slavazeph-coder merged 4 commits into
mainfrom
feature/gaugegap-science-arcade
Jul 10, 2026
Merged

Expand GaugeGap into a four-experiment science arcade#88
slavazeph-coder merged 4 commits into
mainfrom
feature/gaugegap-science-arcade

Conversation

@slavazeph-coder

Copy link
Copy Markdown
Owner

What this adds

Builds the next GaugeGap growth layer from the strongest patterns in interactive-science libraries: immediate motion, recognizable presets, one clear challenge, different interaction styles, and shareable run states.

Four playable labs

  1. Butterfly Effect — existing Lorenz attractor tuning, scoring, poster and clip export
  2. Firefly Sync — Kuramoto-style collective synchronization with coupling, noise, population and time controls
  3. Wave Eraser — animated two-source interference field with a movable detector and destructive-interference challenge
  4. Living Chemistry — drawable Gray–Scott reaction-diffusion field with coral, cell, maze and worm presets

Arcade experience

  • Horizontal/mobile-friendly experiment selector
  • Surprise-me mechanic
  • Each lab has distinct interaction: tune, synchronize, explore and draw
  • Exact URL state sharing for all new experiments
  • Live challenge scores and mission prompts
  • Updated homepage copy, lab gallery and audience-growth story
  • Existing BrainSNN scanner and research workspace remain intact

Validation requested

  • Typecheck
  • Deterministic tests
  • Production Vite/Express build
  • MCP smoke
  • Manual canvas check on desktop and mobile

@slavazeph-coder slavazeph-coder merged commit f92b0bf 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 introduces a new 'Science Arcade' feature (ExperimentArcade) containing four interactive simulations: the Butterfly Effect, Firefly Sync, Wave Eraser, and Living Chemistry. It adds the simulation logic, state management, and styling, while updating the landing page to integrate the new arcade. Key feedback includes addressing a potential TypeError when copying experiments via navigator.clipboard, fixing the Wave Eraser detector intensity to reflect live wave states instead of freezing on pointer stop, ensuring scrollToPlayground does not reference the removed playgroundRef, and adding -webkit-backdrop-filter prefixes in CSS for Safari compatibility.

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 +37 to +39
navigator.clipboard?.writeText(url.toString())
.then(() => onNotice('Challenge copied. Send it to someone who thinks they can do better.'))
.catch(() => onNotice('Copy was blocked by the browser. Use Share challenge.'));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Using optional chaining navigator.clipboard?.writeText(...) followed by a .then() call will result in a TypeError: Cannot read properties of undefined (reading 'then') if navigator.clipboard is undefined (e.g., in non-secure HTTP contexts or older browsers). Check if navigator.clipboard?.writeText is available before calling it.

Suggested change
navigator.clipboard?.writeText(url.toString())
.then(() => onNotice('Challenge copied. Send it to someone who thinks they can do better.'))
.catch(() => onNotice('Copy was blocked by the browser. Use Share challenge.'));
if (navigator.clipboard?.writeText) {
navigator.clipboard.writeText(url.toString())
.then(() => onNotice('Challenge copied. Send it to someone who thinks they can do better.'))
.catch(() => onNotice('Copy was blocked by the browser. Use Share challenge.'));
} else {
onNotice('Copy is not supported by your browser or in this context.');
}

Comment on lines +381 to +382
const value = (Math.sin(k * Math.hypot(px - s1x, py - sy) - timeRef.current)
+ Math.sin(k * Math.hypot(px - s2x, py - sy) - timeRef.current + active.phase)) * 0.5;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The detector's intensity is calculated using timeRef.current, which continuously changes in the animation loop. However, moveDetector is only triggered on pointer events. When the user stops moving the pointer, the displayed 'Detector energy' score freezes at a random instantaneous value rather than reflecting the live wave state. To fix this without expensive state updates in the render loop, we can calculate the time-independent wave amplitude (envelope) at the detector's position.

Suggested change
const value = (Math.sin(k * Math.hypot(px - s1x, py - sy) - timeRef.current)
+ Math.sin(k * Math.hypot(px - s2x, py - sy) - timeRef.current + active.phase)) * 0.5;
const r1 = Math.hypot(px - s1x, py - sy);
const r2 = Math.hypot(px - s2x, py - sy);
const value = Math.abs(Math.cos((k * (r1 - r2) - active.phase) * 0.5));

const playgroundRef = useRef(null);
const ARCADE_IDS = new Set(['attractor', 'fireflies', 'waves', 'reaction']);

export function GaugeGapLanding({ onStart, onNavigate, onOpenReconstruct }) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The playgroundRef has been removed from this component, but the scrollToPlayground function (which is called in multiple click handlers) likely still references it. This will cause a runtime error when those handlers are triggered. Please update scrollToPlayground to scroll to the new #playground element directly (e.g., using document.getElementById('playground')?.scrollIntoView(...)).

border-radius: 8px;
color: rgba(220, 252, 255, 0.7);
background: rgba(2, 4, 10, 0.72);
backdrop-filter: blur(8px);

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

Add -webkit-backdrop-filter for cross-browser compatibility, as Safari requires the prefix for backdrop filters to work.

Suggested change
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);

border-radius: 999px;
color: #edffb3;
background: rgba(4, 9, 12, 0.72);
backdrop-filter: blur(8px);

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

Add -webkit-backdrop-filter for cross-browser compatibility, as Safari requires the prefix for backdrop filters to work.

Suggested change
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);

@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: 092cd9fedd

ℹ️ 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".

setNotice('The interference map changed instantly. Hunt for a silent node.');
}

const visibility = Math.round(Math.abs(detector.intensity) * 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 Recompute Wave Eraser detector energy live

When the Wave Eraser opens or when its sliders/time change, detector.intensity stays at the last pointer event value (0 initially), so the score can report “Near-perfect silence” while the animated field under the crosshair has a different energy. This affects the default startup state and any stationary detector; recompute the detector intensity in the render loop or whenever params/time advance.

Useful? React with 👍 / 👎.

}

const visibility = Math.round(Math.abs(detector.intensity) * 100);
const state = [params.wavelength, params.spacing, params.phase, params.speed].map((value) => round(value, 3)).join(',');

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 Include detector position in wave challenge state

When users share a Wave Eraser run after finding a quiet point, the URL only encodes the wave parameters and drops the detector coordinates, while a recipient reloads with the detector reset to the center. The copied/shared link therefore cannot reproduce the node that produced the advertised detector score/title, so include detector.x/detector.y in the state and restore them on load.

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