Build1 distinct publisher2 min readUpdated
A dev.to walkthrough maps a bitmap onto arbitrary triangles using clip plus drawImage. The load-bearing decision is making each frame a pure function of time, so preview and export share one path.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Follow any of these and your For You feed starts watching them — no settings page required.
The per-triangle affine solve is where the work and the bill both land. Each mesh quad becomes two triangles [3], and the posted loops run inclusively over rows and columns [16], so the 18x12 preview mesh is 247 vertices and 432 triangles [1][2]. Export at 22x12 comes to 528 triangles [3], about 22 percent more clip-and-draw pairs for every frame written out [4]. Nothing batches: each triangle needs its own clip path and its own drawImage [3]. Grid density is the quality dial here, and it is priced in draw calls rather than shader instructions.
Which makes the post's own figures worth checking. It describes 18x12 as 432 vertices and 396 triangles [6]; 432 is the triangle count, and 396 matches neither number [5]. That does not change the technique, but it does invalidate any capacity estimate copied from the prose.
The motion code is more careful than it first looks. The harmonic weights in snap() sum to exactly 1.00 [7][6], which bounds the function at plus or minus one and keeps the amplitude parameter meaning what it says. edgeFlex evaluates to 0.6 at the sheet centre and 1.0 at each corner [8][7], so corners travel roughly 67 percent further than the middle [8]. That is the author's stiffer-in-the-middle paper claim [9] written as arithmetic instead of solved by a simulation. Horizontal displacement is scaled by 0.4 against 0.25 vertical [10], a 1.6 to 1 bias [9] that reads as a sheet shaking sideways. The per-vertex phase offset of u * 1.2 + v * 0.8 is what makes it a travelling wave rather than a grid pulsing in lockstep [13].
All of that is closed form in t, which is the point of the purity rule rather than an accident of style. The author's stated failure mode for a stateful preview loop is drift, stutter, or output that depends on the host machine's frame rate [11], and sampling at frame/fps only cures that if renderFrame cannot remember anything between calls [4][5]. The price is written into the code convention: sin(phase), never position += velocity [12]. Paper flutter gives up nothing for that. Cloth catching on an obstacle, or any motion with contact history, cannot be expressed this way and would need the accumulator the design rules out.
Worth noting that the material supplied here stops at the declaration of the 2x3 matrix the solver produces [15], so the solve itself is left to the reader. The transferable part is the surrounding structure, plain TypeScript with no framework dependency [14], which applies to any ripple or page-curl someone wants to ship without a GL context.
Ranked by verification strength, evidence, and original report placement.
The technique slices the image into a grid of vertices, each carrying a (u, v) texture coordinate in 0..1 and an (x, y) screen position, splits each grid quad into two triangles, and for each triangle computes the affine transform mapping its undeformed source corners onto its deformed destination corners, then clips to the triangle and calls drawImage.
The edge flex factor is edgeFlex = 0.6 + 0.4 * (Math.abs(u - 0.5) * 2 + Math.abs(v - 0.5) * 2) * 0.5.
The author says edge flex keeps the interior relatively rigid while corners flap, because real paper is stiffer in the middle of a held sheet.
The supplied text identifies the per-triangle mapper as the load-bearing function, solving for the 2x3 affine matrix [m11, m12, m21, m22, dx, dy], and ends at that point without showing the solve.
The vertex generation loops run row = 0 to rows inclusive and column = 0 to columns inclusive, with u = column / columns and v = row / rows.
The author published a walkthrough of the mesh-warping technique behind Paper Animator, a browser tool that turns a photo into a paper cut-out that flutters and floats, with no upload, no server and no WebGL required to get the first frame on screen, and which exports the same animation to GIF/WebM/MP4.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Code shown and checkable, but unmeasured and internally inconsistent
The central mechanism is published as runnable code with every coefficient exposed, so the affine solve, clip-and-drawImage path, purity rule and motion formulas can be verified by inspection and by arithmetic. Against that: a single self-published source, no timing or compatibility measurement behind the fast and export-safe framing, a truncated listing, and a stated vertex/triangle count that contradicts the post's own loops.
One self-reported tool, no third-party use
The only adoption signal is the author's own shipped browser tool built on the technique. There are no third-party deployments, repository or package metrics, download figures, or independent reimplementations anywhere in the supplied material, so adoption is real but confined to a single self-disclosed instance.
Mildly overstated on numbers and speed, sound on mechanism
The technique claims are modest and mostly self-evidencing, which keeps the gap small. It is positive rather than zero because the post labels the design fast and export-safe with no measurement of 432 or 528 clip-and-drawImage pairs per frame, and because its headline mesh statistics are wrong on its own terms. The determinism argument itself is well-supported by the shown code path.
Technique post that markets the author's own tool
The post opens by naming the author's product, Paper Animator, and links the technique to it, so there is a clear promotional incentive to present the approach as fast and export-safe. The incentive is bounded by the fact that the load-bearing code is published in full, which invites contradiction, but no independent party reviews or replicates the claims.
High on mechanism, low on performance and uptake
Confidence is high for what the code shows - the affine per-triangle mapping, the purity rule, and every motion coefficient - because those are verifiable from the listing and reproducible arithmetic. It is held down by single-source provenance, a truncated snippet, absent measurements, no external adoption, and one demonstrably incorrect quantitative claim in the source.
build
Allow-list the closed set, block-list the open one: 193 thin geo pages, one gate1 distinct publisher
build
A GAN beauty filter is a device budget allocation, not a feature toggle1 distinct publisher
build
Agent memory rots by accumulation, and the missing primitive is a supersession key1 distinct publisher
build
Forty animated backgrounds, one battery budget: how Pairly rations frames on old Android1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 24, 2026