Genga Split — 原画
A real-time anime-style camera filter with a WebGL2 shader pipeline and a drag-to-split reveal interface
Genga Split is a self-contained single HTML file that turns your camera feed into an animated anime frame in real time. Named after "genga" (原画) — the key drawings in Japanese animation — the app runs a multi-pass WebGL2 shader pipeline that flattens the video into painted regions, extracts ink-line edges, and adds a diffusion bloom characteristic of hand-drawn animation cels shot through real optical filters.
A split-reveal interface lets you drag a divider across the canvas to compare the original camera view with the stylized output side-by-side — vertical or horizontal split, your choice.
Delivery
1 HTML file
Dependencies
0 installed
Style presets
4 named
Shader passes
3-stage pipeline
GPU API
WebGL2
Backend calls
Zero
Camera access requires a secure origin — https:// or http://localhost. Additionally, the browser must support WebGL2 (all modern Chromium, Firefox, and Safari builds do).
python -m http.server 8080 and open http://localhost:8080/genga-split.htmlnpx serve . and open the printed URLEach preset is a named tuning of shader parameters modeled on real anime production stages. Switch presets in real time — a shader uniform update on the next frame.
Shiage / Cel
The final production cel look — flat brightness bands with a soft terminator, saturated color, clean dark ink lines. Balanced bloom for a broadcast-anime feel.
Sumi / Ink
Sumi-e brush painting — near-desaturated palette, heavy ink evidence, minimal bloom. Thin flowing edge lines dominate. Feels like ink on rice paper.
Suisai / Pastel
Watercolor style — more brightness bands for a softer gradient, muted ink at 60% strength, lifted mid-tones. Full bloom for a diffused watercolor glow.
Yakei / Neon
Night-scene neon — hyper-saturated (1.85×), lowered exposure, cool ink tint, aggressive bloom. Evokes anime night scenes with lit signs and rim light.
Every frame runs through three WebGL2 shader passes in sequence. Each pass is a fragment shader run over a full-screen quad, writing to a framebuffer texture that the next pass reads from.
The Kuwahara filter flattens image regions into painted-looking blocks while preserving strong edges. It works by sampling four overlapping sub-windows around each pixel, computing brightness variance for each, and picking the mean color of the window with the lowest variance. The result: smooth interior regions with sharp boundaries — the signature "painted anime cel" look. This app uses an anisotropic Kuwahara variant that also aligns sample orientation to the local image structure.
Brightness banding (bands) quantizes luminance into a small number of steps for the cel-shaded terminator effect. A soft threshold (celSoft) controls the sharpness of transitions between bands. In parallel, a Sobel-based Difference-of-Gaussians (DoG) extracts edge lines by measuring cross-edge brightness differences. Line evidence is then integrated along the flow direction (sigmaM) to convert speckly edge noise into continuous strokes.
An XDoG (Extended DoG) with threshold parameters phi and eps produces the final ink mask, which is mixed into the flattened color at strength inkAmt using the preset's ink color.
Traditional anime cels are physically shot through diffusion filters to soften highlights and create a filmic bloom. This shader emulates that: pixels above bloomThr are blurred and added back to the base image. The bloomKnee parameter softens the threshold transition, and bloomInt controls overall intensity.
The shipped build is shader-only — it runs entirely on the GPU with no ML model. There's also a hook for adding an AnimeGAN neural network on top for even more stylization: self-host an animeganv3_tiny.onnx model on your own origin, wire it in via ONNX Runtime Web, and use the shader path as your live preview while ONNX inference runs in the background.
The shader pipeline stays as the always-on live path because it's fast (60fps on modest GPUs); the optional ONNX path is for offline stylization of captured frames where higher quality justifies the extra latency.
WebGL2
GPU shader pipeline — Kuwahara, Sobel, DoG, bloom
Native browser
GLSL ES 3.0
Fragment shaders for all three passes
Inline in HTML
WebRTC getUserMedia
Camera stream to video texture
Native browser
HTML5 Canvas 2D
Split composite of shader output + raw camera
Native browser
Framebuffer objects (FBO)
Off-screen render targets between shader passes
WebGL2 feature
bands / celSoft
Brightness banding + terminator width
sigmaE / tau
Cross-edge DoG width + surround balance
sigmaM
Line integration distance along flow
phi / eps
XDoG threshold sharpness + cutoff
ink / inkAmt
Line color and mix strength
bloomThr / bloomKnee / bloomInt
Diffusion bloom shaping
https:// or http://localhost for camera access.chrome://gpu if the shader path fails to initialize.Single flat script — no framework, no build step. All GLSL shader source is inlined as template literals. Shaders are compiled and linked once at startup; the same three-pass pipeline runs every frame with just the uniform values changing when the user switches presets.
State is a small S object: current preset ID, current split position (0–1), split axis (v/h), and a few timing values. The render loop reads state each frame — no mutation queue, no reactive framework — the simplest possible model.
Framebuffer objects hold intermediate textures between passes. On resize, all FBOs are torn down and recreated at the new canvas dimensions — a full GPU state reset that takes milliseconds.