JellyTest

Play the demo

How to use

Turn the wheels until the jelly fits inside the gold outline. Learn it in four short levels; each one adds a wheel. These are real challenges, but here the dots show you where to go.

Drag a wheel sideways. Slowly for fine steps, quickly for big ones.
Scroll while hovering a wheel. Hold Shift for bigger steps; arrow keys work too.
Watch the bar next to the picture. When it passes the line, the jelly fits.

Technical explanation

The transformations

Each wheel bends space before the shape is evaluated. Here are the building blocks, rendered live on one fixed shape. In the formulas, y is a secret axis, a is how far the wheel is from its neutral point, and the shader applies the inverse map.

Non-linear: most of the wheels

How much these move a point depends on where the point is: a twist turns the ends more than the middle, and a bulge swells only the waist. No single matrix describes the result, so the picture changes in ways a solver can't summarise with a few numbers. That makes them harder to model, and it also makes the shape behave like jelly.

Linear: one or two wheels per challenge

These keep straight lines straight and move every point by the same rule: rotate, shift, shear, or stretch. A wheel's whole effect is then one small matrix. After a couple of pictures a solver can fit that matrix and predict every other position, for example by tracking the silhouette's centre and orientation. They are easy for people too, so each level has one as an anchor (two on Hard): Easy combines one linear and one non-linear wheel, Normal one and two, Hard two and two.

How wheels are wired

Every wheel runs from 0 to 1 and starts in the middle. It has two secret values: the solution, and a neutral point. Its distance from the neutral point drives one main transformation and up to two weaker ones. Neutral points are random, so the target is a random pose, not a plain shape.

Each transformation type appears at most once per challenge. Two twists, say, could cancel each other out, which is confusing to reason about.

Wheel 2 value − neutral point Main: twist secret axis, sign, strength Secondary: bend 15–20% of its strength applied to the shape

Combinations we rule out

Every axis, sign, and phase is random. But some transformations look so alike that, on a shared axis, one wheel could partly undo or imitate another. That makes the puzzle confusing rather than hard, so the server never builds these:

twist
+
twist

The same type twice

never twice

Two opposite twists cancel out. Each type is used at most once; rotation about x, y, or z counts as one type.

stretch
bulge
taper

Changing width

never on one axis

All three change how wide the slices are across the axis, so a bulge would read as a partial stretch.

shear
bend
wave

Sideways shift

never on one axis

All three push slices sideways depending on where they sit along the axis. Part of a bend looks like a shear.

twist
rotation

Twist and rotation

never together

Both turn slices around an axis. Combined, on any axis, they are too hard to tell apart.

Translation has no axis, so it combines with everything. The width and sideways groups have at most three members each, one per axis, so a valid choice always exists.

Every wheel must matter

When a challenge is created, the server turns each wheel ⅛ of its travel both ways from the solution and measures how much the silhouette changes. It scales the wheel's strength until that change lands in the sensitivity band (default 0.08–0.2). A transformation that can't get there, such as a twist of an almost round shape, is replaced. So no wheel is uselessly subtle or twitchy.

sensitivity band ⅛ of a sweep solutionoffset change weak: replaced calibrated

The frame exchange

Each picture costs a one-use ticket, replaced with every answer, so a replayed request never buys an extra view. The server allows a sustained frame rate, 12 per second by default: about where separate pictures start to read as motion. The page always sends the latest wheel values.

Optionally, each ticket also needs a proof of work, a SHA-256 chain computed in the background. It is off by default, because making the ~100 pictures a person needs more expensive adds little security.

BrowserServer wheel values + one-use ticket check ticket and frame rate render on the GPU compare with the target picture, overlap score, next ticket …at most 12 times per second

When does it fit?

Each picture's silhouette is compared with the target's by intersection over union, and the score comes back with the picture to fill the bar. Showing it costs nothing: a bot could segment the picture and compute it anyway.

The moment the score reaches the required overlap, the wheels lock, the outline turns green, and the server renders the solved jelly once more at double resolution. If you get stuck, Show solution turns the wheels to the answer; asking before you solve ends that challenge.

overlap = intersection ÷ union solved at 0.94

Under the hood: the server

The jelly is a signed distance field: a function that gives each point's distance to the surface. Two to four spheres and rounded boxes are blended smoothly. A WGSL compute shader on the GPU marches a ray per pixel along that distance, then shades the result as glossy, slightly translucent jelly in a small coloured room.

With the Rust server, the browser never receives the shape, only pictures. Rendering in the browser would hand the shape to a bot.

The public demo is a static site, so there the very same Rust backend runs in your browser, compiled to WebAssembly and rendering with WebGL2. That makes the shape inspectable: fine for trying it out, not for a real CAPTCHA.

Your browser Wheels Sees only pictures, the outline, and the overlap score Rust server checks the ticket Challenge (in memory) Secret shape Wheel behaviours Solution, target silhouette Tickets, frame rate GPU raymarcher → PNG values, ticket picture, score

Settings

All of these appear under Settings in the demo. Easy, Normal, and Hard are presets.

SettingDefaultMeaning
TransformationRangeEffect

Honest status

This is a research prototype. Nobody has shown yet that humans beat automated solvers here. Numerical search and inverse rendering are plausible attacks. A production service would also need redeemable completion proofs, quotas, and an accessible alternative.