Skip to content
Merged
20 changes: 10 additions & 10 deletions brainsnn-r3f-app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GaugeGap Foundry | Play with the impossible</title>

<meta name="description" content="Playable science by BrainSNN. Change the rules of live simulations, discover unexpected states, and export the exact run as a challenge, poster or short clip." />
<meta name="description" content="Playable science and custom interactive experiences by BrainSNN. Explore live simulations, share exact run states, or build a focused pilot for your audience." />
<meta name="theme-color" content="#030308" />
<link rel="canonical" href="https://brainsnn.com/" />
<link rel="canonical" href="https://www.brainsnn.com/" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="manifest" href="/site.webmanifest" />

<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="GaugeGap Foundry by BrainSNN" />
<meta property="og:title" content="GaugeGap Foundry | Don’t just learn the universe. Play with it." />
<meta property="og:description" content="Live science simulations, visual challenges and shareable discoveries. Change one rule, watch reality respond, and publish what you find." />
<meta property="og:url" content="https://brainsnn.com/" />
<meta property="og:image" content="https://brainsnn.com/og-image.png" />
<meta property="og:title" content="GaugeGap Foundry | Do not just explain the idea. Let people operate it." />
<meta property="og:description" content="Live science simulations, visual challenges and client-ready interactive experiences with a visible model and claim boundary." />
<meta property="og:url" content="https://www.brainsnn.com/" />
<meta property="og:image" content="https://www.brainsnn.com/og-image.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />

<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="GaugeGap Foundry | Play with the impossible" />
<meta name="twitter:description" content="Touch the variables, find a discovery, and challenge someone to beat your run." />
<meta name="twitter:image" content="https://brainsnn.com/og-image.png" />
<meta name="twitter:description" content="Explore a live system or build an interactive experience for your audience." />
<meta name="twitter:image" content="https://www.brainsnn.com/og-image.png" />

<!-- Structured data -->
<script type="application/ld+json">
Expand All @@ -35,8 +35,8 @@
"name": "GaugeGap Foundry",
"alternateName": "BrainSNN Interactive Foundry",
"applicationCategory": "EducationalApplication",
"description": "An interactive science, research and publishing platform with playable simulations and reproducible shared run states.",
"url": "https://brainsnn.com/",
"description": "An interactive science, research and publishing platform with playable simulations, reproducible shared states and custom client pilots.",
"url": "https://www.brainsnn.com/",
"operatingSystem": "Web",
"isAccessibleForFree": true
}
Expand Down
121 changes: 69 additions & 52 deletions brainsnn-r3f-app/src/app/GaugeGapLanding.jsx

Large diffs are not rendered by default.

241 changes: 241 additions & 0 deletions brainsnn-r3f-app/src/features/gaugegap/AudiencePathways.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import React from 'react';
import {
ArrowRight,
Building2,
CheckCircle2,
GraduationCap,
Megaphone,
Microscope,
ShieldCheck,
Sparkles,
} from 'lucide-react';
import { Button } from '../../components/ui/Button.jsx';
import { track } from '../../lib/analytics.js';
import '../../styles/audience-pathways.css';

const VISITOR_ROUTES = [
{
id: 'wonder',
icon: Sparkles,
eyebrow: 'I have two minutes',
title: 'Show me something wild',
text: 'Start with the Butterfly Effect and change one number until the future splits.',
action: 'Open the fastest wow',
lab: 'attractor',
},
{
id: 'teach',
icon: GraduationCap,
eyebrow: 'I teach or explain',
title: 'Give me a lesson people remember',
text: 'Paint cellular life, contain an outbreak, or let a class compete on the same model.',
action: 'Open a classroom-ready lab',
lab: 'life',
},
{
id: 'research',
icon: Microscope,
eyebrow: 'I need depth',
title: 'Show me the instrument underneath',
text: 'Move beyond spectacle into parameters, assumptions, limitations and reproducible states.',
action: 'Enter research mode',
route: 'research',
},
{
id: 'client',
icon: Building2,
eyebrow: 'I have an audience or client',
title: 'Build an interactive experience for us',
text: 'Turn a difficult idea, product story or research concept into something people can play and share.',
action: 'See client pilots',
target: 'clients',
},
];

