CLAUDE.md#
Tips for future agents working in this repo.
Architecture#
src/engine/pulseq/ vendored pulseq +mr tree (86 .m files) + LICENSE +
VENDORED.md; NEVER edit — re-sync with `npm run
vendor-pulseq` (reads ../../pulseq by default)
src/engine/mrFiles.ts +mr tree as numbl boot files (vite ?raw glob), with
+mr/+aux/md5.m replaced by a wrapper over numbl's
`hash` builtin (the original needs Java on MATLAB)
src/engine/runner.ts run-per-execution wrapper over numbl/browser
createNumblSession: boots idle (mip off, no
persistence) with +mr + main.m staged, executes
'main;', collects *.seq via a dir() snippet, disposes.
Cancel = dispose (works without cross-origin isolation).
src/seq/parseSeq.ts .seq parser (v1.4.x/1.5.x), column layouts and unit
scales mirror pulseq's @Sequence/read.m; shape RLE
decompression mirrors decompressShape.m
src/seq/reconstruct.ts ParsedSeq -> plottable polylines, mirroring
Sequence.waveforms_and_times (trap vertices, centers-
raster arbitrary grads get first/last edge points,
extended trapezoids use vertices as stored)
src/viewer/ canvas Timeline (min/max pixel decimation, wheel zoom,
drag pan, click-to-select block), ReportPanel,
BlockInspector
src/examples/ gallery: 3 curated .m (fid/epi/gre, hand-written with
the autoLabel toggle), catalog.ts (name/category/desc per
id), generated-timings.ts (AUTO), and pulseq/*.m —
auto-adapted demoSeq scripts written by gen-examples.mjs.
ExamplesModal groups them by category.
test-data/golden/ .seq goldens generated by Octave and verified
byte-identical against real MATLAB R2026b
Examples pipeline#
The gallery's pulseq demos are generated, not hand-maintained:
node scripts/test-demos.mjsbatch-runs every../../pulseq/matlab/demoSeqscript on numbl in isolated child processes. It adapts each (strips visualization/analysis/scanner-side-effect statements, truncates after the firstseq.write, re-appends trailing local functions), stages +mr with the md5 + isSigPyAvailable overrides, runs it, and parses the output with the JS parser. Writesscripts/demo-results.json.node scripts/gen-examples.mjsreads that JSON and writessrc/examples/ pulseq/<id>.mfor every demo that ran cleanly AND has acatalog.tsentry that isn't already curated (fid/epi/gre), plusgenerated-timings.ts.- 12 of 42 demos run on numbl today (fid, epi, EpiRS, EpiSpinEcho,
EpiSpinEchoRS, FastRadialGradientEcho, GradientEcho/gre, GRE_live_demo
[_step0], RadialGradientEcho, UTE, UTE_rs). The rest hit numbl gaps — see
the numbl-gap list in the
seqlab-projectmemory. Re-run both scripts after numbl improvements to pick up newly-working demos. adaptDemois exported from test-demos.mjs and reused by gen-examples; that file only runs the batch when executed directly (isMain guard), so importing it foradaptDemois safe.
Key gotchas#
- numbl >= 0.4.17. Needs the pulseq-compat fixes (inputParser optionals,
dictionary FallbackValue, containers.Map sorted keys,
hashbuiltin, fnint/ppint, warning('off',id), sprintf -0, …). package.json points atfile:../../numblwhile 0.4.17 is unpublished; switch to^0.4.17before deploy, thenrm -rf node_modules package-lock.json && npm install. For local numbl changes runnpm run build:lib && npm run build:browserthere. - The .seq filename is discovered, not assumed. The runner lists
*.seqin the session cwd after the run (COLLECT_SNIPPET); scripts may write any name(s), and each file becomes a viewer tab. execute('main;'), not the script text. Running by name keeps MATLAB script semantics (local functions allowed); the trailing semicolon suppresses a spuriousansdisplay under the REPL's displayResults.- scripts/engine-test.mjs mirrors worker.ts exactly (idle boot: cwd /project, relative workspace-file names, mainScriptPath 'repl', empty search paths). If numbl's browser worker changes its call shape, update the mirror or the test stops being representative.
- Node runs the .ts sources directly (Node >= 22.6 type stripping), which
is why src/seq imports use explicit
.tsextensions. - GRE takes ~30 s in-browser/Node (interpreter mode; numbl's JIT declines most pulseq code — see numbl-jit-performance). FID ~1 s, EPI ~2 s. Keep gallery time labels honest.
- Signature hashing: the md5 covers the file up to but excluding the
newline that precedes
[SIGNATURE].
Testing#
npm run engine-test— FID through the exact worker call shape, byte-compared against test-data/golden/fid.seq.npm run parser-test— parser/reconstruction invariants on all 5 goldens (fid, gre, seq1-3): signature verification, block/event counts, tamper detection, RLE round-trip.node scripts/run-example.mjs <fid|epi|gre>— run any example headlessly.- Browser verification (worker boot, editor, timeline interactions, drag &
drop) is manual:
npm run dev.