Squish

Springs you can feel.

Fig. 1 — Squish, live captureOpen the live demo ↗10 s loop · recorded frame by frame on GPU

Field notes

A spring easing tool with a 3D jelly you can poke. Pick a preset or drag stiffness and damping, press the jelly to feel the spring, then copy it as a CSS linear() easing. The squash and wobble run in a vertex shader. No models, no textures.

  • 3D
  • WebGL shader
  • Pointer interaction
  • Developer tool
  • Light theme

Squish is a one-page tool for designing spring motion. Four presets (Wobbly, Bouncy, Snappy, Gentle) and two sliders set the spring, and a translucent jelly with a cherry on top shows how it feels: press it and it squashes, let go and it springs back, wobbling as much as the damping allows. A dark code card draws the curve, rides a playhead along it after every poke and hands you the CSS, ready to paste.

The export is a plain CSS linear() easing sampled from the same closed-form spring that drives the jelly, so what you feel is what ships. It works in current Chrome, Firefox and Safari with no animation library. Until someone touches it, the page runs its own 10-second demo, gliding through the presets and flavors; anyone who prefers reduced motion gets a still jelly that only moves when they poke it.

How it's built

  • One spring, three uses: a closed-form damped oscillator (under-, critically and over-damped) moves the jelly, draws the curve and samples the CSS linear() stops, so the export matches what you felt exactly.
  • Squash in the vertex shader: onBeforeCompile on a MeshPhysicalMaterial scales height down, bulges the waist to keep the volume, and leans the top on a second, looser spring. Normals get the inverse scale so the highlights follow the new shape.
  • A jelly from a lathe: one profile of three soft tiers and a dome, turned into a LatheGeometry. Transmission, clearcoat and an attenuation colour make it read as gelatin against a polka-dot cloth it can refract.
  • No seam between canvas and page: the tablecloth is unlit and not tone mapped, so its fog fades into exactly the HTML's cream, while NeutralToneMapping keeps the candy colours bright on everything lit.

Inside the prompt

Every file below is written out in full, so your agent creates the project exactly — no guessing, no missing pieces.

squish-springs/
├─ .gitignore
├─ index.html
├─ package.json
├─ tsconfig.json
├─ vite.config.ts
└─ src/
   ├─ App.tsx
   ├─ index.css
   ├─ main.tsx
   ├─ vite-env.d.ts
   ├─ components/
   │  ├─ CodeCard.tsx
   │  ├─ Jelly.tsx
   │  ├─ Panel.tsx
   │  └─ Scene.tsx
   └─ lib/
      ├─ loop.ts
      ├─ spring.ts
      └─ store.ts

Recut it

  • Rename the tool and rewrite the pitchsrc/components/Panel.tsx → Intro()
  • Add or retune the spring presetssrc/lib/store.ts → PRESETS
  • Swap the flavors (jelly and accent colours)src/lib/store.ts → FLAVORS
  • Change what the exported CSS animatessrc/components/CodeCard.tsx → cssFor()
  • Reshape the jelly mouldsrc/components/Jelly.tsx → mouldProfile()
  • Make it squash harder or softersrc/components/Jelly.tsx → SQUASH
  • Retime the demo loopsrc/lib/store.ts → scripted()