Generated banner for Paper Cinder Transition
Generated logo for Paper Cinder Transition

Paper Cinder Transition

Meng ToCommunityCreated by Meng To

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Change between pages, chapters or scenes with a paper-burn transition, a ragged ember line that sweeps across the frame, chars the old page ahead of it and reveals the next scene live behind it, written as one WebGL composite pass over a frozen frame and a scissored live scene. Covers the front's silhouette, the luminous ember gradient with a beading gold thread, torn porous charcoal that is alpha-masked, baked noise, finite-difference slopes, the 0.75-scale live scene, sweep direction, timing, reduced motion and visibility pausing. Use for a burn transition, paper burn, cinder wipe, chapter change by fire, charring page reveal, burn-away section change, ember dissolve, or when a fade, slide or generic dissolve between scenes reads as cheap.
— the description by Meng To

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The paper-cinder-transition provides a method for creating a visual transition where one scene is replaced by another through a simulated fire-burn effect. It uses a single WebGL composite pass to manage the frozen outgoing frame, the burning ember line, and the live incoming scene. The effect includes features such as a luminous ember gradient, alpha-masked charcoal, and baked noise to simulate the physical process of paper charring and burning away. It is designed to replace standard fades or slides with a more thematic chapter-change animation.

What it does

  • Renders a ragged ember line that sweeps across the frame to reveal a new scene.
  • Uses a WebGL composite pass to manage frozen and live scene buffers.
  • Applies alpha-masked charcoal and luminous ember gradients to the transition edge.
  • Implements finite-difference slopes for accurate edge rendering.
  • Supports reduced-motion settings by falling back to a standard cross-fade.
  • Includes logic for scissoring and scaling the incoming scene during the transition.

When to use it

  • When you need a thematic transition between chapters or sections of a web page.
  • When standard fades or slides are insufficient for the desired aesthetic.
  • When implementing a fire-themed reveal for content.
  • When you require a transition that maintains performance by baking noise and using scene-specific buffers.

Advantages

  • Provides a distinct, non-standard visual transition for scene changes.
  • Includes built-in support for accessibility via reduced-motion preferences.
  • Optimized through noise baking and selective rendering of scene buffers.
  • Highly configurable parameters for sweep direction, timing, and ember appearance.

Usage examples

“Implement a paper-burn transition between the current chapter and the next.”
The agent provides the WebGL composite logic and staging instructions to replace the current frozen frame with the next scene using the cinder-wipe effect.
“How do I ensure the transition respects user accessibility settings?”
The agent explains the implementation of the prefers-reduced-motion media query to disable the burn effect and use a standard cross-fade instead.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/mengto/paper-cinder-transition/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip paper-cinder-transition.zip -d .agents/skills

Documentation by Meng To

Paper Cinder Transition

A page does not fade into the next one, it is eaten by a line of fire. Reach for fire-paper-loader when the burn is a ring on a loading screen that must survive a blocked main thread; reach for this when the burn is the change between two scenes you own. For text that is written in by a mask rather than burned, use masked-reveal; for a scroll-scrubbed sequence with no burn, scroll-scrubbed-visual-sequence.

The mechanism

One full-screen pass decides, per pixel, whether it belongs to the frozen old frame (ahead of the line), to the burning zone (the line), or to the live new scene (behind it), from a single signed distance to a noisy front. Everything else is staging. Remove any of the three layers and it stops reading as fire: no frozen frame and the old page keeps moving under the flame, no live scene and the reveal is a still, no pixel-true distance and the edge is a soft blotch.

xc  = signed distance to the front in CSS px (+ ahead, - burnt)
reveal = clamp(0.5 - xc/aa, 0, 1)      // new frame from the front back, cut to the pixel
col = mix(fromFrozen, toLive, reveal)
col = mix(col, charcoal,  bed * pores) // 26 px band of torn, porous char (alpha-masked)
col += flame(xc) + charGlow(xc)        // additive: thread, ember zone, tight glow

Staging split

goes in the skillstaging (yours to change)
the composite order, the distance field, the ember ramp, char rules, the noise bakewhat the two scenes are, palette of the scenes, typography, page copy
the two scene buffers (frozen from, live to) and the scissorwhich side the line enters from (see below)
timing, easing, DPR, reduced-motion stillcontrol chrome

Rules, each tied to the failure it prevents

Draw the frozen old frame and the live new scene, never one fading into the other. Snapshot the outgoing scene once into a full-resolution target when the transition starts (clock frozen) and keep rendering the incoming scene live. A cross-fade, or a burn over a still-animating old scene, shows two chapters in one patch of screen and the fire stops being the thing that changes the page.

