← Prompts

Physics Playground

Read the current prompt
# Task: Build a 2D Soft-Body Physics Playground

Build an interactive 2D physics playground (vanilla JS, no external assets, no CDN, no libraries) based on **Verlet integration with constraint relaxation** — ropes, cloth, and soft bodies the user can grab, tear, and spawn. The top priority is **numerical stability** — a physics toy that explodes, jitters, or tunnels is a failed physics toy.

## Core Specification

**Engine (write it yourself — position-based dynamics, not a rigid-body library clone)**
- Verlet integration: `x' = x + (x - xPrev) * damping + a * dt²` with a **fixed timestep** accumulator (e.g. 60 Hz physics) decoupled from render rate
- Constraint solving via relaxation: distance constraints iterated N times per step (N configurable, ~3–8)
- Collision: points vs. static shapes (bounding walls/floor, a few static circles/boxes) with friction; simple point-vs-point collision optional
- Gravity toggle and strength slider; optional wind
- No `NaN` escapes: guard division-by-zero in constraint resolution (zero-length links, coincident points)

**Spawnable Objects (toolbar + click/drag to place)**
- **Rope:** click-drag to draw a hanging chain of N points pinned at the start
- **Cloth:** draggable rectangle of points with structural + shear constraints, pinned along the top edge (pin pattern selectable: both corners / full edge)
- **Soft body:** circle/blob or box of points with edge + internal brace constraints that holds shape but deforms on impact
- **Ball:** single point with radius that bounces
- Spawn several objects; they coexist and interact with static geometry

**Interaction**
- **Grab:** click near any point to grab it (nearest point within a radius); drag to move it, it follows the cursor with the constraint solver reacting live; release to throw with the drag velocity
- **Tear/cut:** right-drag (or hold a modifier) to slice through constraints — cloth rips along the cut line, ropes split
- **Pin/unpin:** click a point with a modifier to toggle a pin in place
- Pause/step controls (Space to pause, arrow to step one physics frame while paused), reset button, gravity and iterations sliders

**Rendering**
- Canvas 2D: constraints as lines, points as small dots (hidden by default for cloth — render cloth as a filled mesh or grid lines), soft bodies as filled polygons
- Optional stress visualization: color constraints by stretch ratio (green → red)
- FPS counter and physics-step time readout

## Visual Style
- Dark playground with vibrant materials (each object type a distinct hue), subtle floor/wall rendering
- Satisfying feel: slight motion blur trail optional, cursor grab highlight, tear effect
- Toolbar minimal and out of the way — the canvas is the app

## Technical Requirements
- Vanilla JS, Canvas 2D; all code organized with clear section comments
- Fixed-timestep accumulator with a maximum frame delta clamp (tab-switch must not explode the sim)
- Tunable constants block at the top (gravity, damping, iterations, timestep, tear radius, colors)
- Target: stable 60 FPS with ~1000 constraint points

## Quality Bar (must hit all)
- A pendulum rope swings smoothly and settles; cloth hangs from pins and drapes over a static circle without exploding or self-intersecting into chaos
- Leaving the tab for 30 seconds and returning does not detonate the simulation
- Grabbing and whipping a cloth corner produces a believable wave; releasing throws it
- Tearing a rope in the middle leaves two independently swinging halves
- No visible jitter on resting stacks; energy visibly decays (nothing oscillates forever)

## Self-Check Before Finishing
Verify with the browser tools (expose the sim on `window` — e.g. `sim.points`, `sim.step()` — so it can be probed headlessly):
- Drop a soft body from height with gravity on: after settling (~3s of stepped time), its total kinetic energy is near zero and no point is below the floor
- Step the sim 1000 frames and assert no coordinate is `NaN` or beyond a sane bound
- Pin two cloth corners, step 600 frames, assert the cloth's lowest point stays above the floor and the top pins haven't moved
- Tear a rope constraint via the exposed model, step, and assert the halves move independently