{"id":51167026,"url":"https://github.com/andymai/plancktons","last_synced_at":"2026-06-26T20:03:21.509Z","repository":{"id":358359836,"uuid":"1241065894","full_name":"andymai/plancktons","owner":"andymai","description":"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.","archived":false,"fork":false,"pushed_at":"2026-06-12T04:53:50.000Z","size":1579,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T06:24:19.897Z","etag":null,"topics":["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"],"latest_commit_sha":null,"homepage":"https://andymai.github.io/plancktons/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andymai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-16T23:16:10.000Z","updated_at":"2026-06-12T04:53:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/andymai/plancktons","commit_stats":null,"previous_names":["andymai/plancktons"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andymai/plancktons","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andymai%2Fplancktons","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andymai%2Fplancktons/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andymai%2Fplancktons/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andymai%2Fplancktons/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andymai","download_url":"https://codeload.github.com/andymai/plancktons/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andymai%2Fplancktons/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34831250,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["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"],"created_at":"2026-06-26T20:03:20.720Z","updated_at":"2026-06-26T20:03:21.499Z","avatar_url":"https://github.com/andymai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Plancktons\n\n[![CI](https://github.com/andymai/plancktons/actions/workflows/ci.yml/badge.svg)](https://github.com/andymai/plancktons/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/github/license/andymai/plancktons)](./LICENSE)\n\nInteractive 3D study of Hill T₁ orthoschemes and their random face-to-face assemblies.\n\n[Live](https://andymai.github.io/plancktons/) · [Theory](./THEORY.md) · [Proof](./docs/PROOF.md)\n\n\u003c/div\u003e\n\nBrowser playground plus a headless CLI for batch runs.\n\n**Deep dive:** [THEORY.md](./THEORY.md) — Schläfli orthoschemes, Hilbert's\nthird problem, Matoušek-Safernová's m³-reptile theorem, jamming, gyration-\ntensor descriptors, fractal dimension, pair correlation, and where Plancktons\nsit relative to sphere FCC, regular-tet packing, and random close packing in\nthe literature.\n\n**Proof of zero overlap:** [docs/PROOF.md](./docs/PROOF.md) — separating-\naxis test correctness + numerical margin analysis.\n\n## What's a Planckton?\n\nThe Hill orthoscheme T₁ (Hill 1896): the right tetrahedron with vertices\n\n```\nV₀ = (0, 0, 0)   V₁ = (L, 0, 0)   V₂ = (L, L, 0)   V₃ = (L, L, L)\n```\n\nVolume `L³ / 6`. Six edges of three distinct lengths `(L, L√2, L√3)`. Four\nright-triangle faces:\n\n- `(L, L, L√2)` isoceles right (×2)\n- `(L, L√2, L√3)` scalene right (×2)\n\nAll 6 dihedral angles are rational multiples of π - i.e. the Dehn invariant\nis zero - which is exactly the condition that makes T₁ scissors-congruent to\na cube. So 6 Plancktons tile a cube, 8 tile a doubled Planckton (the m³\nreptile), 64 tile it recursively, etc. By Matoušek-Safernová (2010) this is\nthe **only** k-reptile family for tetrahedra (k = m³).\n\nThe chiral mirror is its other handedness (red = right-handed, white =\nleft-handed in the default color scheme).\n\n## Scenes\n\n1. **Single Planckton inspector** - chiral pair side by side, toggle\n   handedness, dihedral angles in rational π form.\n2. **Cube triptych** - three 6-piece dissections side by side: the classical\n   geometric (3R+3L) main-diagonal cube and the two HT-realizable mirrors\n   (4R+2L, 2R+4L) buildable from one Matoušek decomposition. Synchronized\n   explode slider. η = 1 each.\n3. **8-reptile dissection** - eight unit Plancktons tile a doubled\n   Planckton; recurse to 64 sub-Plancktons. η = 1 at every depth.\n4. **Random face-to-face growth** - face-restricted cluster aggregation\n   (Eden-like growth on the face graph) with SAT overlap rejection. Live\n   readout of two distinct η values, gyration descriptors, free-face shape\n   counts, vertex / tet coordination, bbox.\n5. **Vacuum-bag compaction** - N loose, freely-oriented Plancktons squeezed\n   into a jammed random packing by a contracting \"bag\" (a deterministic,\n   frictionless 6-DOF rigid-body settle seeded by the same LCG, so the same\n   seed reproduces the same packing). Press **Pack it** to run the settle off\n   the main thread, then scrub the \"% air removed\" timeline to replay the air\n   being drawn out. The wrinkled vacuum-seal skin is the morphological hull of\n   the sealed pack; η (η*C/η_B/η_M/η_V), R_g, and a contact-coordination\n   number are computed on the final jammed frame. Unlike growth, tets here are\n   \\_not* face-mated — they only touch where the physics pushes them together,\n   so this is a genuinely different (looser, frictionless) kind of packing.\n\n## The two η values\n\nThe HUD reports **both**:\n\n| Metric  | Formula     | Meaning                                                                                                                                                                      |\n| ------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **η_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. |\n| **η_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.                                   |\n\nV★ = N · L³/6 (exact sum of part volumes; face-to-face mating never overlaps).\n\n## Two growth strategies\n\n- **Uniform** - pick any free face with equal probability.\n- **Compact** - Boltzmann weight `p(face) ∝ exp(β · n̂ · ĉ)` biases toward\n  concave pockets (n̂ = outward face normal, ĉ = direction to assembly\n  centroid). Slider over β: 0 recovers uniform, β ≈ 3 is the default sweet\n  spot, β → ∞ is greedy.\n\nChirality bias slider `c_R ∈ [0, 1]` controls the per-attempt probability of\ndrawing a right-handed template. The resulting R:L ratio in the assembly\ndepends on which chiralities geometrically fit, not purely on the bias.\n\nBoth strategies use a two-phase placement:\n\n1. **Phase 1** - random sampling, ≤ 80 attempts.\n2. **Phase 2** - deterministic exhaustive search over every (free face ×\n   chirality × template face × perm) before declaring \"jammed\". If any valid\n   placement exists, it is found.\n\n## Disclosure modes\n\nA three-position switch in the topbar (**Learn / Explore / Research**) controls how much UI is exposed:\n\n- **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.\n- **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).\n- **Research** — adds histograms, η-vs-N sweeps, pair correlation, kinetics, autocorrelation, MC refinement, and the morphological / Voronoi η variants. Reference packing densities overlay onto the plots.\n\nPress `?` 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`).\n\n## Research mode features\n\n- **Trial histogram** at fixed N - distribution of η_C, A/B overlay, mean ±\n  SEM, CSV export with build provenance.\n- **η vs N curve** - error band defaults to SEM (toggle to ±σ for trial\n  spread). Choose **η_C** or **η_B** on the y axis. Fits three candidate\n  models simultaneously:\n  - `1 − η ∝ N^α` (pure power law) - reports `α ± Δα`\n  - `1 − η = y∞ + B·N^(−β)` (asymptote + power correction)\n  - `1 − η = y∞ + B·exp(−N/N₀)` (exponential approach)\n  - Model selection by AIC; ΔAIC \u003e 2 is meaningful.\n- **Fractal dimension D_f** - fit from R_g ∼ N^(1/D_f). D_f → 3 for compact\n  3D growth; lower values indicate fractal / surface-dominated aggregation.\n- **Pair correlation g(r)** - averaged over an ensemble of seeds. Random\n  uniform → 1; crystalline order → sharp peaks; amorphous → broad peaks\n  decaying to 1.\n- **Reference packing densities** table with full citations (Hales / Kepler\n  conjecture, Conway-Torquato, Hoylman, Scott-Kilgour, Onoda-Liniger).\n\n## Detailed HUD (growth scene)\n\n| Section              | Quantities                                                                                                        |\n| -------------------- | ----------------------------------------------------------------------------------------------------------------- |\n| Bulk                 | N (with stalled marker), V★, V_hull, **η_C**, **η_B**, free surface                                               |\n| Gyration / shape     | R_g, asphericity b, acylindricity c, anisotropy κ², prolateness S                                                 |\n| Topology / chirality | R / L counts, free-face fraction, ⟨z⟩ tet-tet coordination, ⟨coord⟩ / max vertex coordination, free iso / scalene |\n| Bounding box         | V_bbox, dims                                                                                                      |\n\nToggle the **gyration ellipsoid** overlay to see the principal axes of the\ngyration tensor. NB: this is NOT the inertia ellipsoid - the inertia tensor\n`I_ij = ⟨r²⟩δ_ij − ⟨rᵢrⱼ⟩` has different (orthogonal) principal directions.\n\n## CLI - `scripts/study.ts`\n\nFor real ensemble averages, fit-grade statistics, and offline pipelines:\n\n```bash\n# 500 trials at N=50, compact β=4 → CSV\nnpm run study -- --N 50 --trials 500 --strategy compact --beta 4 \\\n    --out compact_b4.csv\n\n# Sweep N at constant trials → one CSV\nnpm run study -- --sweep-N 10,20,30,50,80,120 --trials 200 \\\n    --strategy uniform --out uniform_sweep.csv\n\n# JSON Lines, for streaming into a notebook\nnpm run study -- --N 30 --trials 1000 --format jsonl --out trials.jsonl\n\n# Parallel: fan trials out across N node:worker_threads. 'auto' picks\n# max(1, min(8, cpus()-1)). Output is bit-identical to single-worker.\nnpm run study -- --N 50 --trials 500 --workers auto --out compact_par.csv\n```\n\nCSV columns:\n\n```\ntrial, N, seed, V, Vbbox, Vstar, efficiency, bboxEfficiency, surface,\nrg, kappaSq, prolateness, meanCoord, maxCoord, meanTetCoord, chirR, ms\n```\n\n(efficiency = η_C, bboxEfficiency = η_B, meanTetCoord = ⟨z⟩.)\n\nEvery CSV is prefixed with a `#`-commented provenance block:\n\n```\n# plancktons export\n# algorithm_version=2\n# commit=\u003cshort-sha\u003e\n# build_time=\u003ciso\u003e\n# export_time=\u003ciso\u003e\n# n_trials=200\n# startSeed=1\n# chiralityBias=0.5\n# strategy=compact\n# compactBeta=3\n```\n\nso re-runs months later can identify the exact code that produced the data.\nJSON exports (`exportAssemblyJSON`) carry the same provenance object.\n\nThe CLI uses the same kernel as the browser, so results are bit-identical\nand `seed_t = startSeed + t·9973` is fully reproducible.\n\n## Export and share\n\n- **Share link** - encodes scene/seed/N/strategy/β/chirality in the URL hash.\n- **PNG** - canvas screenshot.\n- **STL** - watertight STL of the current assembly.\n- **JSON** - full state dump with provenance.\n\n## Scope\n\nTo set expectations, this project deliberately does not:\n\n- **Simulate general tetrahedral shapes** — only the Hill T₁ orthoscheme (and its chiral mirror) is modeled; no other tetrahedra, polyhedra, or particle types are supported.\n- **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.\n- **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.)\n- **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.\n- **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.\n\n## Local development\n\n```bash\nnpm install\nnpm run dev          # http://localhost:5173\nnpm run build        # production bundle in dist/\nnpm run preview      # serve the bundle locally\n\nnpm run validate     # typecheck + lint + format:check + test\nnpm run test         # vitest\nnpm run test:coverage\n```\n\nPre-commit hook (husky) runs `validate` automatically.\n\n## Source layout\n\n```\nsrc/\n  lib/                  Pure math (no React, no THREE imports allowed)\n    Geometry kernel:    planckton, assembly, hull, mesh, canonicalScenes,\n                        spatialHash, vertexHash, kdtree, validate\n    Strategies \u0026 RNG:   rng, vec, constants\n    Statistics:         study, studyClient, workerPool, scaling, shape,\n                        paircorr, autocorr, kinetics, steinhardt,\n                        embeddedCubes, mcRefine, morphology, voronoi\n    I/O:                exports, svgExport, provenance, references, store\n  scenes/               R3F components (read lib, never imported by lib)\n    SceneCanvas, SingleScene, CubeScene, ReptileScene, GrowthScene,\n    PlancktonMesh, HullMesh, GyrationEllipsoid, DihedralLabels, CameraFit\n  ui/                   React UI (reads lib + scenes, never imported by lib)\n    Chrome:             Controls, HUD, Actions, ModeSwitch, MetricsPanel,\n                        ProgressBar, Transport, HelpOverlay, Term, glossary,\n                        FirstVisitToast, icons, SvgPlot\n    Layout:             ResizableSidebar, ResizablePane, ErrorBoundary\n    State \u0026 hooks:      uiStore, useDraftValue, useKeyboard, useRadioGroup,\n                        useWorkerRun, DraftSlider\n    controls/           Per-scene control panels (Single, Cube, Reptile,\n                        Growth, Display, Analyses)\n    research/           Research-mode panels (Histogram, Curve, Kinetics,\n                        Autocorr, PairCorrelation, Steinhardt, References)\n  worker/\n    study.worker.ts     Browser Web Worker entry (uses lib only)\nscripts/\n  study.ts              Headless batch CLI (npm run study)\n  _studyWorker.ts       node:worker_threads worker used by --workers\n  brepjsOverlap.ts      Independent OpenCascade overlap oracle (devDep)\n  preliminary-analyze.ts, preliminary-q4.ts    Offline analysis helpers\ntests/                  Vitest suites\ndocs/\n  PROOF.md              SAT overlap-test correctness proof\ndata/preliminary/       CSVs backing THEORY.md §4.5\n```\n\n## Known gaps\n\n- **No two-level Ns × trials fan-out for curve sweeps.** The browser pool\n  partitions Ns across workers; if Ns is shorter than the pool size, some\n  cores idle. A two-level partition would help short-Ns / many-trials\n  sweeps but adds CurvePoint-merge complexity. The CLI sidesteps this by\n  fanning trials within a single N across `node:worker_threads` (see\n  `scripts/study.ts --workers`).\n\n## References\n\nThe full bibliographic list is in [THEORY.md §5-§6](./THEORY.md). Key entries:\n\n- M. J. M. Hill, _Determination of the volumes of certain species of\n  tetrahedra without employment of the method of limits_, Proc. Lond. Math.\n  Soc. 2:39 (1896).\n- J. Matoušek \u0026 Z. Safernová, _On the nonexistence of k-reptile tetrahedra_,\n  [arXiv:1006.1807](https://arxiv.org/abs/1006.1807) (2010).\n- E. R. Chen, M. Engel \u0026 S. C. Glotzer, _Dense crystalline dimer packings of\n  regular tetrahedra_, Discrete Comput. Geom. 44:253 (2010),\n  [doi:10.1007/s00454-010-9273-0](https://doi.org/10.1007/s00454-010-9273-0).\n- D. N. Theodorou \u0026 U. W. Suter, _Shape of unperturbed linear polymers:\n  polypropylene_, Macromolecules 18:1206 (1985) - gyration descriptors.\n- J. Rudnick \u0026 G. Gaspari, _The asphericity of random walks_, J. Phys. A\n  19:L191 (1986) - κ² normalization.\n\n## License\n\nMIT - see [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandymai%2Fplancktons","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandymai%2Fplancktons","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandymai%2Fplancktons/lists"}