CLAUDE.md#
Tips for future agents working in this repo. Patterned after the sibling
surfacefun-interactive project (same numbl + uihtml two-way bridge), but the
figure is a 2D canvas instead of a three.js surface.
Architecture#
app/— React single-file widget (npm run build→app/dist/index.html)*.mat root — scripts users open and run in numblhelpers/— the region/sampling algorithm (make_region,hit_and_run), put on the path by the driver viaaddpath('helpers')numbl-project.json— project metadata;entryis the landing page
Multi-file layout / addpath#
hitandrun_demo.m is the driver; its first statement is
addpath('helpers') so make_region / hit_and_run resolve from the subdir.
Two constraints make that placement mandatory:
addpath(<literal>)must be a leading statement in the driver, before any other non-comment statement (numbl's static path resolution requires it; the runtime/interpreter path is fine with it too). It also cannot live inside a function file — only the driver. Sohitandrun_sampler.mcan't add the path itself; runhitandrun_demo.m, not the sampler directly.- Plain subdirectories are otherwise invisible to function resolution — only
addpath'd dirs (plus root,+pkg,@Class,private/) are searched.
This works the same in the browser deploy (the worker runs the interpreter,
which honors the runtime addpath).
Data flow#
MATLAB → figure: set uihtml(..., 'Data', struct) or call
sendEventToHTMLSource(src, 'eventName', data)
Figure → MATLAB: call sendToMATLAB('eventName', value) (see bridge.ts);
receive via HTMLEventReceivedFcn
The demo, built in stages (all done)#
- (done) Generate a convex region +
Nhit-and-run samples in the script; show region + samples in the figure. The samples are drawn server-side and sent viaData. - (done) Add controls to the figure panel: a Samples slider, a Resample button, and a New region button.
- (done) Wire those controls to the sampler (two-way bridge).
The figure → script protocol:
- Samples slider (on release) / Resample →
sendToMATLAB('resample', { n, x, y }).x, yare the current region's vertices — the script is stateless, so it samples the region it's given and replies withsendEventToHTMLSource(src, 'samples', { x, y, n }). - New region →
sendToMATLAB('newRegion', { n }). The script builds a new region and replies with a fullsendEventToHTMLSource(src, 'data', <payload>)(same shape as the initialData).
Ideas for the next iteration: show the chain path / burn-in, animate the walk, a "uniform vs. non-uniform target" toggle, or a non-convex region (hit-and-run chords become multiple segments).
Client-side vs. server-side interactivity#
- Low-latency / view-only (e.g. dot size, zoom): update React state only — instant, no MATLAB round-trip.
- New samples (depends on the RNG and the algorithm):
sendToMATLAB→ script re-runs →sendEventToHTMLSource→ React re-renders.
Key files#
| File | Purpose |
|---|---|
app/src/App.tsx |
Main React component; reads data, hosts the panel |
app/src/render/RegionView.tsx |
2D canvas renderer (region outline + sample dots) |
app/src/bridge.ts |
onData / onHostEvent / sendToMATLAB helpers (generic; identical across these projects) |
hitandrun_sampler.m |
Opens the figure, sends data, handles resample/newRegion (figure plumbing: on_event, pack_data, pack_samples) |
helpers/make_region.m |
Random convex region (convex hull of disk points) |
helpers/hit_and_run.m |
The hit-and-run sampler (half-plane chord intersection) |
hitandrun_demo.m |
User-facing driver: addpath('helpers') + seed + call the sampler |
Local iteration#
Always rebuild the figure app first — both workflows read the prebuilt
app/dist/index.html:
cd app && npm install && npm run build # produces app/dist/index.html
cd ..
NUMBL below is a local clone of https://github.com/flatironinstitute/numbl
(e.g. ~/src/numbl). Run its CLI with npx tsx $NUMBL/src/cli.ts … — no
global install.
A. Quick run via the CLI (fastest inner loop)#
npx tsx $NUMBL/src/cli.ts run hitandrun_demo.m --plot
--plot opens the figure in a browser and keeps the script's session alive so
figure → script callbacks work (Ctrl+C to stop). Good for iterating on the .m
- app together.
B. Preview the actual GitHub Pages site locally#
This reproduces what the deploy workflow ships
(it calls flatironinstitute/numbl/.github/actions/build-site@main, which is
just cli.ts build-site after building the site-viewer). The numbl in the
deployed site runs the .m in a web worker in the browser, and it keeps a
live uihtml session there — so figure → script callbacks (resample) round-trip
in the deployed site exactly like in the CLI --plot path. (That two-way bridge
is why the workflow builds numbl from main rather than the npm release.)
# one-time, in the numbl clone: build the browser site-viewer
( cd $NUMBL && npm ci && npm run build:site-viewer )
# from this project: bundle project + viewer into _site/
npx tsx $NUMBL/src/cli.ts build-site . --out _site --base /
# serve it (localhost is a secure context, so coi-serviceworker.js can set the
# COOP/COEP headers numbl's WASM needs)
( cd _site && python3 -m http.server 8080 )
# → open http://localhost:8080/
Notes:
--base /is for serving at localhost root. GitHub Pages serves this project at/<repo>/, so the workflow auto-detects--base /hitandrun-interactive/. Content is identical; only asset paths differ._site/anddist/are git-ignored (see.gitignore).- The real target is GitHub Pages, where the same single-file app runs against numbl compiled in the browser.