A real-time bitmap processor that applies an old-school ordered dithering effect to your live webcam feed using an 8x8 Bayer matrix. It is built natively with WebGL for high performance and bundled with Vite.
- Live WebGL Processing: Fast, real-time image manipulation directly in the browser via custom fragment shaders.
- Adjustable Resolution: Pixelate up your feed dynamically by adjusting the block size.
- Adjustable Contrast: Tweak the contrast multiplier to achieve the perfect dithered spread.
- Multiple Palettes:
- B&W: Classic 1-bit style monochromatic dithering.
- Gameboy: Nostalgic 4-shade green tint simulation.
- Retro: High-contrast multi-color retro scheme (Black, Purple, Cyan, Yellow, White).
- Capture Functionality: Take a snapshot of your currently dithered view and automatically download it as a PNG.
- Vite - Frontend Tooling
- WebGL - Custom Vertex and Fragment Shaders via the WebGL API
- Vanilla JavaScript - Core logic and state management
- HTML/CSS - Structure and retro-styled UI layout
- Node.js installed on your machine.
- A functional webcam connected to your device.
- Clone or download this project.
- Navigate to the project directory:
cd dithered-camera- Install the required development dependencies:
npm installTo start the Vite development server and view the project:
npm run devOpen the local URL provided by Vite (typically http://localhost:5173) in your web browser.
Note: The browser will request permission to access your camera. You must grant camera permissions for the dithering effect to work.
index.html— The main HTML structure, overlay text, controls panel, and canvas wrapper.src/main.js— Core application logic. It handles camera permissions, video streaming, WebGL context and buffer initialization, shader compilation, and the main requestAnimationFrame rendering loop. The 8x8 Bayer Matrix, contrast adjustment, and color mappings are mathematically calculated directly within the WebGL fragment shader script.src/style.css— Modern yet retro-themed CSS styling for the interface, including responsive absolute positioning for the camera and floating control panels.
- Video Feed: The app captures your realtime webcam feed using the
navigator.mediaDevices.getUserMediaAPI. - WebGL Texture: The video frames are streamed directly and continuously into a 2D WebGL texture.
- Fragment Shader: A custom fragment shader processes each frame pixel-by-pixel:
- It downscales the resolution by flooring UV coordinates if a resolution
> 1is selected. - It applies a contrast adjustment to the sampled pixel colors.
- It calculates the perceived luma (grayscale) value.
- It performs thresholding against an 8x8 Bayer matrix to decide whether a pixel should be considered "on" or "off", creating the uniform pattern known as ordered dithering.
- Finally, it applies the selected color palette map based on the active state.
- It downscales the resolution by flooring UV coordinates if a resolution