Reference detail moved out of
CLAUDE.mdto keep that file a terse map. This is the full text for the viewer's controls, panels, input, and selection model.
One collapsible "neurarium" panel bottom-left (#controls; #controls-toggle collapses the
body). The body splits into #settings-pane and #details-pane (#info-body), switched by the
#panel-tabs bar: a pinned Settings tab (#tab-settings) + one closable tab per opened
detail in #detail-tabs (see Detail tabs + Info panel). The settings pane holds, pinned at top,
the #lang-switch (EN/FR) + a keyboard-shortcuts / reset / search / legend / sources / about
.toolbar-row, then:
- Controls (
#controls-settings): the Separate + Transparency sliders, the Auto-rotate / Show all names / Show projections / See inside checkboxes, and the arrow colour-mode switch (#color-mode). Ships open; toggles independently of the accordion. - Four single-open-accordion sections (opening one closes the others): Structures
(
#structures), Projections (#projections, "Projections & Circuits"), Receptors & targets (#receptors), Drugs (#drugs, with#drugs-filter). - Three toolbar-icon popups (all
.modal-overlay, viawireModal): Legend (#legend-modal), Sources & provenance (#sourcing-modal), About (#about-modal).
The accordion is a list of {toggle, body} in wireControls; wireCollapse(onToggle) +
setSection() drive it. Searching swaps #search in for #controls-main.
Pan-aside. While expanded, the brain is pushed clear of the panel (updatePanelPan ->
focus.setScreenOffset -> PerspectiveCamera.setViewOffset, eased in focus.tick; gated on the
panel being visible so ?ui=0 is unaffected). Portrait: full-width bottom-half panel, brain up.
Landscape: left sidebar, brain right.
Scroll model. The panel is an overflow:hidden flex column that never scrolls; its top chrome
is pinned and exactly one inner region scrolls (#controls-main, or #details-pane/#search). A
min-height:0 flex chain gives an open section its natural height with the list scrolling.
- Auto-rotate (OrbitControls
autoRotate, on by default): off the moment the user picks content (selection.onPick(stopAutoRotate));?autorotate=1forces on. - Show all names (
#toggle-names, off): every label on. Key n;?names=all. - Show projections (
#toggle-projections, on): unchecking hides every arrow (projVis; composes with the Hypothetical toggle). - See inside (
#see-inside, off):createNearCullrecomputes each frame the structures on the camera-facing side (centre >NEAR_CULL_BIASpast the centre plane) and hides them so deep nuclei show; snapshots visibility to restore; composes with?only=; arrows stay.cull.tick()runs aftercontrols.update(). - Animations (
#toggle-animations,animSettings.enabled): the decorative motion (intro, gem-dot twinkle, drug wash, circuit pulse). Default on for a fine pointer, off for coarse / reduced-motion; persisted. Off is content-preserving: focus still lights regions/arrows + shows a static gem field, just frozen (intro skipped,tick()s to a still frame,playno-ops). - Arrow colour-mode (
#color-mode, default Neurotransmitter): Neurotransmitter =projection.colorper molecule; Potential =projection.signColorby coarse sign (from metasignColors/signLabels).setColorModerecolours in place + rebuilds the Projections section (per sign vs per transmitter). The switch lives outside#projections-bodyso rebuilds never touch it. - Separate slider (0..1 explode): pushes regions radially out (
EXPLODE_STRENGTH); the camera auto-zooms to keep a constant apparent size (focus.zoomForExplodeoffboundingRadiusAt). - Auto-spread (
createAutoSpread): focusing a deep (non-lobe) node from search / a panel animates Separate to full (autoSpreadIfDeep->spreadTo(1)) so it isn't buried; only ever raises the spread; a manual slider grab cancels; a plain 3D click doesn't trigger it. - Intro (
createIntroAnimation): on load the regions assemble from blown-out (Separate 1->0) while the camera follows + sweepsINTRO_ROTATION_TURNS. Drives the slider; suspends/restores auto-rotate; cancelled on a slider grab; skipped when?explode=is pinned. Under the dev banner the brain settles lower/further back (DEV_BANNER_DROP/_UNZOOM). - Transparency slider = material opacity (depth-write off while translucent). Owned by the selection controller, so it composes with isolate dimming.
Single source of truth for what is highlighted/focused.
- Plain 3D click/tap halos a structure (
mesh.userData.halo) or arrow (ProjectionArrow.setHalo); double-click isolates. From search or a detail panel a pick isolates instead (selectStructure({isolate:true})dims the rest + pins the L/R pair;selectConnection({isolate:true})pins the arrow + endpoints). Structure + arrow halos are mutually exclusive. - A Structures legend row toggles that structure (both hemispheres) into the isolate set +
opens its tab (on isolate-on only); a category heading toggles the group. While the set is
non-empty others drop to
DIM, untouched arrows fade (setOpacity), the legend greys non- isolated rows. Additive. - A Circuits row isolates that circuit (
selection.setCircuitpins an arrow set) + plays the pulse (see Circuit animation) + opens its tab (focusCircuit). A Projections row isolates a group viasetCircuit(pins the group's arrows + endpoints; dims every structure) + opens its tab (focusProjectionGroup;dataKey=kind:<kind>/sign:<sign>). Built from non-tentative projections. - Hypothetical pathways (off by default): a "Show speculative (N)" toggle reveals every
tentative(dotted) arrow, composed with Show projections viacreateProjectionVisibility. - reset + double-click empty space fully clear (halos + isolate + circuit).
Hover/tap shows a boxless name label (white glyphs outlined in the region's --label-color + a
black halo); tapping empty space clears. Selecting a structure pins its name for the whole L/R
pair (selection.onHighlight -> labels.setPinned); hovering another adds its label. Labels
carry no "Right/Left" (base_name). pickHover is focus-aware: a focused region the ray passes
through beats a nearer non-focused one.
- Structures (
#structures): rows by group viabuildLegendinto#structures-body. Row click isolates + opens the tab (onPickStructure, gated onselection.isIsolated); heading isolates the group. - Projections (
#projections): samebuildLegendinto#projections-body(the colour-mode switch that drives them lives up in Controls); below it the per-group rows, the Circuits section, and the Hypothetical pathways toggle.buildLegendfills both Structures + Projections and returns one shared focus-greying callback. - Legend (the key) (
#legend-modal, toolbar popup or k): a static colour/symbol key built once bybuildLegendKeyinto#legend-bodyfrom meta (so colours never drift): the expression gem dots, the per-drug effect dots + wash, the drug flow overlay (frommeta.systemFlowKinds), a dotted speculative pathway; ends with a Sources & provenance link (#legend-open-sourcing). Wired bywireLegendModal. - Sources & provenance (
#sourcing-modal,wireSourcingModal): the grade key + coverage tally (#about-sourcing,buildAboutSourcingfromdata.meta.provenanceStats). The single place explaining the sourcing system (see Source provenance); auto-shown over the loading overlay on startup (the gate).buildAboutSourcing(null)renders the static intro + key immediately, a second call fills the tally once loaded. - Receptors & targets (
#receptors) / Drugs (#drugs): see their sections. - About (
#about-modal, ⓘ,wireAboutModal): a blurb (Olivier Cornelis + Claude), an "open an issue" link (cfg.sourceUrl + "/issues", dropped unlesssourceUrlis repo-like), a Source code link, a licence line (AGPL-3.0), a CC BY-SA attribution line, and a Sources & provenance link (#about-open-sourcing). The tally is not here (own popup).
- Touch / mouse: one finger / left-drag rotates; pinch / wheel zooms; two-finger drag pans
(OrbitControls). Shift + wheel drives the Separate slider (a capture-phase
windowlistener swallows it onshiftKey). - Keyboard shortcuts (
wireShortcuts, single-key, ignored while typing / for modifier combos): n names, s spread, l Structures, p Projections, k Legend, c See inside, r Receptors, m Drugs, f search, Tab/Shift+Tab cycle detail tabs, Esc peels one layer (active tab -> clear focus/isolate/circuit -> close search / collapse section). Arrow keys browse the open section (see below). Each maps by clicking the DOM element a mouse user would. - Section row navigation (
sectionNav): with a section open, ArrowDown/Up rove a.kbd-activehighlight over its buttons +.clickablerows, Enter activates. Recomputed each key, wraps, cleared on section change/close + Esc. Typing in the drug filter keeps the arrows. - Toolbar icon-row (wraps to a second row when narrow): keyboard-shortcuts, reset, search (swaps
#searchin place), legend, sources, about. The three popups sharewireModal. - Search: filters structures / connections / receptors / drugs / circuits / projection groups
(the last two tagged
· circuit/· pathways). Type-filter chips (#search-filters) scope to one kind (activeType, session-persisted). Hovering a result transiently applies its full focus via apreviewthunk (theselect*/focus*helpers'preview:true= scene focus only, no panel/tab/camera/auto-spread); leaving the list restores neutral, a click commits. Picking focuses- frames + opens the panel, exactly like the item's legend row (structure/connection via
selectStructure/selectConnection'sisolate); the same focus-on-pick rule holds for detail-panel rows. Only focusable receptors/drugs are searchable. The box remembers the last query for the session. Matching is case/accent-insensitive and normalizes Greek + dashes (foldText+GREEK_NAMES, so "beta" finds "β1" and "5ht" finds "5-HT"; also used by#drugs-filter) over the label + hiddenkeywords. Afield:"value"filter (parseSearchQuery+SEARCH_FIELDS):class:"SNRI"/nbn:"..."(field name folded, so Frenchclasse:works); a drug panel's clickable Class + Nomenclature build such a query (info.onSearch->openSearchWithQuery). A "?" toggles#search-syntax. Connection results carry aconnectionSideTag. Ctrl/Cmd+F intercepts page-find + opens search; Esc closes. Results are relevance-ranked (label-prefix > substring > keyword-only), capped, and keyboard-navigable.
- frames + opens the panel, exactly like the item's legend row (structure/connection via
- Keyboard-shortcuts help popup (
#shortcuts-modal,wireShortcutsHelp): a centered dialog, rows mirroringwireShortcuts(so it can't drift), labels fromshortcuts.*i18n. Opened by the keyboard button or ?; closed by ×, backdrop, or Esc (routed first when open).
Owns the #panel-tabs strip + which pane shows; it does not render a detail or apply focus.
The select* layer (selectStructure/selectConnection/focusTarget/focusDrug/focusCircuit/
focusProjectionGroup) renders + focuses, then calls openDetailTab(key, title, reopen); the
reopen thunk re-runs that select*, so clicking a tab restores content + scene with no duplicated
logic. Keys dedupe one tab per thing (structure:/connection:/target:/drug:/circuit:/
group:); MAX_TABS bounds the strip. Closing the active tab falls back to a neighbour (re-applying
its focus) or, if last, to Settings + onEmpty() (tabs.setOnEmpty(() => selection.clear())).
Interactions: click, × to close, long-press (~450ms) then drag to reorder, wheel/touch-drag to
scroll. The strip is touch-action: none with a JS-driven drag-scroll (a native pan would
pointercancel mid-hold and kill the long-press). Tab/Shift+Tab cycle (tabs.cycle); Esc
closes the active tab (tabs.closeActive, false when only Settings is active).
Pure rendering of a connection / structure / receptor / target / drug / circuit /
projection-group view; the active detail tab drives which shows. Opening the tab +
applying focus is the select* caller's job, so each show*() is reused unchanged
whether first picked or re-shown. An empty-space click returns to Settings
(tabs.showSettings(); detail tabs stay).
Important
Panel changes are cross-cutting: think in node kinds, not one panel. All info
is organized into nodes, and the seven show*() views (connection / structure /
receptor / target / drug / circuit / projection-group) share the same building
blocks (makeProvenancePill, appendSourcedHeading = a node's identity line +
its grade pill, pathwayRow / appendPathwayList, locationList,
appendReference / appendWikiImages, the "Interacting drugs" / "Found in" lists).
When you change what one panel shows or how it renders a row, check whether the
other panel kinds carry the analogous node and would benefit from the same change,
and ask the user about any you find before finishing. Prefer editing the shared
helper over one call site, so a fix lands on every panel that reuses it at once
(this is why the row markup lives in one place). Skipping this means a request made
for one panel silently misses the others.
Every source shows a provenance pill (makeProvenancePill, see Source provenance) with a
hover/tap tooltip via withTip(trigger, text) (a present Wikipedia reference link is the
exception: no pill). The bubble is appended to document.body (escaping the panel's overflow +
dimming), position: fixed, re-placed on scroll/resize (place() / fixedContainingBlock).
Hover/focus reveals; clicking pins it (selectable); only one open at a time (openTip). Touch runs
the click-toggle path only. Text shows the concrete source first, the grade explainer under. Pill
tooltips are info.provNone/provLlm/provSourced/provVerified.
Views:
- connection: label, a
Projectiontype line, route (from → to,↔bidirectional; each endpoint clickable viaendpointEl->onStructurePick), kind + neurotransmitter, description. Each of those rows carries the pathway's ownproj.provenancebadge (no bottom Sources block). Arrow picking (pickArrowAt) beats the region behind. - structure (
showStructure): name, a group heading with the anatomy grade pill (classification_provenance), a Reference row (Wikipedia link orNOSOURCE), the live Wikipedia lead as asourceddescription (fetch-only, no baked copy), then the pathway list. Each connection row: a bolddirectionArrow(inline SVG, pathway colour, out/in/both; wrapped inwithTipso a tap explains direction without bubbling to the row click), the other endpoint, and the pathway's summary pill (proj.provenance, resolved injs/data.js). Left/right twin pathways collapse to one row (by direction + other-endpointbase_name+ label). - receptor / target / drug / circuit / projection-group: see their sections.
A click on empty space closes the panel. Double-click: on a structure isolates it; on empty space recenters.
All framing (reset, search, panel buttons) goes through one smooth tween: moves the orbit pivot +
camera distance, keeps the view direction, advanced once per frame, cancelled the moment the user
grabs the controls. Also owns the screen offset (setScreenOffset, eased in tick) for the
pan-aside. While a focus is held, moving Separate keeps it centered: the explode handler calls
reaimFocused(), enabling a pivot-follow that tick() eases (only the pivot moves, so the
camera holds the user's distance + angle). The tracked center is getFocusMeshes over the live
selection.getSelected(): a single focused structure tracks precisely, a multi-region focus tracks
the visible set's bounding-sphere center (only visible meshes, so it composes with "See inside"). The
follow disables itself once settled, on a camera grab (cancel), or when the focus clears.