Measure the front in pixels, not in field units. xc = (field - T)/grad * pxHeight / pxScale. A level set alone runs a hair-thin seam wherever the noise leans with the sweep and a fat one where it leans against it, so the flame's width is uneven for no reason.

Take the slope by finite differences a few px apart, never dFdx of the baked texture. The baked noise's slope is constant across each texel; per pixel it stripes the band across the line. Sample the broad field at +4 px in x and y (hStep = 4*uPxS/uPxH) and clamp the gradient to 0.35/aspect .. 3/aspect.

The ember zone is a smooth luminous gradient, not steps. Symptom: it reads as a non-realistic poster. Grade it continuously by a heat variable: yellow at the front, then orange, then deep red at a crisp torn lip. Hot stretches carry yellow further back. Ramp constants (linear, before tone map):

stoprgbwhere
deep0.34, 0.022, 0.003lip, tau 0.05
orange0.86, 0.20, 0.024tau 0.42
gold1.02, 0.38, 0.055tau 0.76
hot gold1.10, 0.64, 0.17 x (0.30 + 0.70*hot)tau above 0.86
thread1.40, 0.56, 0.09 to 1.85, 1.02, 0.30 by heatthe front line
glow0.95, 0.20, 0.022 x 0.602 to 5 px round the thread

Keep hot colours gold, never cream. A pale yellow reads cream at full heat and khaki when dimmed. Nothing on the ramp is grey or white; a dim stretch goes down the ramp, it is not just darker.

The front is a bright thread that beads and pinches, 0.7 to 5 px, not an even stroke. An even stroke reads as neon. Width (0.9 + 2.6*heat) * bead with bead 0.5 to 1.5 from a noise along the edge. Give it a tight glow only (exp(-|xc+0.5wc| / (2 + 2.8*heat))), no wide halo.

It must visibly move, at rest of the sweep too. Symptom: "too stale/static". Drive heat with pulses that run along the edge in both directions (sA*0.018 - t*1.30, sA*0.027 + t*1.70), flicker at t*7, a roll back through the zone at -t*2.6, drifting beads (-t*0.8), and licking tongues on the front (t*1.1, t*2.8, at most 0.022 and 0.010 of the screen). Stills hide all of this, so judge the burn in a real-time held clip.

Alpha-mask the black char; it is not a flat slab. The char is a band 26 px wide (plus 12 px of front slack) that crumbles off the live scene along a torn far edge, with pores opening in it as it ages, down to whatever lies beneath. A solid black strip reads as a wipe. Cover = bed * pores, edge torn by 8*noise(0.08) + 3*noise(0.25) px, which is gentler than the front's own slope so it frays without cutting loose an island.

Never ring the pores with a glowing rim. Rims joined into one drawn contour along the char edge. Pores are just holes.

Take the char's edge from the broad front, not the fine one. A 2-D noise cut loose islands of char that floated on the new frame. Use a noise along the edge only (kbEdgeNLine), and let edge = zoneW + fs + bedW*(0.35 + 1.10*n) with fs at most 12.

Scorch the old frame ahead of the flame in one continuous darkening, 20 to 40 px reach, from tan 0.80, 0.62, 0.42 to dark brown 0.20, 0.10, 0.045 by tk^2, reach varied by noise. Three separate steps drew outlines that copied the flame.

Bake the noise; do not stack fbm per pixel. Cost at 2880x1800: per-pixel fbm 1.5 to 3 ms a pass; one tileable texture and a hash table, 0.3 to 0.6 ms with the same look. Bake once: a 1024^2 RGBA16F texture on a 16-cell period (r fbm 3 octaves, g ridged 3, b gradient, a ridged 2, all sampled at x*0.0625) and the integer hash lattice in a 2048^2 R16F table, filtered at the smoothstep of the fraction so it equals the value noise exactly.

Scissor the live scene to the revealed side, and render it small. Behind the line only, plus 0.16 of the screen for bays and haze. During a burn draw it at 0.75 scale (the composite stays full size, because the edge is what the eye reads); once the transition has rested 150 ms, cross-fade to the full-size scene over 0.3 s, both drawn meanwhile, so the sharpness step is never seen and never costs a moving frame. Put text on the live side at full size in the composite; drawn in the 0.75 buffer it goes soft.

Skip the noise where nothing can reach. By hx: more than 0.215 + 0.15 ahead of the front return the frozen frame, and behind 0.25 - 0.215 return the live one. Inside the band, more than 62 px ahead (plus slack) or 125 px behind does the same. That is what pays for full device resolution.

