https://github.com/flyingrobots/html-to-cloth
Let's turn HTML DOM elements into physics cloth, for fun.
https://github.com/flyingrobots/html-to-cloth
browser-art cloth-simulation delight experimental fun game-engine html2image interactive-visualizations not-supposed-to-do-that performance-art physics skeuomorphism webgl2
Last synced: about 1 month ago
JSON representation
Let's turn HTML DOM elements into physics cloth, for fun.
- Host: GitHub
- URL: https://github.com/flyingrobots/html-to-cloth
- Owner: flyingrobots
- Created: 2025-10-11T06:47:44.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-11-28T07:32:10.000Z (7 months ago)
- Last Synced: 2025-12-25T23:42:58.388Z (6 months ago)
- Topics: browser-art, cloth-simulation, delight, experimental, fun, game-engine, html2image, interactive-visualizations, not-supposed-to-do-that, performance-art, physics, skeuomorphism, webgl2
- Language: TypeScript
- Homepage:
- Size: 1.9 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- Roadmap: ROADMAP.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# HTML-to-cloth

A portfolio playground that hides a WebGL cloth simulation beneath an accessible DOM layout. Clicking any `.cloth-enabled` element swaps it for a textured mesh, lets the fabric react to pointer gusts, and eventually returns the DOM element when the cloth falls off screen. The codebase is deliberately modular so the experiment can be reused for future interactive sites.
## Architecture at a Glance
| Layer | Responsibilities | Source |
| ----- | ---------------- | ------ |
| UI / DOM | captures elements, handles pointer input, debug UI | `src/lib/clothSceneController.ts` + React components (Mantine) |
| Render | applies camera snapshot to DOMToWebGL and renders each frame | `src/engine/render/worldRendererSystem.ts`, `src/lib/domToWebGL.ts` |
| Camera | spring camera with read-only snapshots | `src/engine/camera/CameraSystem.ts`, `src/engine/camera/CameraSpring.ts` |
| Simulation | cloth physics, collision clamps, sleep/wake, scheduler | `src/lib/clothPhysics.ts`, `src/lib/simWorld.ts`, `src/lib/collisionSystem.ts` |
| Engine | fixed-step loop & system ordering | `src/engine/simulationRunner.ts`, `src/engine/world.ts` |
| Entity | lightweight ECS tracking cloth body adapters | `src/engine/entity/` |
Long-form docs live in:
- [`docs/architecture.md`](docs/architecture.md) – layer overview, DI strategy, extension tips.
- [`docs/components.md`](docs/components.md) – Mermaid component diagram.
- [`docs/data-flow.md`](docs/data-flow.md) – step-by-step activation/update/offscreen flows.
- Generated API docs (`npm run docs:api`) end up in `docs/api/`.
## Getting Started
```bash
npm install
npm run dev # start the Vite dev server
npm run build # type-check + production bundle
npm test # run Vitest suites
npm run docs:api # generate Markdown API reference via TypeDoc
```
Key entry points:
- `src/App.tsx` – React shell + debug drawer wiring (Mantine components, zero custom CSS).
- `src/lib/clothSceneController.ts` – DOM orchestration + simulation delegation (rendering handled by a system).
- `src/engine/render/worldRendererSystem.ts` – applies the camera snapshot and calls DOMToWebGL render.
- `src/engine/camera/CameraSystem.ts` – spring-based camera that exposes read-only snapshots.
- `src/engine/simulationRunner.ts` – deterministic fixed-step loop.
- `src/lib/clothPhysics.ts` – cloth solver plus impulse helpers.
## Testing
- Unit suites cover cloth physics, impulse helpers, simulation scheduler, SimWorld, entity lifecycle, and the simulation runner.
- Integration suite (`src/lib/__tests__/domIntegration.test.ts`) verifies DOM capture, activation lifecycle, pointer wakeups, offscreen recycling, and debug controls.
- App UI tests (`src/app/__tests__/debugActions.test.tsx`) assert that the debug palette routes actions into the engine (real-time, substeps, camera zoom, gravity, iterations).
- Render-while-paused integration (`src/engine/render/__tests__/pausedRenderIntegration.test.ts`) verifies the render system still runs during `engine.frame(dt)` when real-time is disabled.
## UI Library
The app uses Mantine (no Tailwind, no shadcn/ui). We avoid custom CSS entirely and compose the debug UI purely from Mantine components and props. Global styles come from `@mantine/core/styles.css` imported in `src/main.tsx`.
## Debug Presets
For quick demos, the debug palette includes presets that apply multiple settings at once:
- Floaty – gravity 6.0, 3 iterations, looser sleep (0.0005, 80f), 1.2× zoom, warm-start 2 passes
- Crisp – gravity 9.81, 6 iterations, default sleep (0.001, 60f), 1.0× zoom, warm-start 3 passes
- Heavy – gravity 14.0, 8 iterations, tighter sleep (0.002, 40f), 0.9× zoom, warm-start 1 pass
- Manual QA scenarios are listed in [`TEST_PLAN.md`](TEST_PLAN.md); progress is tracked in [`PROGRESS_CHECKLIST.md`](PROGRESS_CHECKLIST.md).
## Workflow
We follow the cycle described in [`AGENTS.md`](AGENTS.md): branch-per-task, write failing specs first, implement, document, log the session, open a PR. Notes and experiments are appended to [`BLOG_NOTES.md`](BLOG_NOTES.md).
Debug actions entry point: create `EngineActions` with `runner`, `world`, `camera`, and `simulation` from the controller. The UI never reaches into simulation internals directly.
## Roadmap
- Camera/render systems that consume simulation snapshots instead of hand-rolling controller logic.
- Continuous collision for sweeping pointer helpers.
- Expanded component library (e.g., cloth analytics, audio emitters) via the entity layer.
- Portable presets for gravity, pinning, and impulse tuning.
Contributions, experiments, and wild ideas are welcome—this repository is a sandbox on purpose.