Genga Split — 原画

A real-time anime-style camera filter with a WebGL2 shader pipeline and a drag-to-split reveal interface

WebGL2 GLSL shaders Kuwahara + Sobel Anime-style

What it is

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

How to open it

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 — python -m http.server 8080 and open http://localhost:8080/genga-split.html
▸Node — npx serve . and open the printed URL
▸Static host — Netlify, Vercel, GitHub Pages all serve over HTTPS automatically

Style presets

Each 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.

The shader pipeline

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.

Camera video texture
→
Pass A: Kuwahara flatten
→
Pass B: Sobel + posterize
→
Pass C: Diffusion bloom
→
Split composite

Pass A — Kuwahara filter

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.

Pass B — Posterize + Sobel

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.

Pass C — Diffusion bloom

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.

Split-reveal interface

DragDrag on the canvas to move the split line — cursor position sets the divider between original and stylized output.
Axis toggleButton switches between vertical (left/right) and horizontal (top/bottom) split orientation.
Full stylizedDrag the split fully to one edge to see the stylized output covering the entire frame.
Full originalDrag to the opposite edge to see the raw camera feed unmodified.

Optional AnimeGAN path

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.

Technology stack

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

Shader parameter reference

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

Camera lifecycle and privacy

✓All shader work runs on your device's GPU. Video frames never leave the browser tab.
✓Camera stops when the tab is backgrounded — OS indicator light turns off.
✓Closing or navigating away releases the camera immediately.
⚠Requires https:// or http://localhost for camera access.
⚠Requires WebGL2 support — check chrome://gpu if the shader path fails to initialize.

Architecture overview

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.