/* Console 2.0 — Drawer contents. Each renderer takes (ctx, depth) where depth
is 'peek' | 'expand' | 'full'; what shows is gated by depth (the schema-tier
disclosure mechanism, simulated here).
NOTE: these are the PLACEHOLDER drawers. The real dock contents are specified
in docs/redesign/dock-spec.md (six drawers: Learning-Behaviour / Inputs /
Outputs-Routing / Powerful Synth Engine / Particle-Visual / Help). */
const DRW_DS = window.ManifoldDesignSystem_490915;
function Chip({ children, tone }) {
return (
{children}
);
}
function SectionLabel({ children }) {
return
{children}
;
}
const PRESETS = ['Sculpt', 'Wander', 'Lock-in', 'Chaos', 'Glide', 'Pin & probe'];
function FeelDrawer(ctx, depth) {
const { ControlAxis, PillToggle } = DRW_DS;
const axes = [
{ key: 'boldness', label: 'Boldness', endpoints: ['Caution', 'Bold'], accent: 'var(--accent)' },
{ key: 'memory', label: 'Memory', endpoints: ['Amnesia', 'Elephant'], accent: 'var(--accent-2)' },
{ key: 'precision', label: 'Precision', endpoints: ['Raw', 'Precise'], accent: 'var(--accent)' },
];
return (
3 axes
preset · {ctx.preset}
{ctx.offsetActive && offset active }
Compound axes
{axes.map((a) => (
ctx.setAxis(a.key, v)}
preset={a.key === 'boldness' ? (ctx.axes.boldness > 0.66 ? 'explore' : 'steady') : undefined} />
))}
Control presets
{PRESETS.map((p) => (
ctx.setPreset(p)}
style={{
padding: '5px 10px', fontSize: 'var(--fs-xs)', fontFamily: 'var(--font-mono)', cursor: 'pointer',
borderRadius: 'var(--r-pill)', border: `1px solid ${ctx.preset === p ? 'var(--accent)' : 'var(--line)'}`,
background: ctx.preset === p ? 'rgba(255,106,0,0.15)' : 'var(--bg-2)',
color: ctx.preset === p ? 'var(--accent)' : 'var(--fg-mute)',
}}>{p}
))}
{depth !== 'peek' && (
Trim-pot offsets
Axis tweaks layer as offsets over the active preset. Double-tap an axis to re-link. An offset-active dot marks divergence.
)}
);
}
function ShapeDrawer(ctx, depth) {
const { Button, Sparkline, Badge } = DRW_DS;
return (
examples {ctx.datasetCount}
loss {ctx.loss.length ? ctx.loss[ctx.loss.length - 1].toExponential(1) : '—'}
{ctx.busy && training… }
Reinforcement (default)
Use the + / − verdicts on the manifold. Every verdict auto-snapshots first — undo is consequence-free.
Examples (IML)
{ctx.addingExample ? '② store target' : '① add example'}
Train
clear
Loss history
{depth !== 'peek' && (
Snapshot DAG · {ctx.snapshots.length}
{ctx.snapshots.slice().reverse().map((s, idx) => (
ctx.onJump(s.id)} style={{
width: '100%', textAlign: 'left', display: 'flex', justifyContent: 'space-between',
background: idx === 0 ? 'var(--bg-3)' : 'var(--bg-2)', border: '1px solid var(--line)',
borderRadius: 'var(--r-1)', padding: '4px 8px', cursor: 'pointer', fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-xs)',
}}>
{s.tag}
noise {s.noise.toFixed(2)}
))}
)}
);
}
const STATUS_CYCLE = { off: 'fixed', fixed: 'live', live: 'off' };
const STATUS_COLOR = { off: 'var(--fg-dim)', fixed: 'var(--accent-2)', live: 'var(--accent)' };
function RouteDrawer(ctx, depth) {
const { PillToggle, Badge } = DRW_DS;
const counts = ctx.params.reduce((a, p) => { a[p.status] = (a[p.status] || 0) + 1; return a; }, {});
const rows = depth === 'peek' ? ctx.params.slice(0, 6) : ctx.params;
return (
sources {ctx.mode.inN}/48
targets {ctx.params.length}/{ctx.params.length}
live {counts.live || 0}
fixed {counts.fixed || 0}
Input source
{ctx.mode.input === 'joystick' ? 'joystick' : ctx.mode.input === 'audio_in' ? 'mic (1-input)' : 'xy pad'}
Output backend
Control points · off / fixed / live
{rows.map((p, i) => (
{p.name}
{p.group}
ctx.cycleStatus(ctx.params.indexOf(p))}
style={{ width: 52, fontSize: 10, fontFamily: 'var(--font-mono)', textTransform: 'uppercase', letterSpacing: '0.06em',
border: `1px solid ${STATUS_COLOR[p.status]}`, color: STATUS_COLOR[p.status], background: 'transparent',
borderRadius: 'var(--r-1)', padding: '2px 4px', cursor: 'pointer' }}>{p.status}
))}
{depth === 'full' && (
Full tier hosts the Emitters × Targets matrix + per-cell editor + staged-unlock opt-in (built for the modular mega-mode).
)}
);
}
function GradientBars({ norms, status }) {
const COLOR = { vanishing: 'var(--info)', exploding: 'var(--danger)', converged: 'var(--fg-mute)', healthy: 'var(--good)' };
const max = Math.max(...norms, 0.0001);
return (
{norms.map((n, i) => (
))}
);
}
function HealthDrawer(ctx, depth) {
const { Sparkline, Switch, Slider, Badge } = DRW_DS;
const healthTone = ctx.health > 0.66 ? 'good' : ctx.health > 0.33 ? 'warn' : 'bad';
return (
{healthTone === 'good' ? 'healthy' : healthTone === 'warn' ? 'drifting' : 'unstable'}
rev {ctx.weightsRevision}
Loss history
Gradient flow · per layer
{depth !== 'peek' && (
Lab controls
)}
);
}
const KEYS = [['1–5', 'open drawers'], ['\\', 'full depth'], ['space / ↑', 'commit +'], ['↓', 'perturb −'], ['z', 'undo'], ['double-click dot', 'follow mode']];
function HelpDrawer(ctx, depth) {
return (
Keyboard
{KEYS.map(([k, v]) => (
{k}
{v}
))}
The loop
Drag the manifold to explore. Hear something good → + to settle. Wrong → − to perturb. Went too far → ↺ undo. The screen reveals exactly as much machinery as you reach for.
);
}
window.DRAWERS = {
shape: { icon: '◇', label: 'Shape', render: ShapeDrawer },
feel: { icon: '◎', label: 'Feel', render: FeelDrawer },
route: { icon: '⇄', label: 'Route', render: RouteDrawer },
health: { icon: '♥', label: 'Health', render: HealthDrawer },
help: { icon: '?', label: 'Help', render: HelpDrawer },
};