const CLIENT_PATHWAYS = [
{
id: 'education',
icon: GraduationCap,
title: 'Schools, museums and training',
text: 'Transform an abstract concept into a guided lab, exhibit or workshop challenge.',
outcomes: ['Branded interactive lesson', 'Facilitator prompts and missions', 'Shareable student run states'],
},
{
id: 'media',
icon: Megaphone,
title: 'Publishers and creators',
text: 'Turn an article, episode or complex story into a playable explanation that earns a second click.',
outcomes: ['Playable story companion', 'Short-form visual assets', 'Challenge links for distribution'],
},
{
id: 'brand',
icon: Building2,
title: 'Brands and campaigns',
text: 'Build a memorable product or campaign experience without reducing the idea to another landing page.',
outcomes: ['Campaign microsite concept', 'Custom scoring and missions', 'Launch and analytics plan'],
},
{
id: 'research',
icon: Microscope,
title: 'Research and innovation teams',
text: 'Create a browser instrument that preserves settings, communicates limits and produces reviewable outputs.',
outcomes: ['Reproducible experiment state', 'Model and assumption layer', 'Evidence and export workflow'],
},
];

const TRUST_LEVELS = [
{
label: 'Play',
title: 'Explore the behavior',
text: 'A fast visual model designed to build intuition and curiosity.',
},
{
label: 'Teach',
title: 'Explain the mechanism',
text: 'Controls, missions and model notes connect the spectacle to the underlying idea.',
},
{
label: 'Verify',
title: 'Expose the boundary',
text: 'Research releases preserve parameters, assumptions, limitations and reproducible outputs.',
},
];

function openLab(lab) {
const url = new URL(window.location.href);
url.searchParams.set('lab', lab);
url.searchParams.delete('run');
url.searchParams.delete('state');
url.hash = 'playground';
window.history.replaceState({}, '', url);
window.dispatchEvent(new CustomEvent('gaugegap:lab', { detail: { lab } }));
window.requestAnimationFrame(() => document.getElementById('playground')?.scrollIntoView({ behavior: 'smooth', block: 'start' }));
}

