# Godlights — Full API Reference > Animated god ray/light beam effects for React. > npm: `npm install godlights` | Docs: https://www.godlights.io/docs | Context7: https://context7.com/gustavoquinalha/godlights > shadcn registry: `npx shadcn@latest add "https://www.godlights.io/r/god-lights-hero.json"` --- ## Framework requirements **Next.js App Router**: add `"use client"` at the top of any file that uses `` or imports from `godlights`. The component uses `useRef`, `useEffect`, and `requestAnimationFrame` — all client-only APIs. ```tsx "use client"; import { GodLights } from "godlights"; ``` **Next.js Pages Router**: use dynamic import with `ssr: false` to avoid hydration errors. ```tsx import dynamic from "next/dynamic"; const GodLights = dynamic(() => import("godlights").then(m => m.GodLights), { ssr: false }); ``` **Vite / Create React App / other bundlers**: no special setup needed. --- ## GodLights component ```tsx import { GodLights } from "godlights"; ``` The wrapper div has `position: relative` and `overflow: hidden` by default. For full-bleed background: ```tsx style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} ``` Do NOT rely on `className="absolute"` alone — inline style wins over Tailwind classes. Always define `scene` outside the component or wrap it in `useMemo`. Constructing it inline causes unnecessary canvas redraws on every parent render. ```tsx // ✅ memoized — recomputes only when color changes const scene = useMemo(() => ({ ...base, layers: [...] }), [color]); // ❌ inline — reconstructs on every render ``` --- ## SceneConfig ```ts interface SceneConfig { width: number; // canvas width in px (typically 1920) height: number; // canvas height in px (typically 1080) noise: number; // film grain intensity 0–100 (0 = none) grainSize: number; // grain pixel size 1–4 (1 = fine, 4 = coarse) layers: Layer[]; // ordered back-to-front; layers[0] MUST be BackgroundLayer } ``` **CRITICAL**: `layers[0]` must always be a `BackgroundLayer`. Without it the canvas is never cleared between frames — in animated mode, rays will smear and trail across the screen. --- ## Layer types ### BackgroundLayer ```ts interface BackgroundLayer { type: "background"; bgType: "solid" | "gradient" | "transparent"; bgColor: string; // hex — primary / top color bgColor2: string; // hex — secondary / bottom color (gradients only) bgGradientAngle: number; // degrees: 0=left-to-right, 90=bottom-to-top, 180=top-to-bottom } ``` Example: ```ts { type: "background", bgType: "solid", bgColor: "#000000", bgColor2: "#000000", bgGradientAngle: 180, } ``` Use `bgType: "transparent"` to overlay rays on existing page content without painting a background. ### RayLayer ```ts interface RayLayer { type: "rays"; direction: number; // compass bearing rays point toward (0=up, 90=right, 180=down, 270=left) spread: number; // angular width of the ray fan in degrees originX: number; // origin X as % of canvas width (can be <0 or >100 for off-screen) originY: number; // origin Y as % of canvas height (can be <0 or >100) rayCount: number; // number of rays (1–200; 10–30 typical) rayWidth: number; // ray width at origin in px (1–200) divergence: number; // tip-to-base width ratio (0.1–5; 1.0 = uniform beam) rayLength: number; // length as fraction of canvas diagonal (0.1–3) colorStart: string; // hex color at ray origin colorEnd: string; // hex color at ray tip (ignored when fadeToTransparent=true) opacity: number; // overall layer opacity 0–1 blendMode: BlendMode; fadeToTransparent: boolean; // fade tips to alpha=0 blur: number; // gaussian blur in px (0–100; 0 = no OffscreenCanvas pass) randomnessWidth: number; // per-ray width variation 0–100 randomnessLength: number; // per-ray length variation 0–100 randomnessAngle: number; // per-ray angle jitter 0–100 seed: number; // RNG seed — same seed = same ray layout every render } ``` Example: ```ts { type: "rays", direction: 180, spread: 100, originX: 50, originY: -15, rayCount: 30, rayWidth: 80, divergence: 1.6, rayLength: 1.2, colorStart: "#3b82f6", colorEnd: "#3b82f6", opacity: 0.2, blendMode: "screen", fadeToTransparent: true, blur: 12, randomnessWidth: 60, randomnessLength: 20, randomnessAngle: 15, seed: 42, } ``` ### HaloLayer ```ts interface HaloLayer { type: "halo"; originX: number; // center X as % of canvas width originY: number; // center Y as % of canvas height color: string; // hex color intensity: number; // peak opacity at center 0–1 size: number; // radius as fraction of canvas diagonal (0.01–2) blendMode: BlendMode; } ``` Example: ```ts { type: "halo", originX: 50, originY: 0, color: "#3b82f6", intensity: 0.3, size: 0.45, blendMode: "lighter", } ``` --- ## BlendMode ```ts type BlendMode = | "source-over" // normal alpha compositing — background-agnostic | "lighter" // additive — bright glowing effect (dark backgrounds only) | "screen" // soft additive glow (dark backgrounds only) | "overlay" // contrast boost — works on mid-tone and light backgrounds | "soft-light" // gentle contrast — works on most backgrounds | "hard-light"; // strong contrast ``` **Dark backgrounds**: use `"lighter"` or `"screen"` — additive modes make rays visible. **Light/white backgrounds**: `"screen"` and `"lighter"` become invisible. Use `"overlay"` or `"soft-light"` instead. Note: `"multiply"` is a valid browser composite operation but is **not** in the `BlendMode` type. If you need it, cast: `blendMode: "multiply" as BlendMode`. --- ## AnimParams ```ts interface AnimParams { speed: number; // time multiplier — 0=frozen, 1=normal, 2=double speed angleAmp: number; // ray angle oscillation 0–100 lengthAmp: number; // ray length oscillation 0–100 widthAmp: number; // ray width oscillation 0–100 haloAmp: number; // halo size oscillation 0–100 } // NOTE: there is NO opacityAmp field. TypeScript will reject it. ``` `animParams` changes take effect on the next animation frame without remounting the component. Use this to drive animation from real-time data: ```tsx const animParams = useMemo(() => ({ speed: 0.5 + (activityLevel / 100) * 2, angleAmp: 20 + (activityLevel / 100) * 60, lengthAmp: 10 + (activityLevel / 100) * 50, widthAmp: 10 + (activityLevel / 100) * 40, haloAmp: 20 + (activityLevel / 100) * 60, }), [activityLevel]); ``` --- ## Utility functions ```ts // Draw one static frame onto an existing canvas element drawScene( canvas: HTMLCanvasElement, scene: SceneConfig, time?: number, // elapsed seconds — 0 = rest position anim?: AnimParams, skipGrain?: boolean ): void // Export scene as PNG or JPEG Blob (for download / upload) exportScene( scene: SceneConfig, type: "image/png" | "image/jpeg", quality?: number // 0–1, default 0.95; ignored for PNG ): Promise // Export scene as CSS background-image lines (data URL embedded) buildSceneCssSnippet(scene: SceneConfig): Promise // Returns: background-image: url("data:image/png;base64,..."); // background-size: cover; background-position: center; background-repeat: no-repeat; ``` Export to PNG example: ```ts import { exportScene } from "godlights"; const blob = await exportScene(scene, "image/png"); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "rays.png"; a.click(); URL.revokeObjectURL(url); ``` CSS export example: ```ts import { buildSceneCssSnippet } from "godlights"; const css = await buildSceneCssSnippet(scene); document.getElementById("hero").style.cssText = css; ``` --- ## Default values ```ts import { DEFAULT_SCENE, // complete SceneConfig with bg + halo + rays DEFAULT_RAY_LAYER, // RayLayer with sensible defaults DEFAULT_HALO_LAYER, // HaloLayer with sensible defaults DEFAULT_BACKGROUND_LAYER, // BackgroundLayer (solid black) DEFAULT_ANIM_PARAMS, // { speed:1, angleAmp:50, lengthAmp:50, widthAmp:50, haloAmp:50 } BLEND_MODES, // { value: BlendMode, label: string }[] } from "godlights"; // Spread defaults and override only what you need const myLayer: RayLayer = { ...DEFAULT_RAY_LAYER, colorStart: "#ff6600", colorEnd: "#ff6600", }; ``` --- ## Full example — Next.js hero section ```tsx "use client"; import { useMemo } from "react"; import { GodLights } from "godlights"; import type { SceneConfig, AnimParams } from "godlights"; const scene: SceneConfig = { width: 1920, height: 1080, noise: 8, grainSize: 1, layers: [ { type: "background", bgType: "solid", bgColor: "#06060f", bgColor2: "#06060f", bgGradientAngle: 180, }, { type: "halo", originX: 50, originY: -5, color: "#a78bfa", intensity: 0.3, size: 0.5, blendMode: "lighter", }, { type: "rays", direction: 180, spread: 90, originX: 50, originY: -5, rayCount: 24, rayWidth: 70, divergence: 1.8, rayLength: 1.1, colorStart: "#a78bfa", colorEnd: "#a78bfa", opacity: 0.18, blendMode: "screen", fadeToTransparent: true, blur: 12, randomnessWidth: 60, randomnessLength: 20, randomnessAngle: 15, seed: 42, }, ], }; const animParams: AnimParams = { speed: 1, angleAmp: 40, lengthAmp: 25, widthAmp: 15, haloAmp: 40, // ❌ opacityAmp does NOT exist — do not add it }; export function Hero() { return (

Your content here

); } ``` --- ## Common mistakes checklist 1. ❌ **No BackgroundLayer** → rays smear in animation → add `{ type: "background", ... }` as `layers[0]` 2. ❌ **`opacityAmp` in animParams** → TypeScript error → remove it; valid keys: `speed angleAmp lengthAmp widthAmp haloAmp` 3. ❌ **`className="absolute"` for positioning** → overridden by inline style → use `style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }}` 4. ❌ **`blendMode: "screen"` on white/light background** → invisible rays → use `"overlay"` or `"soft-light"` 5. ❌ **Missing `"use client"` in Next.js App Router** → hydration error → add `"use client"` at top of file 6. ❌ **`scene` constructed inline in JSX** → unnecessary redraws → define outside component or wrap in `useMemo` 7. ❌ **`blur` value too high on multiple instances** → frame drops → keep `blur` ≤ 8 for decorative sections, `blur: 0` skips OffscreenCanvas entirely