# Dazzle Content Authoring Guide Your content runs in a cloud browser captured at 1280x720 @ 30 fps and streamed to platforms like Twitch and Kick. This guide helps you write content that looks great on stream. For ready-to-use examples, see [stream-examples](https://github.com/dazzle-labs/stream-examples). Dazzle stages come in two tiers: - **GPU stages** — NVIDIA RTX with hardware-accelerated WebGL and video encoding. Shaders, raymarching, complex post-processing — all 30 FPS. - **CPU stages** — Software-rendered OpenGL, no hardware GPU. Lighter content only. Most of this guide applies to both. Sections marked **(CPU only)** note constraints that don't apply on GPU. ## Environment at a Glance | Setting | GPU Stage | CPU Stage | |-------------|------------------------------------------------|------------------------------------| | Resolution | 1280x720 (fixed) | 1280x720 (fixed) | | Frame rate | 30 fps rendering + capture | 30 fps rendering + capture | | Renderer | NVIDIA RTX (hardware WebGL) | Software OpenGL (no hardware GPU) | | Encoder | Hardware video encoder, CBR 2500k | Software video encoder, CBR 2500k | | Browser | Chrome, full viewport | Chrome, full viewport | | Audio | Web Audio API supported, audio captured | Web Audio API supported, audio captured | | Persistence | localStorage and IndexedDB survive restarts | Same | ## Page Setup Always start with a full-viewport, no-scroll layout: ```html
``` For canvas-based content, size to the window: ```js const W = canvas.width = window.innerWidth; // 1280 const H = canvas.height = window.innerHeight; // 720 ``` Do NOT hardcode 1920x1080 — the viewport is 1280x720. ## Prefer Declarative Over Imperative Write content as **declarative HTML/CSS/SVG** rather than imperative canvas drawing code whenever possible. Declarative approaches are: - **Easier to maintain** — structure is visible in the markup - **Better for streaming** — CSS animations are GPU-composited and silky smooth - **More resilient** — no frame-loop bugs, no state management issues - **Easier to update** — change a CSS variable, not a draw function **Good: declarative** ```html ``` **Avoid: imperative canvas for things CSS can do** ```js // Don't do this for simple animations function draw() { ctx.clearRect(0, 0, W, H); particles.forEach(p => { ctx.fillStyle = p.color; ctx.fillRect(p.x, p.y, 4, 4); p.y += Math.sin(p.t) * 0.5; }); requestAnimationFrame(draw); } ``` Use canvas/WebGL when you genuinely need it: complex generative art, shader effects, data visualizations with thousands of data points, or anything that requires per-pixel control. ## What Works Well **CSS animations & transitions** (both tiers) - `@keyframes`, `transition`, `transform`, `opacity` — all smooth at 30 fps - CSS is the cheapest way to animate; prefer it over JS when possible **SVG** (both tiers) - Vector graphics scale perfectly and animate smoothly via CSS - Good for logos, icons, diagrams, and data visualizations **Canvas 2D** (both tiers) - Drawing, compositing, particle effects — efficient even with 1000+ particles - Good for dashboards, visualizations, generative art, text rendering **DOM-heavy animation** (both tiers) - 200+ elements repositioned every frame via JS — still 59 fps **WebGL shaders** (GPU: unlimited | CPU: geometry only) - **GPU stages**: Full fragment shader support — raymarching, SDF, FBM noise, multi-pass rendering, bloom, post-processing — all 30 FPS. Go wild. - **CPU stages**: Geometry-based WebGL (500K+ triangles with per-pixel lighting) works at 30 fps. But fragment-heavy shaders (noise, raymarching) drop to 1-11 fps. Use mesh complexity instead of shader complexity. **Web Audio API** (both tiers) - Oscillators, gain nodes, audio buffers — all captured to the stream - Good for music visualizers, sound effects, generative audio **CDN libraries** (both tiers) - Load via `