Sweep from the side the incoming words sit. hx = dir>0 ? uv.x : 1-uv.x; a chapter whose text is on the right is burned in from the right. Going backward uses the target's side too. A line that always runs left to right crosses its own new title last.

Seed every burn. seed = (chapter+1)*17.3 picks 2.0 to 3.6 broad bays up the frame, their depth (0.055 to 0.115) and lean ((sv.x-0.5)*0.07), so two burns are never the same silhouette.

Constants

itemvalue
band half width0.215 screen heights
front, linear-0.26 + 1.62 * rc, rc = clamp((f-0.01)/0.97), in and out off frame
duration3.0 s default; 1.5 to 5 s all read
line noise scalesbroad q*1.10 (0.055-0.115), q*2.60 (0.050-0.030); fine 0.014, 0.006, 0.0025
ember zone width12 to 66 px, (18 + 20*min(w,2.6)) * (0.55 + 0.45*life)
charbed 26 px, crust 3 to 6 px, sumi 0.0085, 0.0062, 0.0048
heat shimmerabout 1.8 px of uPxH, only within 18 px of the front
bloombright pass threshold 1.15, half-res and quarter-res blurs, weights 0.26*4 and 0.34*4
tonevignette 0.42 + 0.58v, ACES, sRGB, grain 0.003
live scene0.75 scale in transit, 150 ms rest, 0.3 s cross-fade
budgetsdt clamp 1/30 s, DPR cap 2

Gotchas, symptom first

  • The flame is a thin red line on black char, no ember zone. The baked noise and hash samplers are unbound, so life reads as the frame texture's value. Bind uKbN and uKbH.

  • Bare garbage or a hard cut behind the line. The live scene is only drawn inside the scissor (front + 0.215 + 0.16); a narrower margin lets the composite read undrawn texels.

  • Stair-steps or 2x2 blocks along the char edge. A derivative taken past a skipped branch. Compute the pixel change from the field's own scale (kbAA(v, w)).

  • Islands of char floating on the new frame. The far edge was cut from fine noise; take it from the broad front.

  • A milky band inside the ember edge. Lifting the blacks with a curve washed it white over paper; light the dark areas by a gain instead.

  • The scene behind the line looks soft after the burn ends. The 0.75 buffer stayed; run the full-size cross-fade after the rest interval.

  • Timings look slow. A hidden Browser pane keeps rendering and steals the GPU; measure in a headless browser on the GPU flags (--use-angle=metal --enable-gpu) with the pane parked. Kibori's transitions held p50 8.3 ms (120 Hz cap) once the noise was baked and the scene scissored; this demo's burn measured p50 8.3 ms, p90 8.8 ms at 1440x900 the same way.

  • The grain and embers swim as the front passes. Keep them on the paper (g in paper coordinates plus a per-burn offset), never in screen space; only the front moves.

Accessibility and lifecycle

  • prefers-reduced-motion: reduce: no burn. Render the designed still of each scene at a fixed time and cross-fade the frozen and live frames over 0.35 s (smoothstep). Controls stay live.

  • Pause on document.hidden and when the canvas leaves the viewport; reset the time base on resume so the first frame does not integrate the pause.

  • Clamp dt to 1/30 s, cap DPR at 2, size from a ResizeObserver and build nothing at a zero viewport.

  • A press during a burn queues the target; the last one wins after the line leaves.

  • Real buttons, arrow keys and 1 to 3 change chapters, and a live region names the arrival.

Cost

Measured in the source page: per-pixel noise was the cost, not the flame. Baking it, and returning the plain scene away from the line, is the lever. The 0.75 scale and the scissor come second. Do not chase MSAA on the composite: the edge is drawn to the pixel by kbAA.

Provenance

Extracted from KIBORI, a WebGL timber-workshop page whose chapters burn into each other and whose footer paper burn set the look. The EDGE GLSL (flame, char, pores, crust, scorch) and the burn pass in demo.html are that page's own, ported, with the scenes replaced by three shader-drawn rooms.

Files

PROMPT.md

Paper Cinder Transition — Demo Prompts

Minimal prompt

Use $paper-cinder-transition to change between these chapters with a paper-burn line: a ragged ember edge sweeps across, the old chapter frozen and charring ahead of it, the next one live behind it. Not a fade, not a slide.

Recreate the demo

Use $paper-cinder-transition to recreate Paper Cinder Transition as one standalone HTML document. Treat demo.html as the visual, motion, responsive, accessibility and performance reference.

