Squishy Butter
Press and hold a stick of butter and watch it sink. Real soft-body physics in your browser - no install required. 160+ collectible skins, each with its own feel, sound and certificate of authenticity.
The Idea
It started with a gift. Someone handed me a squishy butter toy and I immediately understood why people were obsessed with them.
At the time, physical squishies were everywhere - selling out at fairs, people queueing for restocks, the kind of low-cost object that somehow generates outsized enthusiasm. The product hypothesis was simple: if people were this excited about a foam rectangle that does nothing, a digital version with real physics, a collection mechanic, and something to show for it could work. I shipped fast and bet that the demand for the physical thing would translate.
The squish counter wasn't an afterthought - it was intentional. Knowing you've squeezed something 12,000 times makes it yours in a way a purchase receipt never does. The number makes the butter personal.
Almost every squishy thing on the web is a scale animation. The object shrinks toward its middle and springs back - and it feels like rubber, because a spring is what rubber does. I wanted the other sensation: a fingertip actually sinking into something soft. That's a materials problem, not an animation problem - it needed a real deformation model running on the graphics card.
The Landing Page
The full product page - collection, mechanics, rarity tiers, and the order flow.
Mobile Experience
The landing page is fully responsive - the collection, rarity tiers, and order flow all work on a phone with no install required.
Live - scroll to explore
Why It Feels Right
Four decisions do most of the work, and each one is something you notice in the first three seconds without being able to name it.
- Jab it and it resists. Lean on it and it gives. Resistance rises with the square of how fast you're pressing, which is the property that actually separates memory foam from rubber. Even damping feels the same at every speed - this doesn't.
- Hold it and it keeps giving. The target depth drifts lower the longer your finger stays down, so the butter never hits a wall and stops. It's why holding is worth doing and tapping isn't.
- Let go and the dent stays. It sits there for a couple of seconds doing nothing, then eases back - and it never bounces. A spring would overshoot, and overshoot is exactly what reads as jelly. Deeper presses take longer to recover, because there's more to undo.
- Press in several places at once. Every dent is its own little simulation, so you can poke here, poke there, and watch both fade on their own schedule.
160+ Skins, Zero Image Files
Every skin is also a bundled iMessage sticker — hover to pause the lineup.
Marble veining, zebra stripes that taper and fork the way real ones do, cheetah rosettes, wood grain, tie-dye, denim, camo, gold foil - the texture skins. Then sports: baseball stitching, football pigskin, basketball dimples, soccer panels. Seasonal runs: Detroit city flag, Mother's Day, Valentine's Day, Birthday. And a handful that are just their own thing: Frozen, Fortune Cookie, Fur. Every one is drawn at runtime in code - there isn't a single image file in the project.
Which means the download stays tiny no matter how big the catalogue gets, and adding a skin is writing a function instead of running an art pipeline. That's the only reason a 160-skin catalogue was practical for one person.
Skins aren't just colours, either. Each has its own physics - Frozen barely yields until you warm it up with your finger, and it warms where you touch it, so one end can soften while the rest stays solid. Each has its own sound, generated live and fed the dent's depth and speed every frame so it tracks what your hand is doing. And each has a rarity, a supply cap, a serial number, a written provenance story, a certificate and a trading card.
A Few Things Under the Hood
- Fur is 16 stacked layers, not a texture. Printed fur reads as fabric with a picture of fur on it. Real depth means drawing the mesh repeatedly, each copy pushed a little further out, with only the strand pixels surviving. Every layer runs the squish shader too, or the coat would stay stiff while the butter dented underneath it.
- Gold reflects the actual room. Metal looks like metal because it mirrors its surroundings. Paint the highlights into a texture instead and you get yellow plastic wearing a picture of gold.
- Limited runs are enforced in the database, not the app. Two people buying the last copy at the same instant must not both get serial #100 - so minting locks the row, checks supply, assigns the serial and issues the certificate hash inside a single transaction.
Technical Implementation
Soft-Body Physics Shader
Deformation runs entirely on the GPU in a GLSL vertex shader. Each dent is a struct holding a position, depth, velocity, and age. Every frame the shader reads those values, calculates a displacement for each vertex based on a smooth falloff curve from the dent center, and writes the deformed position. Velocity and depth evolve on the CPU each frame and are uploaded as a uniform array - the GPU only does the geometry math, which is the part that needs to be fast.
Resistance rises with the square of press speed, which is what separates memory foam from rubber at the physics level. Recovery uses an exponential ease rather than a spring, so there's no overshoot - overshoot is exactly what reads as jelly.
Device Budget Detection
The number of simultaneous dents is compiled into the shader as a constant. Ask for too many and the shader silently fails to compile on lower-end hardware, which renders as nothing at all - not a loading error, just a blank canvas. Before compiling, the engine queries gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS), uses 45% of the reported budget split across the dent structs, and clamps between 6 and 48. One build, no device detection, no separate mobile path.
The shader asks the device what it can afford before deciding how much to use.
Procedural Skin System
Every skin - marble veining, zebra stripes, cheetah rosettes, wood grain, tie-dye, denim, camo, gold foil - is drawn at runtime in GLSL. There are no image files in the project. Each skin is a function that takes a UV coordinate and returns a color, which means the catalogue can grow indefinitely without affecting download size. Adding a skin is writing a function, not running an art pipeline.
Some skins have physics properties: Frozen raises the stiffness coefficient and tracks warmth per-region so one end of the butter can soften while the other stays solid. The warmth map is a per-dent accumulator updated each frame your finger stays in contact.
Fur Rendering
Fur is rendered using shell texturing - the mesh is drawn 16 times, each pass offset slightly outward along the surface normals. A noise function masks each layer so only strand-shaped pixels survive. Every pass runs through the same squish shader, so the coat deforms with the butter rather than floating above it. Without that, the fur would stay rigid while the body dented - immediately breaking the illusion.
Live Audio
Sound is generated in the Web Audio API each frame, not sampled from a file. Dent depth and press velocity are fed as parameters to an oscillator chain each frame, so the sound tracks what your hand is actually doing - pressing harder produces a lower, more compressed tone; a fast jab produces a sharper transient. Each skin has its own audio profile layered on top of the base model.
Auth Flow
Sign in with Apple and Sign in with Google both use PKCE flows handled by Supabase Auth. The third option is a six-digit OTP sent by email - not a magic link, because a tapped link opens a new browser tab, which breaks the in-page flow and depends on the right email client being set as default on iOS. A code the user types stays in the same tab with no external dependencies.
Minting Transaction
Supply caps are enforced at the database level, not the application level. When a pull resolves to a Limited or rarer skin, a Supabase database function runs inside a single transaction: it locks the relevant row, reads current supply, checks against the cap, increments the counter, assigns the serial number, generates the certificate hash, and commits - all before releasing. Two simultaneous purchases of the last copy cannot both succeed; one gets the serial, the other gets a pool miss and re-draws.
Auth
Sign in with Apple, Sign in with Google, or a six-digit email code - no password to forget or rotate. The magic link pattern was ruled out early: a tapped link that opens a new browser tab breaks the flow, and the right email client on iOS isn't guaranteed to match the browser. A one-time code sidesteps both problems - the user stays in the same app, on the same page, and nothing depends on which client they open.
Once you're in, your profile tracks coins, squish count, and total time squished. You can set a username, pick your butter's color from 27 options, choose from 29 expressions, and claim a title - starting with Fresh Out the Fridge and unlocking through Squish Enthusiast, Butter Baron, and beyond as your squish count, time, and collection grow.
The Pull System
Gacha wasn't chosen arbitrarily. Blind bags and mystery boxes were already dominating physical toy retail - Stanley cups, Sonny Angels, Pop Mart figures - and the same mechanic was proven in mobile gaming. The insight was that nobody had applied it to a browser-based tactile toy. The format fit: a butter you discover through a pull feels different from one you just pick off a shelf, and the uncertainty of the draw is exactly what makes the squish worth something. The collectible market was telling you what worked; the job was to find the version of it that hadn't been built yet.
Skins aren't bought directly. You buy coins, then spend them on pulls - each pull draws from the full rarity pool with published odds. Common skins are plentiful; Epic and Legendary tiers are scarce by design, and supply caps are enforced at the database level. A pity counter guarantees you can't get locked out of the rarest tier forever: after a defined number of dry pulls, the next one is guaranteed to hit.
New accounts start with 300 coins - enough for a few pulls - so the collection is immediately interactive without a purchase required.
Each pull triggers an animated card reveal: the card flips, the rarity tier glows in, and the certificate details resolve. The animation is keyed to what you actually got, so a Legendary reveal doesn't look like a Common one.
The Collection
My Butters opens the Cold Store - a full-screen collection overlay with filter tabs by rarity (All / Common / Rare / Epic / Legendary) and a grid of every skin in the pool. Skins you own show as a full card with your butter's preview; skins you haven't pulled yet show as a ??? silhouette with the rarity visible. One owned skin surrounded by a wall of question marks communicates the whole gacha loop without a word of explanation.
Home Screen Widgets
Three widget sizes put your squish stats on the home screen without opening the app.
Apple Watch
The Watch app surfaces your squish count at a glance — no phone needed.
iMessage Stickers
Squishy Butter ships with a built-in iMessage sticker pack — every butter skin becomes a sticker you can drop into a conversation. The pack is bundled with the app so there's nothing extra to download.
Squishy Butter for Apple Vision Pro
Squishy Butter already runs on Vision Pro — the WebGL physics canvas renders in Safari's floating spatial window today. A Vision Pro–optimized version could fill a room-scale panel, replace touch with eye tracking and a pinch to squish, and lean into the spatial audio engine for layered ASMR sounds. No native port needed. The GPU physics is already there.
What Was Hard
Getting the feel right was mostly deleting things that were subtly wrong - a spring on release, a dent that never deepened, a drag that slid one divot around instead of leaving a trail. Each was defensible on its own; each made the butter feel like a different material.
The worst bug looked correct in the code. The spacing check measured the gap between the cursor and the active dent - except that dent eases toward the cursor every frame, so the distance never grew large enough to trigger. Below a certain speed, dragging left no trail at all. Simulating the loop outside the browser found it in one pass.
Where It Stands
The web product is live - 160+ procedurally generated skins, GPU physics, auth with Apple, Google, and email, a coin economy with rarity tiers, supply caps, pity guarantee, and animated card reveals.
The vault is open: Stripe payments on web, minting inside a single database transaction so two people can't buy the same last copy. iOS is live on the App Store. Android is live on Google Play — both apps add haptics synced to the deformation under your finger.
The coin economy is live but early - 30,813 squishes logged, 48 collecting. Too soon to draw conclusions on conversion. The question the next few months will answer is whether people who love the squish also spend on the collection, or whether those are two different audiences.
The whole product is a feeling. It either lands or it doesn't.
The brand has room to go physical too.
Lighthouse Scores
Both the marketing page and the app were audited against Google Lighthouse. The landing page hits perfect across the board. The app scores 92 on SEO — a known Lighthouse limitation with JavaScript-rendered canvas applications where the crawler can't inspect GPU-drawn content.
Landing Page — squishybutter.app/landing
App — squishybutter.app
*Canvas-rendered game — crawlers cannot inspect GPU-drawn content.
iOS
iPad
The app scales naturally to iPad — the butter gets more room to breathe and the wider canvas makes squishing feel even more tactile. Also available on Mac — download it from the App Store under iPhone & iPad Apps.
Android
Get it on Android
Squishy Butter is now live on Google Play: play.google.com/store/apps/details?id=com.squishybutter.app