/** * Scene lighting (spec: "Scene Lighting") — the manifest surface over * deck.gl's LightingEffect, resolving the backlog TODO ("Lighting/effects * manifest surface"). Attributes on , the basemap= precedent: * singleton scene state as attributes gets undo/redo for free (attribute * history) and live switching through the same MutationObserver path. * * * * * * The sun is ALWAYS a DirectionalLight driven by azimuth/elevation; * `lighting-sun-date` is sugar that computes az/el from solar position at * the map center when lighting is applied (deliberately NOT deck's * experimental `_SunLight`, which recomputes per frame from the viewport — * an attribute-declared scene should be deterministic, and the underscore * API is upgrade churn). Absent `lighting` = deck's default lights — * today's behavior, so the whole surface is additive. */ import { AmbientLight, _CameraLight as CameraLight, DirectionalLight, LightingEffect } from "@deck.gl/core"; export interface LightingIR { /** Preset the values were seeded from (validation/UI echo; "custom" for a fully hand-tuned scene). */ preset: LightingPresetName; /** Ambient intensity — always-on fill. */ ambient: number; /** Sun (directional) intensity; 0 omits the sun light entirely. */ sun: number; /** Sun compass bearing, ° clockwise from north. */ sunAzimuth: number; /** Sun height above the horizon, ° (0 = horizon, 90 = zenith). */ sunElevation: number; /** Camera-following fill intensity (model inspection); 0 omits it. */ camera: number; /** Epoch ms — when set, az/el are recomputed from solar position at apply time. */ sunDate?: number; } export type LightingPresetName = "daylight" | "studio" | "flat" | "custom"; export declare const LIGHTING_PRESET_NAMES: readonly ["daylight", "studio", "flat", "custom"]; export declare function isLightingPreset(name: string): name is LightingPresetName; /** Programmatic twin of the lighting-* attributes (MapControllerOptions.lighting / setLighting). */ export interface LightingOptions { preset?: LightingPresetName; ambient?: number; sun?: number; sunAzimuth?: number; sunElevation?: number; camera?: number; /** Epoch ms or ISO 8601 — the lighting-sun-date twin. */ sunDate?: number | string; } /** Preset seeds values; explicit fields override individual seeds; sunDate (resolved at apply time) wins over az/el. */ export declare function resolveLighting(options: LightingOptions): LightingIR; /** * `lighting*` attributes → IR. Returns null when `lighting` itself is * absent (deck default lights; stray lighting-* overrides without it are * inert — validation warns). Malformed numbers fall back to the preset seed * (validation flags them; the live path must still render something). */ export declare function parseLightingAttrs(getAttr: (name: string) => string | null): LightingIR | null; /** * Solar azimuth/elevation at a timestamp + location, in the manual-sun * convention (azimuth ° CW from north, elevation ° above horizon). The * standard suncalc derivation (the same math deck's `_SunLight` uses via * @math.gl/sun): solar azimuth measured south→west, so matching the * DirectionalLight convention is `azimuth = solar + 180°`. Below-horizon * sun clamps to the horizon — a flat scene can't render a sun beneath it. */ export declare function solarAzElDegrees(timestamp: number, latitude: number, longitude: number): { azimuth: number; elevation: number; }; /** * IR → the named lights map a LightingEffect is constructed from — * separated so tests can assert composition without reaching into * LightingEffect's private fields. The ambient light is always present; * sun and camera lights only at intensity > 0 (deck renders a 0-intensity * light as subtle noise, not nothing). `center` (current map center) feeds * the sunDate → az/el resolution. */ export declare function buildLights(ir: LightingIR, center?: [longitude: number, latitude: number]): Record; /** IR → deck.gl LightingEffect (see buildLights for the composition rules). */ export declare function buildLightingEffect(ir: LightingIR, center?: [longitude: number, latitude: number]): LightingEffect;