An open API service indexing awesome lists of open source software.

https://github.com/andymai/plancktons

Browser + headless TypeScript study of Hill T₁ orthoscheme ("Planckton") tetrahedra: random face-to-face aggregation, packing fractions η_C/η_B, gyration descriptors, fractal dimension, pair correlation, Avrami kinetics, m³-reptile dissection, SAT-correct overlap. R3F + Vite.
https://github.com/andymai/plancktons

computational-geometry discrete-geometry fractal-dimension hill-tetrahedra jamming monte-carlo orthoscheme packing packing-density plancktons random-sequential-adsorption react-three-fiber reptile separating-axis-theorem tetrahedra threejs typescript vite

Last synced: about 17 hours ago
JSON representation

Browser + headless TypeScript study of Hill T₁ orthoscheme ("Planckton") tetrahedra: random face-to-face aggregation, packing fractions η_C/η_B, gyration descriptors, fractal dimension, pair correlation, Avrami kinetics, m³-reptile dissection, SAT-correct overlap. R3F + Vite.

Awesome Lists containing this project

README

          

# Plancktons

[![CI](https://github.com/andymai/plancktons/actions/workflows/ci.yml/badge.svg)](https://github.com/andymai/plancktons/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/github/license/andymai/plancktons)](./LICENSE)

Interactive 3D study of Hill T₁ orthoschemes and their random face-to-face assemblies.

[Live](https://andymai.github.io/plancktons/) · [Theory](./THEORY.md) · [Proof](./docs/PROOF.md)

Browser playground plus a headless CLI for batch runs.

**Deep dive:** [THEORY.md](./THEORY.md) — Schläfli orthoschemes, Hilbert's
third problem, Matoušek-Safernová's m³-reptile theorem, jamming, gyration-
tensor descriptors, fractal dimension, pair correlation, and where Plancktons
sit relative to sphere FCC, regular-tet packing, and random close packing in
the literature.

**Proof of zero overlap:** [docs/PROOF.md](./docs/PROOF.md) — separating-
axis test correctness + numerical margin analysis.

## What's a Planckton?

The Hill orthoscheme T₁ (Hill 1896): the right tetrahedron with vertices

```
V₀ = (0, 0, 0) V₁ = (L, 0, 0) V₂ = (L, L, 0) V₃ = (L, L, L)
```

Volume `L³ / 6`. Six edges of three distinct lengths `(L, L√2, L√3)`. Four
right-triangle faces:

- `(L, L, L√2)` isoceles right (×2)
- `(L, L√2, L√3)` scalene right (×2)

All 6 dihedral angles are rational multiples of π - i.e. the Dehn invariant
is zero - which is exactly the condition that makes T₁ scissors-congruent to
a cube. So 6 Plancktons tile a cube, 8 tile a doubled Planckton (the m³
reptile), 64 tile it recursively, etc. By Matoušek-Safernová (2010) this is
the **only** k-reptile family for tetrahedra (k = m³).

The chiral mirror is its other handedness (red = right-handed, white =
left-handed in the default color scheme).

## Scenes

1. **Single Planckton inspector** - chiral pair side by side, toggle
handedness, dihedral angles in rational π form.
2. **Cube triptych** - three 6-piece dissections side by side: the classical
geometric (3R+3L) main-diagonal cube and the two HT-realizable mirrors
(4R+2L, 2R+4L) buildable from one Matoušek decomposition. Synchronized
explode slider. η = 1 each.
3. **8-reptile dissection** - eight unit Plancktons tile a doubled
Planckton; recurse to 64 sub-Plancktons. η = 1 at every depth.
4. **Random face-to-face growth** - face-restricted cluster aggregation
(Eden-like growth on the face graph) with SAT overlap rejection. Live
readout of two distinct η values, gyration descriptors, free-face shape
counts, vertex / tet coordination, bbox.
5. **Vacuum-bag compaction** - N loose, freely-oriented Plancktons squeezed
into a jammed random packing by a contracting "bag" (a deterministic,
frictionless 6-DOF rigid-body settle seeded by the same LCG, so the same
seed reproduces the same packing). Press **Pack it** to run the settle off
the main thread, then scrub the "% air removed" timeline to replay the air
being drawn out. The wrinkled vacuum-seal skin is the morphological hull of
the sealed pack; η (η*C/η_B/η_M/η_V), R_g, and a contact-coordination
number are computed on the final jammed frame. Unlike growth, tets here are
\_not* face-mated — they only touch where the physics pushes them together,
so this is a genuinely different (looser, frictionless) kind of packing.

## The two η values

The HUD reports **both**:

| Metric | Formula | Meaning |
| ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **η_C** | V★ / V_hull | Convex compactness - the hull shrink-wraps the aggregate, so this can approach 1 even for sparse clusters. Compare within this app, **not** to literature packing densities. |
| **η_B** | V★ / V_bbox | Bbox packing fraction. Bbox is a fixed-orientation container, so this **is** comparable to literature sphere RCP ≈ 0.636, FCC ≈ 0.74, etc. |

V★ = N · L³/6 (exact sum of part volumes; face-to-face mating never overlaps).

## Two growth strategies

- **Uniform** - pick any free face with equal probability.
- **Compact** - Boltzmann weight `p(face) ∝ exp(β · n̂ · ĉ)` biases toward
concave pockets (n̂ = outward face normal, ĉ = direction to assembly
centroid). Slider over β: 0 recovers uniform, β ≈ 3 is the default sweet
spot, β → ∞ is greedy.

Chirality bias slider `c_R ∈ [0, 1]` controls the per-attempt probability of
drawing a right-handed template. The resulting R:L ratio in the assembly
depends on which chiralities geometrically fit, not purely on the bias.

Both strategies use a two-phase placement:

1. **Phase 1** - random sampling, ≤ 80 attempts.
2. **Phase 2** - deterministic exhaustive search over every (free face ×
chirality × template face × perm) before declaring "jammed". If any valid
placement exists, it is found.

## Disclosure modes

A three-position switch in the topbar (**Learn / Explore / Research**) controls how much UI is exposed:

- **Learn** (default) — scene picker, essential growth parameters (N, seed, strategy), basic metrics tile (N, η_C, η_B, free surface). Inline dotted-underlined terms open a glossary popover; the `?` button opens a full help overlay with scene-aware primer + concepts + glossary tabs.
- **Explore** — adds the Display panel (colors, hull, gyration ellipsoid, edge outlines, render gap) and the advanced metrics sections (gyration / shape, bond-orientational order, topology / chirality, bounding box).
- **Research** — adds histograms, η-vs-N sweeps, pair correlation, kinetics, autocorrelation, MC refinement, and the morphological / Voronoi η variants. Reference packing densities overlay onto the plots.

Press `?` to cycle modes. The state round-trips through the share link as `m: learn|explore|research`; legacy links with `a: true/false` still decode (`true → research`, `false → learn`).

## Research mode features

- **Trial histogram** at fixed N - distribution of η_C, A/B overlay, mean ±
SEM, CSV export with build provenance.
- **η vs N curve** - error band defaults to SEM (toggle to ±σ for trial
spread). Choose **η_C** or **η_B** on the y axis. Fits three candidate
models simultaneously:
- `1 − η ∝ N^α` (pure power law) - reports `α ± Δα`
- `1 − η = y∞ + B·N^(−β)` (asymptote + power correction)
- `1 − η = y∞ + B·exp(−N/N₀)` (exponential approach)
- Model selection by AIC; ΔAIC > 2 is meaningful.
- **Fractal dimension D_f** - fit from R_g ∼ N^(1/D_f). D_f → 3 for compact
3D growth; lower values indicate fractal / surface-dominated aggregation.
- **Pair correlation g(r)** - averaged over an ensemble of seeds. Random
uniform → 1; crystalline order → sharp peaks; amorphous → broad peaks
decaying to 1.
- **Reference packing densities** table with full citations (Hales / Kepler
conjecture, Conway-Torquato, Hoylman, Scott-Kilgour, Onoda-Liniger).

## Detailed HUD (growth scene)

| Section | Quantities |
| -------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Bulk | N (with stalled marker), V★, V_hull, **η_C**, **η_B**, free surface |
| Gyration / shape | R_g, asphericity b, acylindricity c, anisotropy κ², prolateness S |
| Topology / chirality | R / L counts, free-face fraction, ⟨z⟩ tet-tet coordination, ⟨coord⟩ / max vertex coordination, free iso / scalene |
| Bounding box | V_bbox, dims |

Toggle the **gyration ellipsoid** overlay to see the principal axes of the
gyration tensor. NB: this is NOT the inertia ellipsoid - the inertia tensor
`I_ij = ⟨r²⟩δ_ij − ⟨rᵢrⱼ⟩` has different (orthogonal) principal directions.

## CLI - `scripts/study.ts`

For real ensemble averages, fit-grade statistics, and offline pipelines:

```bash
# 500 trials at N=50, compact β=4 → CSV
npm run study -- --N 50 --trials 500 --strategy compact --beta 4 \
--out compact_b4.csv

# Sweep N at constant trials → one CSV
npm run study -- --sweep-N 10,20,30,50,80,120 --trials 200 \
--strategy uniform --out uniform_sweep.csv

# JSON Lines, for streaming into a notebook
npm run study -- --N 30 --trials 1000 --format jsonl --out trials.jsonl

# Parallel: fan trials out across N node:worker_threads. 'auto' picks
# max(1, min(8, cpus()-1)). Output is bit-identical to single-worker.
npm run study -- --N 50 --trials 500 --workers auto --out compact_par.csv
```

CSV columns:

```
trial, N, seed, V, Vbbox, Vstar, efficiency, bboxEfficiency, surface,
rg, kappaSq, prolateness, meanCoord, maxCoord, meanTetCoord, chirR, ms
```

(efficiency = η_C, bboxEfficiency = η_B, meanTetCoord = ⟨z⟩.)

Every CSV is prefixed with a `#`-commented provenance block:

```
# plancktons export
# algorithm_version=2
# commit=
# build_time=
# export_time=
# n_trials=200
# startSeed=1
# chiralityBias=0.5
# strategy=compact
# compactBeta=3
```

so re-runs months later can identify the exact code that produced the data.
JSON exports (`exportAssemblyJSON`) carry the same provenance object.

The CLI uses the same kernel as the browser, so results are bit-identical
and `seed_t = startSeed + t·9973` is fully reproducible.

## Export and share

- **Share link** - encodes scene/seed/N/strategy/β/chirality in the URL hash.
- **PNG** - canvas screenshot.
- **STL** - watertight STL of the current assembly.
- **JSON** - full state dump with provenance.

## Scope

To set expectations, this project deliberately does not:

- **Simulate general tetrahedral shapes** — only the Hill T₁ orthoscheme (and its chiral mirror) is modeled; no other tetrahedra, polyhedra, or particle types are supported.
- **Produce tetrahedral meshes for FEA or CAD** — the geometry kernel exists to drive the interactive study, not as a mesh-generation library for engineering workflows.
- **Model physical forces or dynamics in the growth study** — the face-to-face growth kernel is combinatorial (adjacency + SAT overlap rejection); there is no energy minimization or fluid simulation there. (The separate **vacuum-bag scene** _is_ a frictionless rigid-body settle, but it's a browser-only visualization, not part of the CSV/CLI study pipeline.)
- **Optimize packing density** — the tool studies random face-to-face assemblies; it does not search for maximum-density configurations or compete with dedicated sphere/polyhedron packing solvers.
- **Run large-scale statistical campaigns in the browser** — the browser UI is capped by Web Worker throughput; the headless CLI (`scripts/study.ts`) is the intended path for fit-grade ensemble runs.

## Local development

```bash
npm install
npm run dev # http://localhost:5173
npm run build # production bundle in dist/
npm run preview # serve the bundle locally

npm run validate # typecheck + lint + format:check + test
npm run test # vitest
npm run test:coverage
```

Pre-commit hook (husky) runs `validate` automatically.

## Source layout

```
src/
lib/ Pure math (no React, no THREE imports allowed)
Geometry kernel: planckton, assembly, hull, mesh, canonicalScenes,
spatialHash, vertexHash, kdtree, validate
Strategies & RNG: rng, vec, constants
Statistics: study, studyClient, workerPool, scaling, shape,
paircorr, autocorr, kinetics, steinhardt,
embeddedCubes, mcRefine, morphology, voronoi
I/O: exports, svgExport, provenance, references, store
scenes/ R3F components (read lib, never imported by lib)
SceneCanvas, SingleScene, CubeScene, ReptileScene, GrowthScene,
PlancktonMesh, HullMesh, GyrationEllipsoid, DihedralLabels, CameraFit
ui/ React UI (reads lib + scenes, never imported by lib)
Chrome: Controls, HUD, Actions, ModeSwitch, MetricsPanel,
ProgressBar, Transport, HelpOverlay, Term, glossary,
FirstVisitToast, icons, SvgPlot
Layout: ResizableSidebar, ResizablePane, ErrorBoundary
State & hooks: uiStore, useDraftValue, useKeyboard, useRadioGroup,
useWorkerRun, DraftSlider
controls/ Per-scene control panels (Single, Cube, Reptile,
Growth, Display, Analyses)
research/ Research-mode panels (Histogram, Curve, Kinetics,
Autocorr, PairCorrelation, Steinhardt, References)
worker/
study.worker.ts Browser Web Worker entry (uses lib only)
scripts/
study.ts Headless batch CLI (npm run study)
_studyWorker.ts node:worker_threads worker used by --workers
brepjsOverlap.ts Independent OpenCascade overlap oracle (devDep)
preliminary-analyze.ts, preliminary-q4.ts Offline analysis helpers
tests/ Vitest suites
docs/
PROOF.md SAT overlap-test correctness proof
data/preliminary/ CSVs backing THEORY.md §4.5
```

## Known gaps

- **No two-level Ns × trials fan-out for curve sweeps.** The browser pool
partitions Ns across workers; if Ns is shorter than the pool size, some
cores idle. A two-level partition would help short-Ns / many-trials
sweeps but adds CurvePoint-merge complexity. The CLI sidesteps this by
fanning trials within a single N across `node:worker_threads` (see
`scripts/study.ts --workers`).

## References

The full bibliographic list is in [THEORY.md §5-§6](./THEORY.md). Key entries:

- M. J. M. Hill, _Determination of the volumes of certain species of
tetrahedra without employment of the method of limits_, Proc. Lond. Math.
Soc. 2:39 (1896).
- J. Matoušek & Z. Safernová, _On the nonexistence of k-reptile tetrahedra_,
[arXiv:1006.1807](https://arxiv.org/abs/1006.1807) (2010).
- E. R. Chen, M. Engel & S. C. Glotzer, _Dense crystalline dimer packings of
regular tetrahedra_, Discrete Comput. Geom. 44:253 (2010),
[doi:10.1007/s00454-010-9273-0](https://doi.org/10.1007/s00454-010-9273-0).
- D. N. Theodorou & U. W. Suter, _Shape of unperturbed linear polymers:
polypropylene_, Macromolecules 18:1206 (1985) - gyration descriptors.
- J. Rudnick & G. Gaspari, _The asphericity of random walks_, J. Phys. A
19:L191 (1986) - κ² normalization.

## License

MIT - see [LICENSE](./LICENSE).