1# CLAUDE.md
3Tips for future agents working in this repo. Patterned after the sibling
4`surfacefun-interactive` project (same numbl + uihtml two-way bridge), but the
5figure is a 2D canvas instead of a three.js surface.
7## Architecture
9- `app/` — React single-file widget (`npm run build` → `app/dist/index.html`)
10- `*.m` at root — scripts users open and run in [numbl](https://numbl.org)
11- `helpers/` — the region/sampling algorithm (`make_region`, `hit_and_run`,
12 `hit_and_run_general`), put on the path by the driver via `addpath('helpers')`
13- `numbl-project.json` — project metadata; `entry` is the landing page. Its
14 `figures` array declares the editor-less figure view the deploy exposes at
15 `#figure/sampler` (runs `hitandrun_demo.m`, shows just the interactive figure);
16 the org profile's "live" link points there.
18### Multi-file layout / addpath
20`hitandrun_demo.m` is the **driver**; its first statement is
21`addpath('helpers')` so `make_region` / `hit_and_run` resolve from the subdir.
22Two constraints make that placement mandatory:
24- `addpath(<literal>)` must be a **leading** statement in the driver, before any
25 other non-comment statement (numbl's static path resolution requires it; the
26 runtime/interpreter path is fine with it too). It also cannot live inside a
27 function file — only the driver. So `hitandrun_sampler.m` can't add the path
28 itself; run `hitandrun_demo.m`, not the sampler directly.
29- Plain subdirectories are otherwise invisible to function resolution — only
30 `addpath`'d dirs (plus root, `+pkg`, `@Class`, `private/`) are searched.
32This works the same in the browser deploy (the worker runs the interpreter,
33which honors the runtime `addpath`).
35## Data flow
37**MATLAB → figure:** set `uihtml(..., 'Data', struct)` or call
38`sendEventToHTMLSource(src, 'eventName', data)`
40**Figure → MATLAB:** call `sendToMATLAB('eventName', value)` (see `bridge.ts`);
41receive via `HTMLEventReceivedFcn`
43## The demo, built in stages (all done)
451. **(done)** Generate a convex region + `N` hit-and-run samples in the script;
46 show region + samples in the figure. The samples are drawn server-side and
47 sent via `Data`.
482. **(done)** Add controls to the figure panel: a **Samples** slider, a
49 **Resample** button, and a **New region** button.
503. **(done)** Wire those controls to the sampler (two-way bridge).
514. **(done)** Non-convex regions. A **non-convex region** checkbox switches to a
52 star polygon (`make_region(false)`) sampled by `hit_and_run_general`; the
53 movie draws the multiple in-region segments a line makes through it.
55The figure → script protocol (each request carries `convex`):
57- **Samples** slider (on release) / **Resample** →
58 `sendToMATLAB('resample', { n, x, y, convex })`. `x, y` are the *current
59 region's* vertices — the script is **stateless**, so it samples the region it
60 is given and replies with `sendEventToHTMLSource(src, 'samples', { x, y, n })`.
61- **New region** / **non-convex** toggle → `sendToMATLAB('newRegion', { n,
62 convex })`. The script builds a new region of that type and replies with a full
63 `sendEventToHTMLSource(src, 'data', <payload>)` (same shape as the initial
64 `Data`, plus `convex`).
66`hitandrun_sampler.m`'s `sample_region(vx, vy, n, convex)` dispatches to
67`hit_and_run` (convex, JIT) or `hit_and_run_general` (non-convex, interpreter).
68The non-convex path can't JIT (sort + point-in-polygon), so `App.tsx` caps its
69`N` lower via `SAMPLE_CHOICES_NONCONVEX`.
71Ideas for the next iteration: show the chain path / burn-in, animate the walk,
72or a "uniform vs. non-uniform target" toggle.
74## Client-side vs. server-side interactivity
76- **Low-latency / view-only** (e.g. dot size, zoom): update React state only —
77 instant, no MATLAB round-trip.
78- **New samples** (depends on the RNG and the algorithm): `sendToMATLAB` →
79 script re-runs → `sendEventToHTMLSource` → React re-renders.
81## Key files
83| File | Purpose |
84|------|---------|
85| `app/src/App.tsx` | Main React component; reads data, hosts the panel, non-convex toggle + movie `regionSegments` |
86| `app/src/render/RegionView.tsx` | 2D canvas renderer (region outline + sample dots + movie `segments`) |
87| `app/src/bridge.ts` | `onData` / `onHostEvent` / `sendToMATLAB` helpers (generic; identical across these projects) |
88| `hitandrun_sampler.m` | Opens the figure, sends data, handles `resample`/`newRegion` (figure plumbing: `on_event`, `sample_region`, `pack_data`, `pack_samples`) |
89| `helpers/make_region.m` | Random region — convex hull of disk points, or `make_region(false)` for a star polygon |
90| `helpers/hit_and_run.m` | Convex hit-and-run sampler (half-plane chord intersection; JIT) |
91| `helpers/hit_and_run_general.m` | Non-convex hit-and-run sampler (all in-region segments; interpreter) |
92| `hitandrun_demo.m` | User-facing driver: `addpath('helpers')` + seed + call the sampler |
94## Local iteration
96Always rebuild the figure app first — both workflows read the prebuilt
97`app/dist/index.html`:
99```
100cd app && npm install && npm run build # produces app/dist/index.html
101cd ..
102```
104`NUMBL` below is a local clone of https://github.com/flatironinstitute/numbl
105(e.g. `~/src/numbl`). Run its CLI with `npx tsx $NUMBL/src/cli.ts …` — no
106global install.
108### A. Quick run via the CLI (fastest inner loop)
110```
111npx tsx $NUMBL/src/cli.ts run hitandrun_demo.m --plot
112```
114`--plot` opens the figure in a browser and keeps the script's session alive so
115figure → script callbacks work (Ctrl+C to stop). Good for iterating on the `.m`
116+ app together.
118### B. Preview the actual GitHub Pages site locally
120This reproduces what the [deploy workflow](.github/workflows/deploy.yml) ships
121(it calls `flatironinstitute/numbl/.github/actions/build-site@main`, which is
122just `cli.ts build-site` after building the site-viewer). The numbl in the
123deployed site runs the `.m` in a **web worker in the browser**, and it keeps a
124live uihtml session there — so figure → script callbacks (`resample`) round-trip
125in the deployed site exactly like in the CLI `--plot` path. (That two-way bridge
126is why the workflow builds numbl from `main` rather than the npm release.)
128```
129# one-time, in the numbl clone: build the browser site-viewer
130( cd $NUMBL && npm ci && npm run build:site-viewer )
132# from this project: bundle project + viewer into _site/
133npx tsx $NUMBL/src/cli.ts build-site . --out _site --base /
135# serve it (localhost is a secure context, so coi-serviceworker.js can set the
136# COOP/COEP headers numbl's WASM needs)
137( cd _site && python3 -m http.server 8080 )
138# → open http://localhost:8080/
139```
141Notes:
142- `--base /` is for serving at localhost root. GitHub Pages serves this project
143 at `/<repo>/`, so the workflow auto-detects `--base /hitandrun-interactive/`.
144 Content is identical; only asset paths differ.
145- `_site/` and `dist/` are git-ignored (see `.gitignore`).
146- The real target is GitHub Pages, where the same single-file app runs against
147 numbl compiled in the browser.