export function VisitorRoutes({ onResearch }) {
function chooseRoute(route) {
track('gaugegap_pathway_selected', { pathway: route.id });
if (route.lab) openLab(route.lab);
if (route.route === 'research') onResearch?.();
if (route.target) document.getElementById(route.target)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
Comment on lines +115 to +121

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

Accept onOpenLab as a prop and use it instead of the duplicated module-level openLab helper. This allows us to completely remove the duplicated openLab function from this file, improving maintainability.

Suggested change
export function VisitorRoutes({ onResearch }) {
function chooseRoute(route) {
track('gaugegap_pathway_selected', { pathway: route.id });
if (route.lab) openLab(route.lab);
if (route.route === 'research') onResearch?.();
if (route.target) document.getElementById(route.target)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
export function VisitorRoutes({ onResearch, onOpenLab }) {
function chooseRoute(route) {
track('gaugegap_pathway_selected', { pathway: route.id });
if (route.lab) onOpenLab?.(route.lab);
if (route.route === 'research') onResearch?.();
if (route.target) document.getElementById(route.target)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}


return (
<section className="gg-visitor-routes" aria-labelledby="gg-start-heading">
<div className="gg-audience-heading">
<p className="gg-kicker"><Sparkles size={16} /> Start with what brought you here</p>
<h2 id="gg-start-heading">You should know where to click in five seconds.</h2>
<p>GaugeGap serves curious visitors, educators, researchers and organizations. Pick the path that matches your job right now.</p>
</div>
<div className="gg-route-grid">
{VISITOR_ROUTES.map((route) => {
const Icon = route.icon;
return (
<button key={route.id} type="button" className="gg-route-card" onClick={() => chooseRoute(route)}>
<span className="gg-route-icon"><Icon size={22} /></span>
<small>{route.eyebrow}</small>
<strong>{route.title}</strong>
<p>{route.text}</p>

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

Using a <p> element inside a <button> is invalid HTML5, as <button> elements should only contain phrasing content. Consider changing <p> to a <span> with a class name (e.g., className="gg-route-desc") and updating the corresponding CSS selector in audience-pathways.css to use display: block.

Suggested change
<p>{route.text}</p>
<span className="gg-route-desc">{route.text}</span>

<em>{route.action} <ArrowRight size={15} /></em>
</button>
);
})}
</div>
</section>
);
}

function openClientBrief(pathway) {
const subject = encodeURIComponent(`GaugeGap pilot — ${pathway.title}`);
const body = encodeURIComponent([
'Hi GaugeGap team,',
'',
`I am exploring a ${pathway.title.toLowerCase()} project.`,
'',
'Audience:',
'Concept or topic:',
'What I want people to understand or do:',
'Target launch window:',
'',
'Please suggest the smallest useful pilot.',
].join('\n'));
track('gaugegap_client_cta_clicked', { pathway: pathway.id });
window.location.href = `mailto:hello@brainsnn.com?subject=${subject}&body=${body}`;
}

export function ClientPathways() {
return (
<section id="clients" className="gg-client-section" aria-labelledby="gg-client-heading">
<div className="gg-client-intro">
<div className="gg-audience-heading">
<p className="gg-kicker"><Building2 size={16} /> For organizations and client work</p>
<h2 id="gg-client-heading">Do not buy another explanation page. Build something people can operate.</h2>
<p>GaugeGap can turn a hard idea into a branded interactive experience with a clear mission, measurable behavior and a deeper evidence layer.</p>
</div>
<div className="gg-client-promise">
<ShieldCheck size={24} />
<div>
<strong>Start with one useful pilot</strong>
<span>One audience, one concept, one interaction and one success measure. Expand only after people use it.</span>
</div>
</div>
</div>

<div className="gg-client-grid">
{CLIENT_PATHWAYS.map((pathway) => {
const Icon = pathway.icon;
return (
<article key={pathway.id} className="gg-client-card">
<span className="gg-client-icon"><Icon size={24} /></span>
<h3>{pathway.title}</h3>
<p>{pathway.text}</p>
<ul>
{pathway.outcomes.map((outcome) => <li key={outcome}><CheckCircle2 size={15} /> {outcome}</li>)}
</ul>
<button type="button" onClick={() => openClientBrief(pathway)}>Start this brief <ArrowRight size={15} /></button>
</article>
);
})}
</div>

<div className="gg-pilot-strip">
<div>
<small>Typical first pilot</small>
<strong>Concept → playable prototype → client review → launch-ready experience</strong>
</div>
<div className="gg-pilot-steps" aria-label="Pilot deliverables">
<span>Custom interaction</span><span>Branded interface</span><span>Mission and scoring</span><span>Shareable states</span><span>Model notes</span>
</div>
<Button variant="primary" onClick={() => openClientBrief({ id: 'general', title: 'Custom interactive experience' })}>
Discuss a pilot <ArrowRight size={16} />
</Button>
</div>
</section>
);
}

export function TrustLadder({ onResearch }) {
return (
<section className="gg-trust-section" aria-labelledby="gg-trust-heading">
<div className="gg-audience-heading">
<p className="gg-kicker"><ShieldCheck size={16} /> Know what you are looking at</p>
<h2 id="gg-trust-heading">Fun is the front door. The claim boundary stays visible.</h2>
<p>Not every interactive model is a research result. GaugeGap separates intuition-building experiences from releases that expose enough detail for technical review.</p>
</div>
<div className="gg-trust-grid">
{TRUST_LEVELS.map((level, index) => (
<article key={level.label}>
<span>{String(index + 1).padStart(2, '0')}</span>
<small>{level.label}</small>
<h3>{level.title}</h3>
<p>{level.text}</p>
</article>
))}
</div>
<div className="gg-trust-note">
<p><strong>Current public arcade:</strong> educational numerical models for exploration. Research mode is where assumptions, diagnostics and limitations must be made explicit.</p>
<Button variant="secondary" onClick={onResearch}>Inspect the research layer <Microscope size={16} /></Button>
</div>
</section>
);
}
Loading
Loading