# One-Shot Prompt

**Simulation**: Paper / Receipt
**Theme**: Default (Clean Minimal) — studio lighting, off-white matte material
**Name**: Tender
**Generated**: 2026-04-25

## Prompt

Generate a single-file interactive HTML page at `/physics` simulating receipt paper physics. Use Three.js (via CDN importmap) with custom Verlet integration — no physics engine. The simulation must render a portrait-oriented sheet of receipt paper (32 columns × 48 rows of particles, spacing 0.18 units) pinned at three points along the top edge (left, centre, right). Use position-based Verlet integration at a fixed 120 Hz timestep with 8 substeps per tick and a maximum frame dt of 33 ms. Apply gravity in the -Y direction with a damping factor of 0.99 per substep.

Connect particles with distance constraints: structural (horizontal and vertical at spacing 0.18), shear (diagonal at spacing × √2), and bend (skip-one at spacing × 2). Run 4 constraint-iteration passes per substep. Tear constraints when they stretch beyond 2.5× their rest length (structural and bend constraints only; shear constraints should not tear to preserve mesh integrity during folding). Remove torn constraints from the array so the paper visibly splits.

Implement self-collision via a spatial hash grid with cell size 0.45 units. For each particle, check the 27-cell neighbourhood and apply isotropic repulsion to non-adjacent particles closer than 1.2× spacing. Build the adjacency set from constraint indices at initialisation so connected particles are never repelled from each other.

Render the paper as a deforming `THREE.Mesh` with `MeshStandardMaterial` (double-sided, roughness 0.7, metalness 0.0). Map a 512×768 canvas-generated receipt texture onto the mesh UVs. The receipt texture must show a white/off‑white paper background with a diner receipt: header "PHYSICS DINER", address, a dashed divider, nine menu items with prices, a total line, thank-you message, and a faux barcode at the bottom. Everything rendered in monospace font in dark gray/black. Update the mesh position buffer and call `computeVertexNormals()` every frame for smooth shading.

Scene setup: PerspectiveCamera (50° FOV) positioned at (6, 4, 10) looking at (0, 1, 0). DirectionalLight from upper-right with shadow map (2048×2048). AmbientLight at intensity 0.6. Ground plane (5×5 grid, semi-transparent, receiving shadows). Background: linear gradient from #e8e4e0 to #d8d4d0 via CSS.

Interaction — pointer events on the renderer domElement:
- Left-click or touch drag: grab the nearest particle within a 0.6‑unit radius of the raycast intersection, project it onto a camera-facing plane through the grab point, and move it in 3D. The grabbed particle's current and previous positions both follow the cursor so it has zero velocity when released.
- Right-click drag: orbit the camera (update spherical coordinates theta and phi, clamp phi to [0.1, π−0.1]).
- Scroll wheel: zoom in/out by adjusting camera distance within [3, 30].
- Touch: single finger = grab, two fingers = orbit and pinch‑zoom via `touchmove` distance delta.
- On release: paper responds naturally with momentum.

HUD overlay (positioned absolutely over the canvas):
- Title "Tender" in the top-left corner (font 20px system‑ui semibold, color #444).
- Instruction text "Click and drag to interact · Right-drag to orbit" centred at bottom, fading out after 4 seconds.
- Controls hint at bottom-left: "R to Reset · W to toggle Wind · I to toggle FPS".
- FPS counter (top-right, hidden by default, toggled with I key).
- Keyboard: R resets all particles to initial positions (animating over 30 frames), W toggles wind on/off, Space pauses/unpauses physics.
- Window resize listener: update camera aspect ratio and renderer size, reposition HUD.

Wind: sinusoidal superposition (1.3 Hz + 2.7 Hz in X, 0.7 Hz in Y, 1.1 Hz + 3.1 Hz in Z) modulated by a default strength multiplier of 1.0. A subtle breeze is on by default.

Mobile: detect via `navigator.maxTouchPoints > 0` or `window.innerWidth < 768`. If mobile, reduce particle grid to 24×36 (from 32×48) for stable 60 fps. Apply `touch-action: none` on the canvas element to prevent scroll interference. Responsive canvas fills the viewport.

Favicon: inline SVG showing a simplified paper-sheet icon with a fold corner, encoded as a data URI.

Meta tags: description, og:title, og:description, og:type, twitter:card, twitter:title, twitter:description all set for sharing. Page `<title>`: "Tender — Receipt Paper Physics".

Page background uses CSS linear-gradient from #e8e4e0 to #d8d4d0 applied to the `<body>` behind the canvas. The ground plane is a `THREE.Mesh` with a `PlaneGeometry` (10×10), rotated -90° on X, positioned at y = -6, with a `MeshStandardMaterial` (color #d0ccc8, transparent, opacity 0.5, side: DoubleSide).

On initial load, show "Initialising…" text centred for a brief moment, then fade it out once the simulation starts. When paused, show "PAUSED" text centred with 50% opacity overlay. On reset, animate particles back to their initial positions over 30 frames using linear interpolation.

Every line of code must be written — no truncation, no placeholder comments, no ellipses. The complete simulation must fit in a single self‑contained HTML file.

## Notes

- **Physics approach**: Verlet integration chosen for its simplicity, stability with constraints, and natural damping. Position-based dynamics avoid velocity storage and make constraint satisfaction trivial.
- **Performance**: 1536 particles on desktop, 864 on mobile. Spatial hashing keeps self-collision O(n) instead of O(n²). Fixed timestep with accumulator prevents explosion after tab-switch.
- **Tearing**: Structural and bend constraints break at 2.5× rest length, creating realistic paper tearing. Shear constraints preserved to maintain mesh coherence during folding.
- **Texture**: Full canvas-generated receipt with diner theme. UV coordinates map the full texture to the deforming mesh.
- **Self-collision**: Spatial grid with adjacency-set filtering prevents connected-particle repulsion while folding paper over itself.
- **Hosting**: CodePen / Vercel / Cloudflare Pages / local HTTP server.