Experience
  • One full-viewport WebGL canvas showing one of three timber-workshop chapters: a washi and cedar-lattice room in cloud light, a night workshop with one flickering paper lantern, and raking light over planed cedar boards. Each has a large serif title, a small kicker and kanji, and a two-line body, on the left, right, left in that order.

  • The burn is the subject. It runs by itself once on load (about 1.4 s in), then every 2.6 s, until the first touch or key, so the mechanism is on the first screen.

  • Controls: Prev, three numbered chapter buttons, "Burn to next", and a burn-time slider (1.5 to 5 s, default 3.0). Arrow keys, Page Up/Down, Space and 1 to 3 change chapter. A press during a burn queues the target; the last one wins after the line leaves.

  • A translucent chip top-left names the technique, the verified stack line (Vanilla JavaScript, WebGL 2, GLSL; no Three.js) and one sentence of mechanism.

Implementation contract
  • Raw WebGL 2, no libraries. Half-float render targets (EXT_color_buffer_float). A fullscreen triangle from gl_VertexID.

  • Two scene buffers per burn: the outgoing chapter drawn once into a full-size target with its words and its clock frozen, and the incoming chapter drawn live each frame.

  • One composite pass: xc is the signed pixel distance to a noisy, seeded, leaning front (front = -0.26 + 1.62*rc, band half width 0.215, sweep from the side the incoming words sit). It shows the frozen frame ahead, the live frame behind, scorches the frozen frame 20 to 40 px ahead in one continuous darkening (tan to dark brown), draws a 26 px torn porous char band that is alpha-masked over the live scene, a 3 to 6 px crust, and adds the flame: a 0.7 to 5 px beading gold thread, a smooth yellow-orange-deep-red ember zone 12 to 66 px wide with a torn lip, a tight 2 to 5 px glow, and dim grain glowing in the char just behind it. No smoke, no streaks, no rims round pores, no hard colour steps.

  • Ember ramp (linear): deep 0.34,0.022,0.003, orange 0.86,0.20,0.024, gold 1.02,0.38,0.055, hot gold 1.10,0.64,0.17; thread 1.40,0.56,0.09 to 1.85,1.02,0.30. Hot colours stay gold, never cream.

  • Everything alive: heat pulses along the edge both ways, flicker, rolling back through the zone, drifting beads, tongues licking up the front.

  • Noise baked once at start: a 1024^2 RGBA16F tileable fbm/ridged/gradient texture on a 16-cell period, and a 2048^2 R16F hash table. The composite samples them; the slope of the front is taken by finite differences 4 px apart, never with derivatives of the bake.

  • The live scene is scissored to the revealed side (front + 0.215 + 0.16) and drawn at 0.75 scale during the burn; after 150 ms of rest it cross-fades to full size over 0.3 s. The incoming words are composited at full size in the burn pass.

  • Bloom from a bright pass at threshold 1.15, half-res and quarter-res blurs; final pass vignette, ACES, sRGB, 0.003 grain. Scenes are clamped under 1.1 so a rest frame carries no bloom.

  • Words are drawn once per chapter in a 2D canvas (Instrument Serif, Inter, Shippori Mincho), uploaded as textures, and rebuilt on resize.

  • dt clamped to 1/30 s, DPR capped at 2, sized from a ResizeObserver, paused when the page is hidden or off-screen with the time base reset on resume.

  • prefers-reduced-motion: reduce: scenes render as a fixed still and a chapter change is a 0.35 s cross-fade; controls stay live.

  • Buttons are real and keyboard-reachable with a visible focus ring; a live region names the chapter that arrives. Clean console at 390 and 1440 px, no horizontal scroll.

Restrictions
  • No images, video or third-party JS. Google Fonts only.

  • No blur-based flames, no additive white, no sheen or streak passes over the scenes.

  • The composition must be complete without the pointer.

Remix prompt

Use $paper-cinder-transition on a different world: a contemporary art-gallery site with four rooms (white cube, concrete, blue glass, night), with the ember ramp shifted toward magenta and cyan and a cool ash char, sweeping vertically from the bottom in place of the side. Keep the mechanism and the budgets: a frozen old frame and live new scene, the pixel-true noisy front, alpha-masked porous char, a smooth luminous zone with a beading thread that stays lit at the hot spots, baked noise with finite-difference slopes, the scissored 0.75-scale live scene with its rest cross-fade, the queued presses, the reduced-motion cross-fade, dt and DPR limits.

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Meng To
Publisher
Meng To (Community)
Source
MengTo/Skills · agent-skills/web-design/paper-cinder-transition · commit 5ea1661
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Meng To.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download paper-cinder-transition.zip