← Direction Field Lab

READER → STUDENT → RESEARCHER → AUTHOR

One experiment should survive every handoff.

Begin with a figure that runs on a static blog. Clone the lab only when you want to change its structure. Move into TinyAD and Polyscope when the experiment needs a serious native solver. Publish the validated element program with the result.

00Readstatic figure
01Forkbrowser lab
02ResearchTinyAD + Polyscope
03Publishblog + artifact

CHOOSE THE SMALLEST ENVIRONMENT THAT ANSWERS THE QUESTION

Start without installing the entire research stack

WEB CLONE

Change the web experiment

Use this when you want new controls, plots, element kinds, or lessons. The committed Wasm is already present. Open the Direction Field Lab repository ↗

git clone https://github.com/the13fools/direction-field-lab.git
cd direction-field-lab
npm ci
npm run doctor
npm run dev
Open http://localhost:4173. Node 22+ is the only required runtime for this path.
NATIVE PROJECT

Change C++ and inspect in Polyscope

Copy the deliberately small starter when your method needs arbitrary C++, mesh neighborhoods, or native debugging.

cp -R geometry-processing-starter-kit ../my-geometry-project
cd ../my-geometry-project
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j 4
./build/geometry-processing-starter
The first configure downloads the pinned Eigen, TinyAD, and Polyscope dependencies.

THE THREAD THROUGH ALL THREE ENVIRONMENTS

The element program is the research object

A picture is evidence that something rendered. The shared file records what was optimized: unknown association, target, parameters, local expression, edge connection term, face circulation term, and solver choice.

  • element-program.json runs in the browser and lives in a share URL.
  • GeneratedElementProgram.hh carries the same terms into TinyAD.
  • generated_element_program.py is a readable Python reference.
  • result@2 carries mesh fields and diagnostics back to the web or Polyscope.
{
  "unknown": {
    "association": "vertex",
    "dimension": 2,
    "frame": "tangent"
  },
  "terms": [
    "vertex expression",
    "edge connection",
    "triangle circulation"
  ],
  "solver": "damped sparse Newton"
}

STATIC BY DEFAULT

Publish without operating a compiler service

The browser solver, Wasm kernels, examples, and documentation compile into ordinary files under dist/. Public hosting never receives arbitrary C++ or launches Polyscope.

RECOMMENDED FOR STUDENT FORKS

GitHub Pages

  1. Push the fork to GitHub.
  2. Choose Settings → Pages → GitHub Actions.
  3. Run Publish website, or push to main.
  4. Paste the published experiment URL into the blog embed tool.

The included workflow verifies the numerical tests and the subpath-safe static build before deployment.

ANY STATIC HOST

Build once, upload dist/

npm ci
npm run check

Configure the host’s output directory as dist. Relative asset URLs allow the lab to live at a domain root or repository subpath.

SGI BLOG

Embed, with a durable fallback

In the workshop, choose Copy iframe for a live figure and include the full-page link underneath. If the blog sanitizes iframes, use the generated Markdown fallback instead.

Create a publication kit →

KNOW THE BOUNDARY

What works where

CapabilityBlog / PagesLocal webNative
Edit scalar energyyesyesin C++
Sparse Hessian + Newton/PCGbrowserbrowserTinyAD
Compile edited TinyAD C++no · rebuild siteyes · bridge + toolchainyes
Open Polyscopedownload onlyloopback bridgeyes
Share by URLyesyesexport result

The key distinction: JSON and guided controls supply data to code that is already compiled. The Energy Playground expression uses a separate TypeScript autodiff engine. A C++ callback editor on the static site is a source editor and exporter; its changes execute only after a native or Wasm rebuild.