In On What There Is, W. V. O. Quine argues that ontology is not a matter of discovering pre-given entities, but of what our language commits us to treating as objects.
This particle-based artwork translates this claim into a field where, under the pressure of the Special Composition Question, all forms remain fundamentally indeterminate, as particles drift without stable boundaries or privileged composition. In this default state, “objects” are only provisional fluctuations in density, not resolved entities. Linguistic activation (clicking the sentences) reorganizes the field, allowing particles to momentarily cohere into tables or even Santa Claus, thereby enacting existence as a function of conceptual commitment rather than metaphysical fact. In this way, SCQ dissolves not through resolution, but through the act of speaking within a system that decides what may count as a thing.
the-page/ # Static site — this directory is what ships
├── index.html # Canvas + clickable text overlay
├── styles.css # Responsive type & cursor glyph
├── particles.json # Baked particle data (committed; regenerated by the Python script)
└── src/
├── main.js # RAF loop, click wiring, dt-aware tick
├── particles.js # Typed-array pool, per-group emphasis, Brownian wander render
└── tuning.js # All visual constants live here
particle_generation/ # Offline particle baking (Python)
├── References/ # Pre-segmented source layers (background.png, table.png, Santa.png)
├── extract_particles.py # Reads References/, writes the-page/particles.json
└── pyproject.toml # Managed with uv
.github/workflows/deploy.yml # GitHub Pages deploy from the-page/ on push to main
Drop replacement PNGs into particle_generation/References/. All three layers must share the same dimensions (the script enforces this). The GROUPS constant at the top of extract_particles.py controls per-layer particle counts — bump them if a layer needs more density headroom for emphasis.
cd particle_generation
uv run python extract_particles.pyWrites the-page/particles.json. The CLI accepts --gamma, --threshold, --seed, --input, and --output if you want non-default behavior.
All knobs live in the-page/src/tuning.js: wander amplitude/speeds, per-group baseline/invoked brightness & density, emphasis lerp rate, DPR cap. Edit and refresh — no build step.
cd the-page
python3 -m http.server 8765
# open http://127.0.0.1:8765ES modules require an HTTP origin, so file:// won't work.
Pushing to main (or manually) triggers the deployment workflow, which uploads the the-page/ directory as a Pages artifact and publishes it. The site has no build step — the workflow just ships static files.