# 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.mjs` batch-runs every `../../pulseq/matlab/demoSeq` script on numbl in isolated child processes. It **adapts** each (strips visualization/analysis/scanner-side-effect statements, truncates after the first `seq.write`, re-appends trailing local functions), stages +mr with the md5 + isSigPyAvailable overrides, runs it, and parses the output with the JS parser. Writes `scripts/demo-results.json`. - `node scripts/gen-examples.mjs` reads that JSON and writes `src/examples/ pulseq/.m` for every demo that ran cleanly AND has a `catalog.ts` entry that isn't already curated (fid/epi/gre), plus `generated-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-project` memory. Re-run both scripts after numbl improvements to pick up newly-working demos. - `adaptDemo` is exported from test-demos.mjs and reused by gen-examples; that file only runs the batch when executed directly (isMain guard), so importing it for `adaptDemo` is safe. ## Key gotchas - **numbl >= 0.4.17.** Needs the pulseq-compat fixes (inputParser optionals, dictionary FallbackValue, containers.Map sorted keys, `hash` builtin, fnint/ppint, warning('off',id), sprintf -0, …). package.json points at `file:../../numbl` while 0.4.17 is unpublished; switch to `^0.4.17` before deploy, then `rm -rf node_modules package-lock.json && npm install`. For local numbl changes run `npm run build:lib && npm run build:browser` there. - **The .seq filename is discovered, not assumed.** The runner lists `*.seq` in 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 spurious `ans` display 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 `.ts` extensions. - **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 ` — run any example headlessly. - Browser verification (worker boot, editor, timeline interactions, drag & drop) is manual: `npm run dev`.