lecodes-cli 2.0.9 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +151 -94
- package/package.json +8 -8
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/VERSION.json +3 -3
- package/runtime/web/player.js +2 -2
- package/runtime/web-lite/assets/{index-3CbsYWmo.js → index-BttBnvIf.js} +1 -1
- package/runtime/web-lite/assets/scene3d-D8LdhX0V.js +888 -0
- package/runtime/web-lite/features.json +2 -2
- package/runtime/web-lite/lite.js +2 -2
- package/src/dev/webRunner.ts +1 -1
- package/runtime/web-lite/assets/scene3d-CX7MAqmN.js +0 -866
package/runtime/sdk-types.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"global.d.ts":"// AUTO-GENERATED by build-types.ts. The import-free type surface for le.codes projects:\n// every SDK global declared ambiently, so user code uses Scene / Sprite / UIScreen / … \n// with no imports and full editor autocomplete.\n\nimport type * as SDK from \"./types/inject\"\nimport type * as SERVER from \"./types/server/inject\"\n\ndeclare global {\n const ARScene: typeof SDK.ARScene\n const AnimationClip: typeof SDK.AnimationClip\n const Animator: typeof SDK.Animator\n const Aspect: typeof SDK.Aspect\n const AudioPlayer: typeof SDK.AudioPlayer\n const AudioSource: typeof SDK.AudioSource\n const AudioZone: typeof SDK.AudioZone\n const Autotile2D: typeof SDK.Autotile2D\n const Bitmap: typeof SDK.Bitmap\n const Bus: typeof SDK.Bus\n const Camera: typeof SDK.Camera\n const Camera2D: typeof SDK.Camera2D\n const CameraFollow: typeof SDK.CameraFollow\n const CameraPlace: typeof SDK.CameraPlace\n const CameraView: typeof SDK.CameraView\n const Canvas: typeof SDK.Canvas\n const CharacterController: typeof SDK.CharacterController\n const CharacterController2D: typeof SDK.CharacterController2D\n const ClickEvent: typeof SDK.ClickEvent\n const Color: typeof SDK.Color\n const DateValue: typeof SDK.DateValue\n const DecalSet: typeof SDK.DecalSet\n const DecalTrail: typeof SDK.DecalTrail\n const DynamicBone: typeof SDK.DynamicBone\n const DynamicBoneCollider: typeof SDK.DynamicBoneCollider\n const Feet: typeof SDK.Feet\n const File: typeof SDK.File\n const Foliage: typeof SDK.Foliage\n const FollowPath: typeof SDK.FollowPath\n const FormData: typeof SDK.FormData\n const Geolocation: typeof SDK.Geolocation\n const Geometry: typeof SDK.Geometry\n const Gizmos: typeof SDK.Gizmos\n const IK: typeof SDK.IK\n const Input: typeof SDK.Input\n const InputChannel: typeof SDK.InputChannel\n const InspectorUI: typeof SDK.InspectorUI\n const InstancedMesh: typeof SDK.InstancedMesh\n const Layer: typeof SDK.Layer\n const Level: typeof SDK.Level\n const Light: typeof SDK.Light\n const Lightmap: typeof SDK.Lightmap\n const Locomotion: typeof SDK.Locomotion\n const LongPressEvent: typeof SDK.LongPressEvent\n const LookAt: typeof SDK.LookAt\n const Loop: typeof SDK.Loop\n const MapView: typeof SDK.MapView\n const Mat4: typeof SDK.Mat4\n const Material: typeof SDK.Material\n const MaterialHandle: typeof SDK.MaterialHandle\n const Mathf: typeof SDK.Mathf\n const Mesh: typeof SDK.Mesh\n const Model: typeof SDK.Model\n const MouseEnterEvent: typeof SDK.MouseEnterEvent\n const MoveTo: typeof SDK.MoveTo\n const NativeView: typeof SDK.NativeView\n const NavAgent: typeof SDK.NavAgent\n const NavCrowd: typeof SDK.NavCrowd\n const NavMesh: typeof SDK.NavMesh\n const Net: typeof SDK.Net\n const NetEntity: typeof SDK.NetEntity\n const NetPlayer: typeof SDK.NetPlayer\n const Node: typeof SDK.Node\n const Node2D: typeof SDK.Node2D\n const Noise: typeof SDK.Noise\n const OneWay2D: typeof SDK.OneWay2D\n const Particles: typeof SDK.Particles\n const Physics: typeof SDK.Physics\n const Physics2D: typeof SDK.Physics2D\n const PhysicsGroup2D: typeof SDK.PhysicsGroup2D\n const Plane: typeof SDK.Plane\n const PlayAnimation: typeof SDK.PlayAnimation\n const Playback: typeof SDK.Playback\n const Presentable: typeof SDK.Presentable\n const Push: typeof SDK.Push\n const QRScanner: typeof SDK.QRScanner\n const Quat: typeof SDK.Quat\n const REVERB_PRESETS: typeof SDK.REVERB_PRESETS\n const Ragdoll: typeof SDK.Ragdoll\n const Ray: typeof SDK.Ray\n const Replicated: typeof SDK.Replicated\n const Router: typeof SDK.Router\n const RpcError: typeof SDK.RpcError\n const Scene: typeof SDK.Scene\n const Scene2D: typeof SDK.Scene2D\n const Scene2dHandle: typeof SDK.Scene2dHandle\n const SceneAudio: typeof SDK.SceneAudio\n const SceneHandle: typeof SDK.SceneHandle\n const Service: typeof SDK.Service\n const Shape: typeof SDK.Shape\n const Shape2D: typeof SDK.Shape2D\n const Sound: typeof SDK.Sound\n const Spin: typeof SDK.Spin\n const Sprite: typeof SDK.Sprite\n const SpriteAnimation: typeof SDK.SpriteAnimation\n const SpriteSheet: typeof SDK.SpriteSheet\n const StateMachine: typeof SDK.StateMachine\n const SvgSource: typeof SDK.SvgSource\n const System: typeof SDK.System\n const Terrain: typeof SDK.Terrain\n const Texture: typeof SDK.Texture\n const Texture2D: typeof SDK.Texture2D\n const Tilemap: typeof SDK.Tilemap\n const Tileset: typeof SDK.Tileset\n const Time: typeof SDK.Time\n const Timeline: typeof SDK.Timeline\n const Tire: typeof SDK.Tire\n const TouchStartEvent: typeof SDK.TouchStartEvent\n const Trail: typeof SDK.Trail\n const Trigger: typeof SDK.Trigger\n const Trigger2D: typeof SDK.Trigger2D\n const UIBottomSheet: typeof SDK.UIBottomSheet\n const UIBox: typeof SDK.UIBox\n const UIButton: typeof SDK.UIButton\n const UIColumn: typeof SDK.UIColumn\n const UIImage: typeof SDK.UIImage\n const UIInput: typeof SDK.UIInput\n const UIModal: typeof SDK.UIModal\n const UIOverlay: typeof SDK.UIOverlay\n const UIPager: typeof SDK.UIPager\n const UIPopover: typeof SDK.UIPopover\n const UIRow: typeof SDK.UIRow\n const UIScreen: typeof SDK.UIScreen\n const UIScrollable: typeof SDK.UIScrollable\n const UISpacer: typeof SDK.UISpacer\n const UITabs: typeof SDK.UITabs\n const UIText: typeof SDK.UIText\n const UITextArea: typeof SDK.UITextArea\n const UIVideo: typeof SDK.UIVideo\n const UIVirtualizedList: typeof SDK.UIVirtualizedList\n const UIWidget: typeof SDK.UIWidget\n const VRScene: typeof SDK.VRScene\n const Vec2: typeof SDK.Vec2\n const Vec3: typeof SDK.Vec3\n const Vehicle: typeof SDK.Vehicle\n const VideoPlayer: typeof SDK.VideoPlayer\n const Voice: typeof SDK.Voice\n const Warp: typeof SDK.Warp\n const WebSocket: typeof SDK.WebSocket\n const Wheel: typeof SDK.Wheel\n const __UIBox: typeof SDK.__UIBox\n const __UIButton: typeof SDK.__UIButton\n const __UIColumn: typeof SDK.__UIColumn\n const __UIRow: typeof SDK.__UIRow\n const __UIScreen: typeof SDK.__UIScreen\n const __UIScrollable: typeof SDK.__UIScrollable\n const __UIWidget: typeof SDK.__UIWidget\n const __channel: typeof SDK.__channel\n const __compOp: typeof SDK.__compOp\n const __compWrite: typeof SDK.__compWrite\n const __rpc: typeof SDK.__rpc\n const __serverOnly: typeof SDK.__serverOnly\n const __uiMap: typeof SDK.__uiMap\n const animate: typeof SDK.animate\n const app: typeof SDK.app\n const audio: typeof SDK.audio\n const cells: typeof SDK.cells\n const clipboard: typeof SDK.clipboard\n const colorCurve: typeof SDK.colorCurve\n const computed: typeof SDK.computed\n const cubicBezier: typeof SDK.cubicBezier\n const curve: typeof SDK.curve\n const date: typeof SDK.date\n const defineMaterial: typeof SDK.defineMaterial\n const defineScene: typeof SDK.defineScene\n const defineScene2d: typeof SDK.defineScene2d\n const defineSpriteSheet: typeof SDK.defineSpriteSheet\n const defineStates: typeof SDK.defineStates\n const defineTabs: typeof SDK.defineTabs\n const defineTileset: typeof SDK.defineTileset\n const device: typeof SDK.device\n const easeIn: typeof SDK.easeIn\n const easeInOut: typeof SDK.easeInOut\n const easeOut: typeof SDK.easeOut\n const effect: typeof SDK.effect\n const encodeCells: typeof SDK.encodeCells\n const fetch: typeof SDK.fetch\n const fetchLocal: typeof SDK.fetchLocal\n const files: typeof SDK.files\n const flipX: typeof SDK.flipX\n const isRawCell: typeof SDK.isRawCell\n const localStorage: typeof SDK.localStorage\n const make: typeof SDK.make\n const openFilePicker: typeof SDK.openFilePicker\n const openURL: typeof SDK.openURL\n const packTile: typeof SDK.packTile\n const rawCell: typeof SDK.rawCell\n const rawIndex: typeof SDK.rawIndex\n const ref: typeof SDK.ref\n const registerEditorTool: typeof SDK.registerEditorTool\n const registerEditorWindow: typeof SDK.registerEditorWindow\n const registerFont: typeof SDK.registerFont\n const resolveTire: typeof SDK.resolveTire\n const rot180: typeof SDK.rot180\n const rot270: typeof SDK.rot270\n const rot90: typeof SDK.rot90\n const share: typeof SDK.share\n const signal: typeof SDK.signal\n const theme: typeof SDK.theme\n const tileFlip: typeof SDK.tileFlip\n const tileIndex: typeof SDK.tileIndex\n const tileOriented: typeof SDK.tileOriented\n const tileTurns: typeof SDK.tileTurns\n const toast: typeof SDK.toast\n const use: typeof SDK.use\n type ARScene<T extends ARMode = \"default\"> = SDK.ARScene<T>\n type ActiveClip = SDK.ActiveClip\n type AeroConfig = SDK.AeroConfig\n type AnimateOptions<T extends AnimateValue> = SDK.AnimateOptions<T>\n type AnimateOut<T> = SDK.AnimateOut<T>\n type AnimateValue = SDK.AnimateValue\n type Animation = SDK.Animation\n type AnimationClip = SDK.AnimationClip\n type Animator = SDK.Animator\n type AppState = SDK.AppState\n type Aspect<K extends string, P = Node, E extends EventMap = {}> = SDK.Aspect<K, P, E>\n type AspectEntry<A extends Aspect<any, any> = Aspect<any, any>> = SDK.AspectEntry<A>\n type AudioCone = SDK.AudioCone\n type AudioPlayer = SDK.AudioPlayer\n type AudioSource = SDK.AudioSource\n type AudioStats = SDK.AudioStats\n type AudioZone = SDK.AudioZone\n type AutoPaintRules = SDK.AutoPaintRules\n type Autotile2D = SDK.Autotile2D\n type Bitmap = SDK.Bitmap\n type BlendMember = SDK.BlendMember\n type BlendPosition = SDK.BlendPosition\n type BlockEntry = SDK.BlockEntry\n type Bus = SDK.Bus\n type Camera = SDK.Camera\n type Camera2D = SDK.Camera2D\n type Camera2dNodeDef = SDK.Camera2dNodeDef\n type CameraFacing = SDK.CameraFacing\n type CameraFollow = SDK.CameraFollow\n type CameraMove = SDK.CameraMove\n type CameraNodeDef = SDK.CameraNodeDef\n type CameraPlace = SDK.CameraPlace\n type CameraView = SDK.CameraView\n type Canvas = SDK.Canvas\n type CellsData = SDK.CellsData\n type ChannelSubscription = SDK.ChannelSubscription\n type CharacterController = SDK.CharacterController\n type CharacterController2D = SDK.CharacterController2D\n type ClickEvent<T = any> = SDK.ClickEvent<T>\n type ClipAlign = SDK.ClipAlign\n type ClipCycle = SDK.ClipCycle\n type ClipDef = SDK.ClipDef\n type ClipEventHandler = SDK.ClipEventHandler\n type ClipInfo = SDK.ClipInfo\n type ClipKey<V> = SDK.ClipKey<V>\n type ClipTrackDef = SDK.ClipTrackDef\n type CompAxis = SDK.CompAxis\n type CompWriter = SDK.CompWriter\n type Computed<T> = SDK.Computed<T>\n type ConformOptions = SDK.ConformOptions\n type DateInput = SDK.DateInput\n type DateValue = SDK.DateValue\n type DecalOptions = SDK.DecalOptions\n type DecalPlacement = SDK.DecalPlacement\n type DecalSet = SDK.DecalSet\n type DecalSetOptions = SDK.DecalSetOptions\n type DecalSpawnOptions = SDK.DecalSpawnOptions\n type DecalTrail = SDK.DecalTrail\n type DecalTrailOptions = SDK.DecalTrailOptions\n type DifferentialMode = SDK.DifferentialMode\n type DismissOptions = SDK.DismissOptions\n type Displacement = SDK.Displacement\n type DriveLayout = SDK.DriveLayout\n type DynamicBone = SDK.DynamicBone\n type DynamicBoneCollider = SDK.DynamicBoneCollider\n type DynamicBoneColliders = SDK.DynamicBoneColliders\n type DynamicBoneCurve = SDK.DynamicBoneCurve\n type DynamicBoneFloor = SDK.DynamicBoneFloor\n type EasingInput = SDK.EasingInput\n type EchoParams = SDK.EchoParams\n type EdgeSlot = SDK.EdgeSlot\n type EditorApi = SDK.EditorApi\n type EditorRayHit = SDK.EditorRayHit\n type EditorToolHooks = SDK.EditorToolHooks\n type EditorWindowFn = SDK.EditorWindowFn\n type EngineConfig = SDK.EngineConfig\n type EventMap = SDK.EventMap\n type Feet = SDK.Feet\n type FeetOptions = SDK.FeetOptions\n type FetchResponse = SDK.FetchResponse\n type FieldMeta<T = unknown> = SDK.FieldMeta<T>\n type File = SDK.File\n type FileData = SDK.FileData\n type FillBlock = SDK.FillBlock\n type FitOptions = SDK.FitOptions\n type FoliageOptions = SDK.FoliageOptions\n type FoliageWind = SDK.FoliageWind\n type FollowPath = SDK.FollowPath\n type FootState = SDK.FootState\n type FormData = SDK.FormData\n type Gait = SDK.Gait\n type GamepadAxisName = SDK.GamepadAxisName\n type GamepadState = SDK.GamepadState\n type GeoOptions = SDK.GeoOptions\n type GeoPosition = SDK.GeoPosition\n type GeoWatch = SDK.GeoWatch\n type Geometry = SDK.Geometry\n type GizmoAnchor = SDK.GizmoAnchor\n type GizmoStyle = SDK.GizmoStyle\n type HapticStyle = SDK.HapticStyle\n type IKLookAt = SDK.IKLookAt\n type IKTwoBone = SDK.IKTwoBone\n type InputEventName = SDK.InputEventName\n type InputGamepadEvent = SDK.InputGamepadEvent\n type InputKeyEvent = SDK.InputKeyEvent\n type InspectorUI = SDK.InspectorUI\n type InstanceTransform = SDK.InstanceTransform\n type InstancedMesh = SDK.InstancedMesh\n type KneeAxisReport = SDK.KneeAxisReport\n type Layer = SDK.Layer\n type LayerOptions = SDK.LayerOptions\n type LevelBuild = SDK.LevelBuild\n type LevelCollider = SDK.LevelCollider\n type LevelGridOptions = SDK.LevelGridOptions\n type LevelLineOptions = SDK.LevelLineOptions\n type LevelPlaceOptions = SDK.LevelPlaceOptions\n type LevelRingOptions = SDK.LevelRingOptions\n type LevelScatterOptions = SDK.LevelScatterOptions\n type LevelSpot = SDK.LevelSpot\n type Light = SDK.Light\n type LightDef = SDK.LightDef\n type Lightmap = SDK.Lightmap\n type LineLayer = SDK.LineLayer\n type LineLayerOptions = SDK.LineLayerOptions\n type LitMaterialDef = SDK.LitMaterialDef\n type LngLat = SDK.LngLat\n type LoadedScene<D extends SceneDef> = SDK.LoadedScene<D>\n type LoadedScene2d<D extends Scene2dDef> = SDK.LoadedScene2d<D>\n type Locale = SDK.Locale\n type Locomotion = SDK.Locomotion\n type LocomotionClip = SDK.LocomotionClip\n type LocomotionEvents = SDK.LocomotionEvents\n type LocomotionSet = SDK.LocomotionSet\n type LocomotionState = SDK.LocomotionState\n type LocomotionTuning = SDK.LocomotionTuning\n type LodMode = SDK.LodMode\n type LongPressEvent<T = any> = SDK.LongPressEvent<T>\n type LookAt = SDK.LookAt\n type Loop = SDK.Loop\n type LoopDef = SDK.LoopDef\n type LoopOptions = SDK.LoopOptions\n type MakeEntry<A extends Record<string, unknown> = Record<string, unknown>> = SDK.MakeEntry<A>\n type MapCamera = SDK.MapCamera\n type MapOptions = SDK.MapOptions\n type MapPaddingValues = SDK.MapPaddingValues\n type MapStyle = SDK.MapStyle\n type MapStyleName = SDK.MapStyleName\n type MapTap = SDK.MapTap\n type MapView = SDK.MapView\n type MarkerItem = SDK.MarkerItem\n type MarkerLayer = SDK.MarkerLayer\n type MarkerLayerOptions = SDK.MarkerLayerOptions\n type MarkerTap = SDK.MarkerTap\n type Mat4 = SDK.Mat4\n type Material = SDK.Material\n type MaterialData = SDK.MaterialData\n type MaterialDef = SDK.MaterialDef\n type MaterialHandle = SDK.MaterialHandle\n type MaterialParamValue = SDK.MaterialParamValue\n type Mesh = SDK.Mesh\n type MeshDef = SDK.MeshDef\n type Model = SDK.Model\n type MotionOptions = SDK.MotionOptions\n type MouseEnterEvent<T = any> = SDK.MouseEnterEvent<T>\n type MoveTo = SDK.MoveTo\n type NativeView = SDK.NativeView\n type NavAgent = SDK.NavAgent\n type NavAgentAvoidance = SDK.NavAgentAvoidance\n type NavAgentDrive = SDK.NavAgentDrive\n type NavAgentEvents = SDK.NavAgentEvents\n type NavAgentSize = SDK.NavAgentSize\n type NavAgentState = SDK.NavAgentState\n type NavCrowd = SDK.NavCrowd\n type NavMesh = SDK.NavMesh\n type NavMeshInfo = SDK.NavMeshInfo\n type NavMeshLoadOptions = SDK.NavMeshLoadOptions\n type NavPath = SDK.NavPath\n type NavQueryOptions = SDK.NavQueryOptions\n type NavRaycastHit = SDK.NavRaycastHit\n type NetCorrection = SDK.NetCorrection\n type NetEntity<S extends object = any> = SDK.NetEntity<S>\n type NetEvents = SDK.NetEvents\n type NetInput<T extends object = any> = SDK.NetInput<T>\n type NetKind<S extends object = any> = SDK.NetKind<S>\n type NetLaunch = SDK.NetLaunch\n type NetMessage<T = unknown> = SDK.NetMessage<T>\n type NetPlayer = SDK.NetPlayer\n type NetRole = SDK.NetRole\n type NetStatus = SDK.NetStatus\n type NetTransform = SDK.NetTransform\n type Node = SDK.Node\n type Node2D = SDK.Node2D\n type Noise = SDK.Noise\n type OneWay2D = SDK.OneWay2D\n type OrientationLock = SDK.OrientationLock\n type Particles = SDK.Particles\n type PatchMaterial = SDK.PatchMaterial\n type PatchSlots = SDK.PatchSlots\n type PathMaterial = SDK.PathMaterial\n type Physics = SDK.Physics\n type Physics2D = SDK.Physics2D\n type PhysicsGroup2D = SDK.PhysicsGroup2D\n type Plane = SDK.Plane\n type PlayAnimation = SDK.PlayAnimation\n type PlayOptions = SDK.PlayOptions\n type PlaySoundOptions = SDK.PlaySoundOptions\n type Playback = SDK.Playback\n type Point = SDK.Point\n type PresentOptions = SDK.PresentOptions\n type Presentable = SDK.Presentable\n type PushEvent = SDK.PushEvent\n type PushPayload = SDK.PushPayload\n type PushRegisterOptions = SDK.PushRegisterOptions\n type PushStatus = SDK.PushStatus\n type QRScanner = SDK.QRScanner\n type Quat = SDK.Quat\n type Ragdoll = SDK.Ragdoll\n type RagdollActivateOptions = SDK.RagdollActivateOptions\n type RagdollDeactivateOptions = SDK.RagdollDeactivateOptions\n type RagdollFacing = SDK.RagdollFacing\n type RagdollHinge = SDK.RagdollHinge\n type RagdollHitOptions = SDK.RagdollHitOptions\n type RagdollPart = SDK.RagdollPart\n type Ray = SDK.Ray\n type Replicated = SDK.Replicated\n type ReverbParams = SDK.ReverbParams\n type ReverbPreset = SDK.ReverbPreset\n type RibbonOptions = SDK.RibbonOptions\n type Rolloff = SDK.Rolloff\n type RpcError = SDK.RpcError\n type Scene = SDK.Scene\n type Scene2D = SDK.Scene2D\n type Scene2dDef = SDK.Scene2dDef\n type Scene2dEnv = SDK.Scene2dEnv\n type Scene2dHandle<D extends Scene2dDef = Scene2dDef> = SDK.Scene2dHandle<D>\n type Scene2dNodeDef = SDK.Scene2dNodeDef\n type SceneAudio = SDK.SceneAudio\n type SceneDef = SDK.SceneDef\n type SceneHandle<D extends SceneDef = SceneDef> = SDK.SceneHandle<D>\n type SceneInstance<D extends SceneDef> = SDK.SceneInstance<D>\n type SceneNodeDef = SDK.SceneNodeDef\n type SculptOptions = SDK.SculptOptions\n type Service = SDK.Service\n type ShaderMaterialDef = SDK.ShaderMaterialDef\n type Shape = SDK.Shape\n type Shape2D = SDK.Shape2D\n type SheetSprite = SDK.SheetSprite\n type Signal<T> = SDK.Signal<T>\n type Sound = SDK.Sound\n type SoundOptions = SDK.SoundOptions\n type SpatialOptions = SDK.SpatialOptions\n type Spin = SDK.Spin\n type Sprite = SDK.Sprite\n type SpriteAnimation = SDK.SpriteAnimation\n type SpriteMakeOptions = SDK.SpriteMakeOptions\n type SpriteSheet = SDK.SpriteSheet\n type SpriteSheetDef = SDK.SpriteSheetDef\n type SpriteSourceDef = SDK.SpriteSourceDef\n type StateDef<C> = SDK.StateDef<C>\n type StateGuard<C> = SDK.StateGuard<C>\n type StateHandler<C> = SDK.StateHandler<C>\n type StateMachine<C> = SDK.StateMachine<C>\n type StateMachineEvents = SDK.StateMachineEvents\n type StatesDef<C> = SDK.StatesDef<C>\n type SteeringConfig = SDK.SteeringConfig\n type SteeringDriver = SDK.SteeringDriver\n type SteeringFeedback = SDK.SteeringFeedback\n type StepHandler = SDK.StepHandler\n type StepWarpOptions = SDK.StepWarpOptions\n type StopOptions = SDK.StopOptions\n type StoredFile = SDK.StoredFile\n type StoredImage = SDK.StoredImage\n type System<K extends string, S extends SystemHost = Scene, E extends EventMap = {}> = SDK.System<K, S, E>\n type SystemHost = SDK.SystemHost\n type TabDef = SDK.TabDef\n type TabsHandle<T extends Record<string, TabDef>> = SDK.TabsHandle<T>\n type Terrain = SDK.Terrain\n type TerrainHit = SDK.TerrainHit\n type TerrainLayer = SDK.TerrainLayer\n type TerrainOptions = SDK.TerrainOptions\n type TerrainRegion = SDK.TerrainRegion\n type TerrainSnapshot = SDK.TerrainSnapshot\n type Texture = SDK.Texture\n type Texture2D = SDK.Texture2D\n type TextureLoadOptions = SDK.TextureLoadOptions\n type ThemeAccessors<T> = SDK.ThemeAccessors<T>\n type ThemeRoles = SDK.ThemeRoles\n type ThemeValues = SDK.ThemeValues\n type TileBlock = SDK.TileBlock\n type TileMaterial = SDK.TileMaterial\n type TilePart = SDK.TilePart\n type Tilemap = SDK.Tilemap\n type TilemapSourceDef = SDK.TilemapSourceDef\n type Tileset = SDK.Tileset\n type TilesetDef = SDK.TilesetDef\n type Timeline = SDK.Timeline\n type TimelineAddOptions = SDK.TimelineAddOptions\n type TimelineOptions = SDK.TimelineOptions\n type TimelinePosition = SDK.TimelinePosition\n type Tire = SDK.Tire\n type TouchStartEvent<T = any> = SDK.TouchStartEvent<T>\n type Trail = SDK.Trail\n type Transition = SDK.Transition\n type TransitionName = SDK.TransitionName\n type TransitionPose = SDK.TransitionPose\n type TransitionSpec = SDK.TransitionSpec\n type TrianglePick = SDK.TrianglePick\n type Trigger = SDK.Trigger\n type Trigger2D = SDK.Trigger2D\n type TweenMeta = SDK.TweenMeta\n type UIBottomSheet = SDK.UIBottomSheet\n type UIBottomSheetStyle = SDK.UIBottomSheetStyle\n type UIBox = SDK.UIBox\n type UIButton = SDK.UIButton\n type UIButtonStyle = SDK.UIButtonStyle\n type UIColumn = SDK.UIColumn\n type UIContainerStyle = SDK.UIContainerStyle\n type UIImage = SDK.UIImage\n type UIImageStyle = SDK.UIImageStyle\n type UIInput = SDK.UIInput\n type UIInputStyle = SDK.UIInputStyle\n type UIModal = SDK.UIModal\n type UIModalStyle = SDK.UIModalStyle\n type UINativeViewStyle = SDK.UINativeViewStyle\n type UINode = SDK.UINode\n type UINodeChild = SDK.UINodeChild\n type UIPager = SDK.UIPager\n type UIPagerStyle = SDK.UIPagerStyle\n type UIPopover = SDK.UIPopover\n type UIPopoverStyle = SDK.UIPopoverStyle\n type UIRow = SDK.UIRow\n type UIScreen = SDK.UIScreen\n type UIScreenStyle = SDK.UIScreenStyle\n type UIScrollable = SDK.UIScrollable\n type UIScrollableStyle = SDK.UIScrollableStyle\n type UISpacer = SDK.UISpacer\n type UISpacerStyle = SDK.UISpacerStyle\n type UITabDef = SDK.UITabDef\n type UITabs = SDK.UITabs\n type UIText = SDK.UIText\n type UITextArea = SDK.UITextArea\n type UITextStyle = SDK.UITextStyle\n type UIVideo = SDK.UIVideo\n type UIVideoStyle = SDK.UIVideoStyle\n type UIVirtualizedList<T = unknown> = SDK.UIVirtualizedList<T>\n type UIWidget = SDK.UIWidget\n type UIWidgetContent = SDK.UIWidgetContent\n type UIWidgetStyle = SDK.UIWidgetStyle\n type Unit = SDK.Unit\n type UnlitMaterialDef = SDK.UnlitMaterialDef\n type UserLocationOptions = SDK.UserLocationOptions\n type VRScene = SDK.VRScene\n type Vec2 = SDK.Vec2\n type Vec3 = SDK.Vec3\n type Vehicle = SDK.Vehicle\n type VideoPlayer = SDK.VideoPlayer\n type Voice = SDK.Voice\n type VoiceEvents = SDK.VoiceEvents\n type Warp = SDK.Warp\n type WarpOptions = SDK.WarpOptions\n type WebSocket = SDK.WebSocket\n type Wheel = SDK.Wheel\n type WheelSuspension = SDK.WheelSuspension\n type With<N, A extends Aspect<any, any, any>> = SDK.With<N, A>\n // ---- server globals (available in *.server.ts; using them in client code is a build error) ----\n const ApiError: typeof SERVER.ApiError\n const channel: typeof SERVER.channel\n const defineDb: typeof SERVER.defineDb\n const model: typeof SERVER.model\n const ref: typeof SERVER.ref\n const request: typeof SERVER.request\n const t: typeof SERVER.t\n type ApiError = SERVER.ApiError\n type StoredFile = SERVER.StoredFile\n type StoredImage = SERVER.StoredImage\n}\n\nexport {}\n","host.d.ts":"// JS-runtime globals provided by the host engine (web viewer / desktop / iOS), NOT by the SDK.\n// Declared only so SDK and user code type-check — never bundled or injected.\n\ndeclare global {\n function setTimeout(handler: (...args: any[]) => void, timeout?: number): number\n function setInterval(handler: (...args: any[]) => void, timeout?: number): number\n function clearTimeout(id: number): void\n function clearInterval(id: number): void\n /** Per-frame loop, driven by the host (viewer RAF / desktop runTick). `dt` is **seconds** since\n * the previous frame. */\n function setLoop(handler: (dt: number) => void): number\n function clearLoop(id: number): void\n\n /** π/180 — substituted at compile time (bundler `define`). */\n var DEG2RAD: number\n /** 180/π — substituted at compile time (bundler `define`). */\n var RAD2DEG: number\n\n /** Compile-time boolean: `true` in scene-editor bundles, `false` (const-folded + DCE'd) in\n * shipped ones — `if (EDITOR) { … }` costs zero bytes in production. `*.editor.ts` files are\n * the file-level form. */\n var EDITOR: boolean\n\n var console: {\n log(...data: any[]): void\n warn(...data: any[]): void\n info(...data: any[]): void\n error(...data: any[]): void\n }\n\n /** Compile-time macro: `asset('./data.json')` yields the file's PARSED data (a .json file is\n * data, not code — it ships inside the bundle). See the `string` overload for everything else. */\n function asset(path: `${string}.json`): any\n /** Compile-time macro: `asset('./logo.svg')` yields the file as an SVG image source — for\n * `UIImage(...)` and `bgImage`. */\n function asset(path: `${string}.svg`): { readonly svg: string, tintColor: string | null }\n /** Compile-time macro: `asset('./hero.png')` is desugared by the bundler into the module import\n * for that resource. The file must exist — a path that resolves to nothing fails the compile\n * (`asset not found: ./hero.png (main.ts:3)`); there is no runtime fallback. Calls inside\n * comments and string literals are text, not macros. */\n function asset(path: string): string\n\n /** Compile-time macro: installs a font and returns its family name — using a font IS declaring\n * it. A registry id (`font(\"manrope\")`) resolves against the font registry; a project path\n * (`font(\"./fonts/Brand.ttf\")`) reads family/weight/italic from the file itself. `opts`\n * narrows/extends the face set (default: the family's standard weights). String-literal\n * argument only. No awaiting — faces load with app boot and the host holds first paint for\n * them. */\n function font(id: string, opts?: { weights?: number[], italic?: boolean }): string\n\n /** Compile-time macro: resolves one icon from the icon registry at build time and inlines it as\n * an image source for `UIImage(...)` — offline, identical on every host. `id` is `\"pack:name\"`\n * (e.g. `\"lucide:bell\"`), string literal only. Recolor via `{ color }`: a hex LITERAL is baked\n * into the SVG at compile time, a token/expression is applied as a tint (as is the `tintColor`\n * style prop). */\n function assetIcon(id: string, opts?: { color?: string }): { readonly svg: string, tintColor: string | null }\n\n /** Type-only editor convenience: the style object type of a UI element. `Style<UIButton>` (or\n * `Style<typeof myButton>`) is what you'd pass to `el.style(...)` — for typing reusable style\n * presets. Deliberately no `Partial<>` wrapper: every style prop is already optional, and\n * Partial over ClassStyles' `$`-index signature adds `| undefined`, breaking assignability back\n * into `.style(...)`. Round-trip guarded by sdk/tests/ui/types.test.ts. */\n type Style<T> = T extends { style: (s: infer S) => any } ? S : never\n}\n\nexport {}\n","types/animate/bezier.d.ts":"import type { Easing } from \"./easings\";\nexport declare function cubicBezier(mX1: number, mY1: number, mX2: number, mY2: number): Easing;\n","types/animate/easings.d.ts":"export type Easing = (v: number) => number;\nexport type EasingModifier = (easing: Easing) => Easing;\nexport declare function linear(p: number): number;\nexport declare function bounceOut(p: number): number;\nexport declare function bounceInOut(p: number): number;\nexport declare function reverseEasing(easing: Easing): Easing;\nexport declare function mirrorEasing(easing: Easing): Easing;\nexport declare function createExpoIn(power: number): Easing;\nexport declare function createBackIn(power: number): Easing;\nexport declare function createAnticipate(power: number): Easing;\nexport declare function bounceIn(p: number): number;\nexport declare function easeIn(p: number): number;\nexport declare function easeOut(p: number): number;\nexport declare function easeInOut(p: number): number;\nexport declare function circIn(p: number): number;\nexport declare function circOut(p: number): number;\nexport declare function circInOut(p: number): number;\nexport declare function backIn(p: number): number;\nexport declare function backOut(p: number): number;\nexport declare function backInOut(p: number): number;\nexport declare function anticipate(p: number): number;\n","types/animate/tween/animateValue.d.ts":"import { type Animation } from \"./Animation\";\nimport type { Vec2Like, Vec3Like } from \"../../math/vec\";\nimport type { QuatLike } from \"../../math/quat\";\nimport type { Mat4Like } from \"../../math/mat4\";\nimport type { ColorInput } from \"../../core/color\";\nimport { type TweenMeta } from \"./spec\";\n/** What `animate()` tweens: a number (a FLOAT, never a packed color), a color (any CSS color string,\n * through `Color` — delivered as rgba 0..1; a string that is not a color throws), a 2 / 3-vector (a\n * 3-array is a vector, not a color), a quaternion (slerp), or a 4x4 matrix (position / rotation /\n * scale). */\nexport type AnimateValue = number | string | Vec2Like | Vec3Like | QuatLike | Mat4Like | ColorInput;\n/** `onUpdate` receives a number for a number; every other kind arrives as the SAME `Float32Array`\n * every frame (overwritten in place — copy it if you keep it). A matrix is the 16 floats. */\nexport type AnimateOut<T> = T extends number ? number : Float32Array;\nexport type AnimateOptions<T extends AnimateValue> = Omit<TweenMeta, \"commit\" | \"layer\"> & {\n /** Start value (required unless `values` is given). */\n from?: T;\n /** End value. */\n to?: T;\n /** Keyframes instead of from/to (offsets via `times`). */\n values?: T[];\n onUpdate(value: AnimateOut<T>): void;\n /** After the last frame of a run that reached its end (not on cancel). */\n onComplete?(): void;\n};\n/** Tween a free value and apply it yourself in `onUpdate` — the primitive for anything without a\n * native channel (material params, volumes, numbers a Canvas draws). Same easing / keyframes /\n * `loop` / `clock` as `animateTo`; returns the {@link Animation} handle. Default clock: `'ui'`. */\nexport declare const animate: <T extends AnimateValue>(options: AnimateOptions<T>) => Animation;\n","types/animate/tween/Animation.d.ts":"import { CLOCK_GAME, CLOCK_UI, type TweenSpec } from \"./spec\";\n/** Playback control shared by element tweens and timelines. Times are **milliseconds**. */\nexport interface Animation {\n /** One iteration, ms. */\n readonly duration: number;\n /** Position inside the current iteration, ms. Writable = seek. */\n time: number;\n /** 0..1 of the whole animation (iterations included). Writable = seek. */\n progress: number;\n /** Playback rate; negative runs backwards, 0 freezes. */\n rate: number;\n readonly playing: boolean;\n /** Resolves `true` when the animation reaches its end, `false` when cancelled, replaced or replayed. Never rejects. */\n readonly finished: Promise<boolean>;\n /** Start from t = 0 (a running animation restarts). */\n play(): this;\n pause(): this;\n resume(): this;\n /** Jump to `ms`; playback state is unchanged. */\n seek(ms: number): this;\n /** Jump to the end: values land, commits apply, `finished` resolves `true`. */\n finish(): this;\n /** Stop where it is — no commit, `finished` resolves `false`. */\n cancel(): this;\n onFinish(fn: (done: boolean) => void): this;\n}\n/** The concrete handle — what the SDK instantiates behind `animateTo` / `animateFrom` / `Timeline`.\n * User code sees the {@link Animation} interface; the class itself must stay in the public\n * declarations because `TimelineImpl` extends it — marking it internal (even mentioning the tag in\n * this comment: the strip is a substring match) drops the timeline's playback members. */\nexport declare class TweenAnimation implements Animation {\n private _started;\n private _endTime;\n private _playing;\n private _rate;\n private _finished;\n private _resolve;\n private _settled;\n private _listeners;\n constructor(spec: TweenSpec);\n private _newPromise;\n private _settle;\n get duration(): number;\n get playing(): boolean;\n get finished(): Promise<boolean>;\n get rate(): number;\n set rate(r: number);\n get time(): number;\n set time(ms: number);\n get progress(): number;\n set progress(p: number);\n private _totalMs;\n private _elapsedMs;\n private _seekTotal;\n /** Create the host animation (paused at t = 0) if it doesn't exist. */\n private _ensure;\n private _destroy;\n play(): this;\n pause(): this;\n resume(): this;\n seek(ms: number): this;\n finish(): this;\n cancel(): this;\n onFinish(fn: (done: boolean) => void): this;\n}\nexport { CLOCK_UI, CLOCK_GAME };\n","types/animate/tween/easing.d.ts":"import type { Easing } from \"../easings\";\nexport declare const EASE_LINEAR = 0;\nexport declare const EASE_NAMED = 1;\nexport declare const EASE_BEZIER = 2;\nexport declare const EASE_STEPS = 3;\nexport declare const EASE_TABLE = 4;\n/** Samples per table (t = i / 64). Interpolation error for the smooth built-ins is < 1e-3. */\nexport declare const EASE_TABLE_SIZE = 65;\nexport type EasingSpec = {\n kind: number;\n /** kind-specific parameters: NAMED [id], BEZIER [x1, y1, x2, y2], STEPS [n, jumpAtStart], TABLE [tableIndex] */\n p: [number, number, number, number];\n /** TABLE only — the samples, appended to the blob's table section by the builder. */\n table?: Float32Array;\n};\n/** A curve in the options bag: a name, `\"cubic-bezier(x1,y1,x2,y2)\"`, `\"steps(n)\"`, a bezier tuple,\n * or any `Easing` function. */\nexport type EasingInput = string | readonly [number, number, number, number] | Easing;\n/** id → (name, formula). The formulas are the standard easings.net set; creator-tween's\n * `ctweenEaseNamed` implements the same list by id. */\nexport declare const NAMED_EASINGS: ReadonlyArray<readonly [string, Easing]>;\n/** The CSS `ease-in-out` curve — also UIKit's default animation curve, and web-lite's transition\n * default: what every host tweened with before the keyframe core. */\nexport declare const CSS_EASE_IN_OUT: [number, number, number, number];\nexport declare const LINEAR: EasingSpec;\n/** The default of every track with a TARGET (`animateTo` / `animateFrom` / `Timeline.add` on an\n * element, a 3D / 2D object): `ease-in-out` (2026-09-27; linear before). `animate()` — a raw\n * progress the app maps itself — stays linear. Write `easing: \"linear\"` for uniform motion. */\nexport declare const DEFAULT_EASING: EasingSpec;\n/** Sample an `Easing` function into a table. Endpoints are forced exact so a curve that is\n * numerically 0.9999 at 1 still lands on the keyframe. */\nexport declare const sampleEasing: (fn: Easing) => Float32Array;\n/** Normalize one easing input. Unknown strings fall back to linear with a console warning (a typo\n * should be visible, not a silent snap). */\nexport declare const parseEasing: (input: EasingInput | undefined) => EasingSpec;\n/** Evaluate an `EasingSpec` at `u` ∈ [0, 1] — the JS twin of `ctweenEase`. */\nexport declare const evalEasing: (e: EasingSpec, u: number) => number;\n","types/animate/tween/spec.d.ts":"import { type EasingInput, type EasingSpec } from \"./easing\";\nexport declare const BLOB_VERSION = 1;\nexport declare const DOM_UI = 0;\nexport declare const DOM_GL_NODE = 1;\nexport declare const DOM_GL_LIGHT = 2;\nexport declare const DOM_GL_CAMERA = 3;\nexport declare const DOM_NODE2D = 4;\nexport declare const DOM_SPRITE2D = 5;\nexport declare const DOM_VALUE = 6;\nexport declare const KIND_FLOAT = 0;\nexport declare const KIND_FLOAT_UNIT = 1;\nexport declare const KIND_COLOR = 2;\nexport declare const KIND_TRANSFORM = 3;\nexport declare const KIND_TRANSFORM_MATRIX = 4;\nexport declare const KIND_VEC3 = 5;\nexport declare const KIND_QUAT = 6;\nexport declare const KIND_EULER = 7;\nexport declare const KIND_DISCRETE = 8;\nexport declare const KIND_STRING = 9;\nexport declare const KIND_VEC2 = 10;\nexport declare const KIND_MAT4 = 11;\nexport declare const CLOCK_UI = 0;\nexport declare const CLOCK_GAME = 1;\nexport declare const lanesOf: (kind: number) => number;\n/** One normalized value: numeric lanes, or a string (string-lane kinds). */\nexport type TweenValue = {\n lanes: number[];\n} | {\n str: string;\n};\n/** A target's answer to \"can you animate `prop`?\": the writer domain, the id resolver, the value\n * normalizer, and the commit hook (UI writes the last key into its stored style). */\nexport type TweenChannel = {\n domain: number;\n /** Host handle at play time — a number (entity, web node id) or the host's opaque node object\n * (creator-pkg hands `_id` out as one); falsy = not addressable right now (unmounted), the\n * track is skipped. Handed to the host in the blob's `targets` list, never in the float data. */\n id: () => unknown;\n /** Normalize one keyframe value; `null` = not animatable (a warning, the value is committed only). */\n value: (v: unknown) => ({\n kind: number;\n sig?: string;\n } & TweenValue) | null;\n commit?: (v: unknown) => void;\n};\n/** Implemented by every animatable class (Element, Node, Node2D, Sprite, Light, Camera). */\nexport interface TweenTarget {\n}\nexport type Keyframe = {\n /** 0..1 within the track. */\n t: number;\n easing: EasingSpec;\n /** `undefined` = capture at play. */\n value?: TweenValue;\n /** The bag value as written — what the old-host path forwards verbatim. */\n raw?: unknown;\n};\nexport type Track = {\n target: TweenTarget;\n prop: string;\n channel: TweenChannel;\n kind: number;\n lanes: number;\n sig?: string;\n atMs: number;\n durMs: number;\n commit: boolean;\n keys: Keyframe[];\n};\nexport type TweenSpec = {\n clock: number;\n /** One iteration, ms — the last track's end (holds included). */\n durationMs: number;\n delayMs: number;\n /** -1 = forever. */\n iterations: number;\n pingPong: boolean;\n rate: number;\n tracks: Track[];\n /** Time-callbacks, ms; index = the event index the host reports. */\n calls: number[];\n};\n/** Meta keys of an `animateTo` / `Timeline.add` bag — everything that is not a prop target. */\nexport declare const TWEEN_META: Set<string>;\nexport type TweenMeta = {\n /** Tween length in **milliseconds** (default 225). */\n duration?: number;\n /** Wait before starting, **milliseconds**. The first keyframe holds through the wait. A loop delays once. */\n delay?: number;\n /** A curve for every prop, or a per-prop map (`{ width: 'outExpo', opacity: 'linear' }`). Names\n * (`outCubic`, `inOutSine`, `outBack`, …), `cubic-bezier(…)` / a `[x1, y1, x2, y2]` tuple,\n * `steps(n)`, or any `Easing` function. Default `ease-in-out` (cubic-bezier(0.42, 0, 0.58, 1),\n * the curve UIKit and CSS transitions ease with); `\"linear\"` for uniform motion. */\n easing?: EasingInput | Record<string, EasingInput>;\n /** Keyframe offsets 0..1 for array-valued props (default: evenly spaced). */\n times?: number[];\n /** `true` = forever, a number = that many cycles. A loop never commits. */\n loop?: boolean | number;\n /** `\"ping-pong\"` (default) there and back each cycle; `\"restart\"` snaps back and replays. */\n loopMode?: \"restart\" | \"ping-pong\";\n /** `false` = animate without writing the last keyframe into the element's style. */\n commit?: boolean;\n /** `'ui'` = wall time (menus animate while the game is paused); `'game'` follows `Time.scale`.\n * Default: `'ui'` on UI elements, `'game'` on 3D / 2D nodes. */\n clock?: \"ui\" | \"game\";\n /** Legacy escape hatch (old hosts only). */\n layer?: number;\n};\nexport declare const DEFAULT_DURATION_MS = 225;\nexport declare const warnOnce: (key: string, msg: string) => void;\n/** Resolve the per-prop easing from the bag; nothing given (or no entry for `prop` in a per-prop\n * map) = `fallback` — the tracks' DEFAULT_EASING, linear for a value tween. */\nexport declare const easingFor: (easing: TweenMeta[\"easing\"], prop: string, fallback?: EasingSpec) => EasingSpec;\n/** Iteration count from `loop`: 1 = one-shot, -1 = forever, n = cycles. */\nexport declare const iterationsOf: (loop: TweenMeta[\"loop\"]) => number;\n/** A UI style value: number → FLOAT; \"12px\" / \"50%\" → FLOAT_UNIT; other strings → STRING (the host\n * decides color vs discrete); booleans → DISCRETE. The element hands over the WIRE value\n * (UINode._tweenChannel): a color key arrives as a string, never a packed number. */\nexport declare const uiValue: (v: unknown) => ({\n kind: number;\n sig?: string;\n} & TweenValue) | null;\n/** Parse `\"translate(10px, 20px) rotate(45deg) scale(1.2)\"` into a signature + lanes, or null when a\n * function is unknown (the caller falls back to matrix decomposition on the host). `scale(2)` and\n * `translate(5px)` complete their second argument like CSS.\n *\n * `percent`: a `%` in a translate is a percent of the target's box (`translateX(100%)` →\n * `translateX%` [100]; a translate mixing the units splits into its two axes). Without it a `%`\n * reads as px, as the style's own parser reads it — with a warning: only a screen transition\n * measures a translate in percents. */\nexport declare const parseTransformList: (s: string, percent?: boolean) => {\n sig: string;\n lanes: number[];\n} | null;\nexport declare const transformLanes: (sig: string) => number;\nexport declare const vec3Value: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const quatValue: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const eulerValue: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const vec2Value: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const floatValue: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const colorValue: (v: unknown, toRgba: (c: any) => [number, number, number, number]) => {\n kind: number;\n lanes: [number, number, number, number];\n} | null;\n/** A free value for animate(): number → FLOAT, a color string → COLOR, arrays / vectors by length\n * (2 → VEC2, 3 → VEC3, 4 → QUAT, 16 → MAT4 decomposed into position · quaternion · scale). */\nexport declare const valueValue: (v: unknown) => ({\n kind: number;\n} & TweenValue) | null;\n/** Is this bag value a KEYFRAME ARRAY for a vector prop, as opposed to one vector? A vector value\n * is an array of NUMBERS (`[0, 2, 0]`); anything else in the array is a list of keyframes —\n * `[[0,0,0], [0,2,0]]`, `[new Vec3(), …]`, and the UI's `color: ['#fff', '#e29a22']`. */\nexport declare const isVectorKeyframes: (v: unknown) => boolean;\n/** Build one track's keyframes from a bag value: a single value = one explicit key (the other end\n * captured), an array = explicit keys spaced by `times` or evenly. `fromCurrent` says which end is\n * implicit (animateTo: the first; animateFrom: the last). Returns null when a value can't be\n * animated (already warned). */\nexport declare const makeTrack: (target: TweenTarget, prop: string, raw: unknown, meta: TweenMeta, atMs: number, fromCurrent: boolean, vectorProp: boolean) => Track | null;\n/** Every (prop → value) entry of a bag, meta keys stripped. */\nexport declare const bagProps: (bag: Record<string, unknown>) => [string, unknown][];\n/** The value of a numeric track at local time `ms` (the C evaluator's rule: first key holds before,\n * last after; eased segment between). `out` receives `track.lanes` numbers. */\nexport declare const evaluateTrack: (track: Track, ms: number, out: number[]) => void;\nexport type TweenBlob = {\n data: Float32Array;\n strings: string[];\n targets: unknown[];\n};\n/** Flatten a spec for `_creatorTree.tweenCreate`. Tracks whose target has no host id right now are\n * dropped (the animation still runs its clock, calls and finish). */\nexport declare const buildBlob: (spec: TweenSpec) => TweenBlob;\n","types/animate/tween/Timeline.d.ts":"import { TweenAnimation } from \"./Animation\";\nimport { type AnimateOptions, type AnimateValue } from \"./animateValue\";\nimport { type TweenMeta, type TweenTarget } from \"./spec\";\nexport type TimelineOptions = {\n /** `'ui'` (default) = wall time; `'game'` follows `Time.scale` and pauses with the game. */\n clock?: \"ui\" | \"game\";\n /** Repeat the whole timeline: `true` = forever, a number = cycles. */\n loop?: boolean | number;\n loopMode?: \"restart\" | \"ping-pong\";\n /** Wait before the first play, ms. */\n delay?: number;\n};\n/** Where a track goes: ms, a label, or `[label, offsetMs]`. Default = the current end (sequencing). */\nexport type TimelinePosition = number | string | [string, number];\nexport type TimelineAddOptions = {\n at?: TimelinePosition;\n /** With several targets: each starts this many ms after the previous one. */\n stagger?: number;\n};\n/** A choreography: tracks on many targets at absolute times, JS calls, labels and holds, driven by\n * one clock. Build it once, `play()` on every entrance — `play()` restarts from t = 0 and the pose\n * at any time is fully defined by the tracks (the first keyframe of a track holds before it\n * starts, the last one after it ends). */\nexport declare class TimelineImpl extends TweenAnimation {\n private _labels;\n private _end;\n constructor(options?: TimelineOptions);\n private _at;\n private _grow;\n /** Animate `props` on one target or several (staggered), like `animateTo` — arrays are keyframes,\n * `duration` / `easing` / `times` / `commit` apply. The bag's `delay` shifts the track after `at`. */\n add(target: TweenTarget | TweenTarget[], props: Record<string, unknown> & TweenMeta, options?: TimelineAddOptions): this;\n /** Like `add` with the `animateFrom` shape: the target's own state is the implicit last keyframe. */\n addFrom(target: TweenTarget | TweenTarget[], props: Record<string, unknown> & TweenMeta, options?: TimelineAddOptions): this;\n /** A free-value track (see the `animate()` global): the host evaluates it and calls `onUpdate`\n * every frame with the value. */\n animate<T extends AnimateValue>(options: AnimateOptions<T>, at?: TimelinePosition): this;\n /** Call `fn` when playback crosses `at` (forward or backward), in time order, always before\n * finish, never from a previous run. */\n call(at: TimelinePosition, fn: () => void): this;\n /** Name a time — for `at`, `seek` and callers (`tl.labels.landed`). Default = the current end. */\n label(name: string, at?: TimelinePosition): this;\n /** Named times, ms. */\n get labels(): Record<string, number>;\n /** Extend the timeline with stillness after its current end. */\n hold(ms: number): this;\n /** The current end, ms (tracks, calls and holds). */\n get end(): number;\n /** `seek` also accepts a label. */\n seek(at: number | string): this;\n}\n/** The timeline handle type (see {@link TimelineImpl} for the members). */\nexport type Timeline = TimelineImpl;\n/** Create a timeline — `Timeline()` / `Timeline({ clock: 'game', loop: true })`. */\nexport declare function Timeline(options?: TimelineOptions): Timeline;\n","types/audio/audio.d.ts":"import { type Vec3Like } from \"../math/vec\";\nimport { Bus } from \"./Bus\";\nimport type { Sound } from \"./Sound\";\nimport { Voice } from \"./Voice\";\nexport type PlaySoundOptions = {\n /** 0 … 1 (and above, at your own risk). Default 1. */\n volume?: number;\n /** Playback rate, 1 = unchanged. Default 1. */\n pitch?: number;\n loop?: boolean;\n /** Bus name; default: the source's bus, `sfx` for 2D. */\n bus?: string;\n /** Higher survives voice stealing when the pool is full. Default 0. */\n priority?: number;\n /** Fade-in seconds. Default 0. */\n fade?: number;\n /** Seconds into the clip to start from. */\n startAt?: number;\n /** 2D only: -1 left … 1 right. */\n pan?: number;\n};\nexport type Rolloff = \"none\" | \"inverse\" | \"linear\" | \"exponential\";\n/** Distance model of an AudioSource / playAt. */\nexport type SpatialOptions = {\n /** Metres of full volume around the source. Default 1. */\n minDistance?: number;\n /** Metres beyond which the source no longer gets quieter. Default 50. */\n maxDistance?: number;\n /** How volume falls between the two: `inverse` (default, physical), `linear`, `exponential`, `none`. */\n rolloff?: Rolloff;\n};\nexport declare const ROLLOFF: Record<Rolloff, number>;\nexport type AudioStats = {\n voicesPlaying: number;\n voicesMono: number;\n voicesStereo: number;\n /** Voices displaced (or dropped) by a fuller pool since start. */\n stolen: number;\n clips: number;\n clipBytes: number;\n /** Master peak since the previous read, linear (1 = full scale). */\n peak: number;\n sampleRate: number;\n /** The reverb zone the listener is in (0 = none) and how far inside (0 … 1). */\n listenerZone: number;\n zoneBlend: number;\n /** Voices rendered binaurally right now (see `audio.hrtf`). */\n hrtfVoices: number;\n};\ndeclare class AudioSystem {\n private readonly _buses;\n private _hrtf;\n private _hrtfVoices;\n private _timeScalePitch;\n /** True when this host mixes sound. Everything below is a silent no-op otherwise. */\n get supported(): boolean;\n /** HRTF binaural rendering (MIT KEMAR filters on the CPU): sounds get a real up / down / behind in\n * HEADPHONES. Off by default — on speakers it only smears the image. Applies to the `hrtfVoices`\n * nearest 3D voices; the rest keep plain panning. A host built without the filters (an iOS App\n * Clip: they are 184 KB) keeps every voice on the panner — `stats.hrtfVoices` stays 0. */\n get hrtf(): boolean;\n set hrtf(v: boolean);\n /** `Time.scale` also pitches the sfx bus: slow motion drops every effect's tone, like a film. Default\n * false — a pause only mutes sfx, the menu click keeps its pitch. */\n get timeScalePitch(): boolean;\n set timeScalePitch(v: boolean);\n /** How many voices get the (CPU-heavier) binaural path. Default 16. */\n get hrtfVoices(): number;\n set hrtfVoices(n: number);\n /** A bus by name — the five built-ins, or an app-defined one created on first use. */\n bus(name: string): Bus;\n get master(): Bus;\n /** 2D playback (UI, stingers, music one-shots). */\n play(sound: Sound, options?: PlaySoundOptions): Voice;\n /** A one-shot at a world position with its own transient source — impacts, ricochets, debris.\n * The source is freed when the voice ends. */\n playAt(sound: Sound, position: Vec3Like, options?: PlaySoundOptions & SpatialOptions): Voice;\n /** Stop every voice on every bus (fade in seconds). */\n stopAll(fade?: number): void;\n /** Engine counters for a debug overlay or a perf log. */\n get stats(): AudioStats;\n}\nexport declare const audio: AudioSystem;\nexport type { AudioSystem };\n","types/audio/Bus.d.ts":"export type ReverbPreset = \"room\" | \"hall\" | \"cave\" | \"arena\" | \"bathroom\" | \"outdoor\";\nexport type ReverbParams = {\n /** 0 (a closet) … 1 (a cathedral). */\n roomSize?: number;\n /** High-frequency loss per reflection, 0 … 1. */\n damping?: number;\n /** Stereo width of the tail, 0 … 1. */\n width?: number;\n /** Wet amount, 0 … 1. */\n mix?: number;\n /** Seconds before the tail starts (a big hall: 0.02 … 0.05). */\n preDelay?: number;\n};\nexport type EchoParams = {\n /** Seconds between repeats (up to 2). */\n delay?: number;\n /** Feedback, 0 … 0.95 — how many repeats survive. */\n decay?: number;\n /** Wet amount, 0 … 1. */\n mix?: number;\n};\nexport declare const REVERB_PRESETS: Record<ReverbPreset, Required<ReverbParams>>;\nexport declare class Bus {\n readonly name: string;\n private _volume;\n private _muted;\n private _reverb;\n private _echo;\n private _lowpass;\n private get _live();\n get volume(): number;\n set volume(v: number);\n get muted(): boolean;\n set muted(v: boolean);\n /** A preset name, explicit params, or null (off). */\n get reverb(): ReverbPreset | ReverbParams | null;\n set reverb(v: ReverbPreset | ReverbParams | null);\n get echo(): EchoParams | null;\n set echo(v: EchoParams | null);\n /** Low-pass cutoff in Hz (20 … 20000), null = off. */\n get lowpass(): number | null;\n set lowpass(v: number | null);\n /** Stop every voice on this bus (fade in seconds). */\n stopAll(fade?: number): void;\n}\n","types/audio/Sound.d.ts":"export type SoundOptions = {\n /** Keep two channels (2D playback of stereo material — music beds, ambiences). Default: the clip\n * is decoded MONO, which is what 3D spatialization needs and what SFX are anyway. */\n stereo?: boolean;\n};\nexport declare class Sound {\n /** The urls this clip was loaded from (one per variant). */\n readonly urls: readonly string[];\n private readonly _durations;\n private _channels;\n private _disposed;\n private _last;\n private constructor();\n /** Fetch + decode. An array = variants: `play` picks a random one (never the same twice in a row\n * when there are 3 or more). Rejects with the failing url when a file cannot be decoded. */\n static load(src: string | string[], options?: SoundOptions): Promise<Sound>;\n /** Seconds (the first variant's). 0 for a silent clip. */\n get duration(): number;\n /** Decoded channel count: 1, or 2 with `{ stereo: true }`. */\n get channels(): number;\n /** How many variants this clip carries. */\n get variants(): number;\n /** True when the engine has this clip (false on hosts without audio, or after dispose). */\n get ready(): boolean;\n get disposed(): boolean;\n /** Free the engine's PCM. Voices playing it stop at once. Idempotent. */\n dispose(): void;\n}\n","types/audio/support.d.ts":"export declare const audioSupported: boolean;\n","types/audio/Voice.d.ts":"import { Emitter } from \"../core/events\";\nexport type VoiceEvents = {\n /** The voice is over: the clip ended, `stop` completed, or the pool reused the slot. */\n ended: () => void;\n};\nexport declare class Voice extends Emitter<VoiceEvents> {\n private _volume;\n private _pitch;\n private _pan;\n private _over;\n addEventListener<K extends keyof VoiceEvents>(channel: K, callback: VoiceEvents[K]): void;\n /** True while the engine plays this voice. */\n get playing(): boolean;\n /** Seconds into the clip. */\n get time(): number;\n get volume(): number;\n set volume(v: number);\n get pitch(): number;\n set pitch(v: number);\n /** 2D voices only: -1 left … 1 right. */\n get pan(): number;\n set pan(v: number);\n /** Stop now, or fade out over `fade` seconds. `ended` fires from the engine afterwards. */\n stop(options?: {\n fade?: number;\n }): void;\n}\n","types/canvas/Canvas.d.ts":"import { Texture2D } from \"../g2/Texture2D\";\nimport { File, type FetchResponse } from \"../runtime/fetch\";\nimport type { SvgSourceValue } from \"../runtime/misc\";\nimport { Recorder, Gradient, type ImageRef, type TextAlignName, type TextBaselineName, type LineJoinName, type LineCapName, type FillRuleName } from \"./gen/recorder\";\nexport { Gradient };\nexport type TextAlign = TextAlignName;\nexport type TextBaseline = TextBaselineName;\nexport type LineJoin = LineJoinName;\nexport type LineCap = LineCapName;\nexport type FillRule = FillRuleName;\nexport interface CanvasTextMetrics {\n width: number;\n ascent: number;\n descent: number;\n}\nexport declare class Canvas extends Recorder {\n /** Brand so `Sprite`/`UIImage`/`Material` can accept a Canvas anywhere a texture source is expected. */\n readonly __canvas: true;\n width: number;\n height: number;\n /** Device-pixel multiplier (draw at 2 for crisp retina text). Applied by the backend. */\n pixelRatio: number;\n private _drawn?;\n private _tex2d?;\n private _uiBound;\n private _lastBakeLen;\n private _warnedGrowth;\n constructor(width: number, height: number, opts?: {\n pixelRatio?: number;\n });\n /** Change the surface size; takes effect on the next bake. */\n resize(width: number, height: number): this;\n /** Blit a `Bitmap` (a snapshot from `toBitmap()` or `loadImage()`) onto this canvas. All coordinates\n * are LOGICAL — including the source sub-rect in the 9-arg form (it's scaled by the bitmap's\n * pixelRatio here). Records a DRAW_IMAGE op, so the blit runs at bake time; the canvas keeps the\n * Bitmap alive until `reset()` removes the op. Three browser-style forms:\n * drawImage(bmp, dx, dy) — whole bitmap at its natural size\n * drawImage(bmp, dx, dy, dw, dh) — whole bitmap, scaled into dw×dh\n * drawImage(bmp, sx, sy, sw, sh, dx, dy, dw, dh) — a sub-rect of the bitmap, scaled into dw×dh */\n drawImage(img: Bitmap | ImageRef, dx: number, dy: number): this;\n drawImage(img: Bitmap | ImageRef, dx: number, dy: number, dw: number, dh: number): this;\n drawImage(img: Bitmap | ImageRef, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): this;\n /** Decode an image source into a standalone `Bitmap` you can blit with `drawImage()` — either an\n * `SvgSource(...)` (drawn by the core, painted by the host) or a `FetchResponse` holding already-fetched\n * image bytes (decoded; an SVG file is detected). This is async because the web host decodes with the\n * browser; `await` it ONCE, then `drawImage(bitmap, …)` is synchronous and the Bitmap is reusable. The\n * returned Bitmap owns a native surface at the image's natural pixel size (`pixelRatio` 1), freed\n * once nothing references the Bitmap (`destroy()` frees it early). Typical use:\n * const logo = await canvas.loadImage(SvgSource(svg)) // or: await fetch(url) → the response\n * canvas.drawImage(logo, 0, 0) // sync, blit as often as you like */\n loadImage(source: SvgSourceValue | FetchResponse): Promise<Bitmap>;\n /** Measure `text` in the current font and letterSpacing on THIS platform. The one synchronous\n * round-trip. */\n measureText(text: string): CanvasTextMetrics;\n /** Discard the recording (and the Bitmaps its drawImage ops kept alive). */\n reset(): this;\n /** Bake and return the 2D texture (created once, then cached). */\n texture(): Texture2D;\n /** Re-rasterize and re-upload to every texture this canvas produced (call after redrawing) — the\n * cached 2D and/or 3D texture, whichever engines this canvas was baked into. */\n update(): this;\n /** Copy the current pixels into a standalone, immutable `Bitmap` — independent of this canvas, so\n * later drawing/`reset()` never touches it. Draw it back with `drawImage()`, export it with\n * `toFile()`, or use it to \"flatten\" an ever-growing drawing so re-bakes stay O(1):\n * const next = canvas.toBitmap() // bakes with the previous snapshot still alive\n * canvas.reset(); canvas.drawImage(next, 0, 0) // one op replaces the whole history\n * The canvas keeps a drawn Bitmap alive while its drawImage is recorded, and the old snapshot goes\n * on its own once reset() dropped it — no destroy() needed. */\n toBitmap(): Bitmap;\n /** Encode the current pixels to an image `File` — 'image/png' (default) or 'image/jpeg'. The File\n * is an opaque host buffer handle (`name`/`size` only): append it to a FormData to upload, load it\n * as a texture (`Texture2D.load(file)`), or hand it to a share/save sheet. */\n toFile(name?: string, type?: string): Promise<File>;\n /** Free the surface now instead of when the canvas is dropped (an image still showing it goes blank).\n * The recording stays: a later bake makes a new surface. */\n destroy(): void;\n}\n/** Duck-type guard so consumers can accept a Canvas anywhere a texture source is expected. */\nexport declare const isCanvas: (v: unknown) => v is Canvas;\n/** An immutable RGBA8 snapshot of a canvas, produced by `Canvas.toBitmap()` / `loadImage()`. It owns its\n * own baked surface (a copy), so the source canvas can keep drawing or `reset()` without affecting it.\n * Use it to stamp/blit back (`canvas.drawImage(bitmap, …)`), to export (`bitmap.toFile()`), or as a\n * cheap \"layer\" you composite. Its surface is freed once nothing references the Bitmap (a canvas that\n * drew it keeps it until `reset()`); `destroy()` frees it early. */\nexport declare class Bitmap {\n readonly __bitmap: true;\n /** Logical width, matching the Canvas it was captured from (pixelRatio is crispness, not size). */\n readonly width: number;\n readonly height: number;\n readonly pixelRatio: number;\n constructor(surface: Handle | number | null, width: number, height: number, pixelRatio: number);\n /** Device-pixel dimensions of the stored bitmap (`width * pixelRatio`, rounded). */\n get pixelWidth(): number;\n get pixelHeight(): number;\n /** Encode to an image `File` — 'image/png' (default) or 'image/jpeg'. See `Canvas.toFile`. */\n toFile(name?: string, type?: string): Promise<File>;\n /** Free the native surface now instead of when the bitmap is dropped. It must not be drawn or encoded\n * afterwards (a canvas whose recording still draws it blits nothing). */\n destroy(): void;\n}\n/** Duck-type guard for a Bitmap (see `isCanvas`). */\nexport declare const isBitmap: (v: unknown) => v is Bitmap;\n","types/canvas/gen/cssColor.d.ts":"/** A color: straight float32 RGBA, 0..1. */\nexport interface CssRgba {\n r: number;\n g: number;\n b: number;\n a: number;\n}\n/** The named colors as 0xRRGGBBAA: the 148 CSS Color 4 names, transparent and clear (= transparent). */\nexport declare const CSS_COLOR_NAMES: Readonly<Record<string, number>>;\n/** A CSS color → straight float32 RGBA, or null when `input` is not a color. */\nexport declare const parseCssColor: (input: string) => CssRgba | null;\n/** A float channel → a byte, as the header's toByte: float32, clamp (NaN → 0), round half up (0.5 → 128). */\nexport declare const cssToByte: (v: number) => number;\n/** 0xRRGGBBAA (unsigned). */\nexport declare const cssRgba8: (c: CssRgba) => number;\n/** '#rrggbbaa', lower-case. */\nexport declare const cssHex8: (c: CssRgba) => string;\n","types/canvas/gen/recorder.d.ts":"export type FillRuleName = \"nonzero\" | \"evenodd\";\nexport type LineJoinName = \"miter\" | \"round\" | \"bevel\";\nexport type LineCapName = \"butt\" | \"round\" | \"square\";\nexport type TextAlignName = \"left\" | \"center\" | \"right\" | \"start\" | \"end\";\nexport type TextBaselineName = \"alphabetic\" | \"top\" | \"middle\" | \"bottom\" | \"hanging\" | \"ideographic\";\n/** A gradient built by createLinearGradient / createRadialGradient; assign it to fillStyle / strokeStyle. */\nexport declare class Gradient {\n readonly stops: {\n offset: number;\n color: string;\n }[];\n readonly kind: number;\n readonly coords: [number, number, number, number, number, number];\n addColorStop(offset: number, color: string): this;\n}\n/** The recorded stream: the f32 words and the string table the core reads. */\nexport interface Stream {\n cmd: Float32Array;\n refs: string[];\n}\n/** A surface with its device size, for the short drawImage forms. */\nexport interface ImageRef {\n surface: number;\n width: number;\n height: number;\n}\nexport declare class Recorder {\n private cmd;\n private refs;\n private refIndex;\n private _globalAlpha;\n private _fillStyle;\n private _strokeStyle;\n private _lineWidth;\n private _lineJoin;\n private _lineCap;\n private _miterLimit;\n private _lineDash;\n private _lineDashOffset;\n private _font;\n private _textAlign;\n private _textBaseline;\n private _letterSpacing;\n private _saved;\n /** The words recorded so far (a copy) + the string table. */\n stream(): Stream;\n /** Plain arrays, for a JSON file (the golden tests' input). */\n toJSON(): {\n cmd: number[];\n refs: string[];\n };\n /** The number of words recorded. */\n get length(): number;\n /** Discard the recording; the shadowed state is reset too (a fresh replay starts from defaults). */\n reset(): this;\n private ref;\n private push;\n save(): this;\n restore(): this;\n translate(x: number, y: number): this;\n scale(sx: number, sy: number): this;\n rotate(rad: number): this;\n transform(a: number, b: number, c: number, d: number, e: number, f: number): this;\n setTransform(a: number, b: number, c: number, d: number, e: number, f: number): this;\n resetTransform(): this;\n get globalAlpha(): number;\n set globalAlpha(a: number);\n get fillStyle(): string | Gradient;\n set fillStyle(v: string | Gradient);\n get strokeStyle(): string | Gradient;\n set strokeStyle(v: string | Gradient);\n private style;\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): Gradient;\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): Gradient;\n get lineWidth(): number;\n set lineWidth(w: number);\n get lineJoin(): LineJoinName;\n set lineJoin(j: LineJoinName);\n get lineCap(): LineCapName;\n set lineCap(c: LineCapName);\n get miterLimit(): number;\n set miterLimit(m: number);\n setLineDash(segments: number[]): this;\n getLineDash(): number[];\n get lineDashOffset(): number;\n set lineDashOffset(o: number);\n get font(): string;\n set font(f: string);\n get textAlign(): TextAlignName;\n set textAlign(a: TextAlignName);\n get textBaseline(): TextBaselineName;\n set textBaseline(b: TextBaselineName);\n get letterSpacing(): number;\n set letterSpacing(px: number);\n beginPath(): this;\n closePath(): this;\n moveTo(x: number, y: number): this;\n lineTo(x: number, y: number): this;\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): this;\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): this;\n arc(x: number, y: number, r: number, a0: number, a1: number, ccw?: boolean): this;\n arcTo(x1: number, y1: number, x2: number, y2: number, r: number): this;\n ellipse(x: number, y: number, rx: number, ry: number, rotation: number, a0: number, a1: number, ccw?: boolean): this;\n rect(x: number, y: number, w: number, h: number): this;\n roundRect(x: number, y: number, w: number, h: number, r: number): this;\n fill(rule?: FillRuleName): this;\n stroke(): this;\n clip(rule?: FillRuleName): this;\n fillRect(x: number, y: number, w: number, h: number): this;\n strokeRect(x: number, y: number, w: number, h: number): this;\n clearRect(x: number, y: number, w: number, h: number): this;\n fillText(text: string, x: number, y: number, maxWidth?: number): this;\n strokeText(text: string, x: number, y: number, maxWidth?: number): this;\n /** Blit a surface. Three browser-style forms; the source rect is in the surface's device px. */\n drawImage(img: ImageRef, dx: number, dy: number): this;\n drawImage(img: ImageRef, dx: number, dy: number, dw: number, dh: number): this;\n drawImage(img: ImageRef, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): this;\n}\n","types/canvas/gen/spec.d.ts":"export declare const SPEC_VERSION = 1;\nexport declare const LineJoin: {\n readonly MITER: 0;\n readonly ROUND: 1;\n readonly BEVEL: 2;\n};\nexport type LineJoin = (typeof LineJoin)[keyof typeof LineJoin];\nexport declare const LineJoinName: readonly string[];\nexport declare const LineCap: {\n readonly BUTT: 0;\n readonly ROUND: 1;\n readonly SQUARE: 2;\n};\nexport type LineCap = (typeof LineCap)[keyof typeof LineCap];\nexport declare const LineCapName: readonly string[];\nexport declare const TextAlign: {\n readonly LEFT: 0;\n readonly CENTER: 1;\n readonly RIGHT: 2;\n readonly START: 3;\n readonly END: 4;\n};\nexport type TextAlign = (typeof TextAlign)[keyof typeof TextAlign];\nexport declare const TextAlignName: readonly string[];\nexport declare const TextBaseline: {\n readonly ALPHABETIC: 0;\n readonly TOP: 1;\n readonly MIDDLE: 2;\n readonly BOTTOM: 3;\n readonly HANGING: 4;\n readonly IDEOGRAPHIC: 5;\n};\nexport type TextBaseline = (typeof TextBaseline)[keyof typeof TextBaseline];\nexport declare const TextBaselineName: readonly string[];\nexport declare const FillRule: {\n readonly NONZERO: 0;\n readonly EVENODD: 1;\n};\nexport type FillRule = (typeof FillRule)[keyof typeof FillRule];\nexport declare const FillRuleName: readonly string[];\nexport declare const Spread: {\n readonly PAD: 0;\n readonly REFLECT: 1;\n readonly REPEAT: 2;\n};\nexport type Spread = (typeof Spread)[keyof typeof Spread];\nexport declare const SpreadName: readonly string[];\nexport declare const Gradient: {\n readonly LINEAR: 0;\n readonly RADIAL: 1;\n};\nexport type Gradient = (typeof Gradient)[keyof typeof Gradient];\nexport declare const GradientName: readonly string[];\nexport declare const Paint: {\n readonly COLOR: 0;\n readonly LINEAR: 1;\n readonly RADIAL: 2;\n};\nexport type Paint = (typeof Paint)[keyof typeof Paint];\nexport declare const PaintName: readonly string[];\nexport declare const PathVerb: {\n readonly MOVE: 0;\n readonly LINE: 1;\n readonly QUAD: 2;\n readonly CUBIC: 3;\n readonly CLOSE: 4;\n};\nexport type PathVerb = (typeof PathVerb)[keyof typeof PathVerb];\nexport declare const PathVerbName: readonly string[];\nexport declare const ImageFormat: {\n readonly PNG: 0;\n readonly JPEG: 1;\n};\nexport type ImageFormat = (typeof ImageFormat)[keyof typeof ImageFormat];\nexport declare const ImageFormatName: readonly string[];\n/** The opcode stream: op id → the word after it. */\nexport declare const OP: {\n readonly SAVE: 0;\n readonly RESTORE: 1;\n readonly TRANSLATE: 2;\n readonly SCALE: 3;\n readonly ROTATE: 4;\n readonly TRANSFORM: 5;\n readonly SET_TRANSFORM: 6;\n readonly RESET_TRANSFORM: 7;\n readonly GLOBAL_ALPHA: 8;\n readonly FILL_STYLE: 9;\n readonly STROKE_STYLE: 10;\n readonly FILL_GRADIENT: 11;\n readonly STROKE_GRADIENT: 12;\n readonly LINE_WIDTH: 13;\n readonly LINE_JOIN: 14;\n readonly LINE_CAP: 15;\n readonly MITER_LIMIT: 16;\n readonly LINE_DASH: 17;\n readonly LINE_DASH_OFFSET: 18;\n readonly FONT: 19;\n readonly TEXT_ALIGN: 20;\n readonly TEXT_BASELINE: 21;\n readonly LETTER_SPACING: 22;\n readonly PATH_BEGIN: 23;\n readonly PATH_CLOSE: 24;\n readonly MOVE_TO: 25;\n readonly LINE_TO: 26;\n readonly QUADRATIC_TO: 27;\n readonly BEZIER_TO: 28;\n readonly ARC: 29;\n readonly ARC_TO: 30;\n readonly ELLIPSE: 31;\n readonly RECT: 32;\n readonly ROUND_RECT: 33;\n readonly FILL: 34;\n readonly STROKE: 35;\n readonly CLIP: 36;\n readonly FILL_RECT: 37;\n readonly STROKE_RECT: 38;\n readonly CLEAR_RECT: 39;\n readonly FILL_TEXT: 40;\n readonly STROKE_TEXT: 41;\n readonly DRAW_IMAGE: 42;\n};\nexport type OP = (typeof OP)[keyof typeof OP];\n/** Operand layout per op: `args` is one letter per fixed word (f float, i int, r string ref);\n * `repeat` is the group that follows the trailing count. */\nexport declare const OP_ARGS: Record<number, {\n args: string;\n repeat: string;\n}>;\nexport declare const OP_NAME: readonly string[];\n/** The draw list: command id → the word after it. */\nexport declare const DRAW: {\n readonly SET_TRANSFORM: 0;\n readonly SAVE: 1;\n readonly RESTORE: 2;\n readonly CLIP: 3;\n readonly FILL_PATH: 4;\n readonly STROKE_PATH: 5;\n readonly FILL_TEXT: 6;\n readonly STROKE_TEXT: 7;\n readonly DRAW_IMAGE: 8;\n readonly CLEAR_RECT: 9;\n};\nexport type DRAW = (typeof DRAW)[keyof typeof DRAW];\nexport declare const DRAW_NAME: readonly string[];\n","types/core/Aspect.d.ts":"import type { Scene } from \"../gl/Scene\";\nimport { Emitter, type EventMap } from \"./events\";\nimport type { InspectorUI } from \"./InspectorUI\";\nimport type { Node } from \"../gl/Node\";\n/** The class object of an aspect — accepted even when its constructor is protected/abstract. */\nexport type AspectCtor<A extends Aspect<any, any, any>> = abstract new () => A;\n/** The accessor name carried in the aspect's generic. */\nexport type KeyOf<A> = A extends Aspect<infer K, any, any> ? K : never;\n/** The node kind an aspect targets (the scene kind for a System). */\nexport type TargetOf<A> = A extends Aspect<any, infer P, any> ? P : never;\n/** `{ name: Aspect }` — the field an aspect contributes to its node. */\nexport type FieldOf<A extends Aspect<any, any, any>> = {\n [P in KeyOf<A>]: A;\n};\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n/**\n * A variable typed as a node KNOWN to carry the given aspect(s). Union, not a tuple — reads as\n * English and mirrors the runtime guard `node.has(Health)`:\n * let boss: With<Sprite, Health | Physics>\n */\nexport type With<N, A extends Aspect<any, any, any>> = N & UnionToIntersection<A extends any ? FieldOf<A> : never>;\n/**\n * Base for anything that can carry aspects. Extends Emitter, so node kinds get events too. Provides\n * the four verbs; the named accessor (node.physics, node.health, …) is set as an own property at\n * attach time, keyed by the aspect class's runtime `aspect` name.\n */\nexport declare abstract class AspectHost<E extends EventMap = EventMap> extends Emitter<E> {\n /** Attach (and configure) an aspect, or reconfigure it if already present. Returns the node typed\n * as now-having that aspect (so no guard/`?.` is needed afterwards). Rejects a wrong target node. */\n aspect<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;\n /** Safe access — undefined if the aspect isn't attached. */\n get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;\n /** Existence check AND type guard: inside `if (node.has(Physics))`, `node.physics` is present. */\n has<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this is this & FieldOf<A>;\n /** Detach an aspect (runs its onDetach). Named `removeAspect` so it never collides with the\n * child-management `add`/`remove` semantics some node kinds expose. */\n removeAspect<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this;\n}\n/**\n * Base for everything you attach. `K` = accessor name (extracted by chisel for the runtime). `P` =\n * the target node kind: `this.node` is typed to it, AND attaching to a wrong node is a compile error.\n * `E` = the events this aspect emits (`{ explode: (b: Barrel) => void }`): `this.emit('explode', …)`\n * inside, `node.barrel.on('explode', fn)` outside.\n * Initialize in `onAttach` (the node is set by then) — not a constructor; aspects are created by the\n * engine via `node.aspect()`, never `new`.\n */\nexport declare abstract class Aspect<K extends string, P = Node, E extends EventMap = {}> {\n /**\n * Opt this aspect class into EDITOR-RUN mode (generators): while a scene is edited, the scene\n * loader constructs the instance (refs resolved, `node`/`generated` set — never `onAttach`) and\n * calls `rebuild()` — again on inspector prop edits and when a `ref()`-referenced node moves.\n * `static editor = { rebuild: true }`.\n */\n static editor?: {\n rebuild?: boolean;\n };\n /**\n * Custom inspector card for this aspect in the scene editor (immediate-mode — see\n * core/InspectorUI.ts): re-runs on every edit/event and emits a widget list. Without it, the\n * editor shows the inferred fields; `ui.auto()` emits those same fields, so a custom inspector\n * usually starts with `ui.auto()` and appends status lines / buttons / dynamic dropdowns:\n *\n * static inspector(ui: InspectorUI, self: MyAspect) {\n * ui.auto()\n * if (ui.button('Randomize')) self.rebuild()\n * }\n */\n static inspector?: (ui: InspectorUI, aspect: any) => void;\n /** Tick AFTER these classes within the same phase (`static after = [Controls]`). A constraint\n * always beats the numeric `updateOrder`. Classes absent from the phase are ignored. */\n static after?: Function[];\n /** Tick BEFORE these classes within the same phase (`static before = [Camera]`). */\n static before?: Function[];\n /** Every live instance of an aspect/system class, in attach order — the registry a game used to\n * hand-roll as `static all[]`. Live, read-only: copy it (`[...Aspect.all(Barrel)]`) before a loop\n * that detaches. Empty in the scene editor (aspects are inert data there). */\n static all<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): readonly A[];\n /** The node this aspect is attached to (set at attach time). For a System: the scene. */\n readonly node: P;\n /**\n * GENERATOR aspects (`static editor = { rebuild: true }`, attached through a scene file): a\n * scene-added container child for the aspect's generated output — `rebuild()` clears and refills\n * it. Provided by the scene loader before `onAttach`/`rebuild` run; nodes `add()`ed to it join\n * the scene's draw set automatically (membership is separate from parenting). Undefined for\n * aspects attached by hand outside scene files. See docs/3d/scene-files.md.\n */\n readonly generated: Node & {\n clear(): void;\n readonly version: number;\n };\n /**\n * GENERATOR aspects attached through a scene file: the `Scene` the host node was built into —\n * what `handle.instantiate({ scene })` / `scene.add()` need inside `rebuild()`. Set by the scene\n * loader (edit AND play mode); undefined for aspects attached by hand. 3D only (2D aspects own\n * their `scene` field). For a System: always set — the scene it is attached to.\n */\n readonly scene: P extends Node ? Scene : P extends SystemHost ? P : unknown;\n protected readonly __key__?: K;\n protected readonly __events__?: E;\n private _listeners?;\n /** The node (or scene) is set — initialize here, not in a constructor. */\n protected onAttach?(): void;\n /** Release what onAttach acquired. */\n protected onDetach?(): void;\n /** Called after `node.aspect(Ctor, opts)` re-assigns options on an ALREADY attached aspect (a\n * pre-attached one like `model.anim`): rebuild whatever was derived from the options at attach. */\n protected onReconfigure?(): void;\n /**\n * GENERATOR aspects: (re)build the derived output under `this.generated` — must be idempotent\n * (clear, then create). Call it from `onAttach()` for play mode; a class opting in with\n * `static editor = { rebuild: true }` ALSO runs it while a scene is being edited: once at load,\n * and again whenever an inspector prop changes or a `ref()`-referenced node moves.\n */\n rebuild?(): void;\n /**\n * LATE phase — every frame while attached, after the physics step + transform sync + animators,\n * right before the frame draws: reads of `node.worldPosition` are the final drawn position\n * (cameras/followers have no 1-frame lag) and what you write to a plain node is what this frame\n * shows. The default home for game logic. `dt` = GAME seconds since the last frame (`Time.scale`\n * applied; 0 while paused — see `updateWhilePaused`).\n */\n protected update?(dt: number): void;\n /**\n * EARLY phase — every frame BEFORE the physics step, so what you feed the simulation (velocity,\n * `controller.move()`, forces, kinematic transforms) is consumed by this same frame's step: zero\n * input latency. Use it only when you FEED the simulation. Reads here see last frame's settled\n * state. A class rarely needs both phases — that is two aspects on one node.\n */\n protected updateBefore?(dt: number): void;\n /**\n * FIXED phase - once per physics substep, BEFORE that substep's Jolt step, with `dt = Time.fixedDt`\n * (1/60) exactly, on every machine: under `Time.scale` the NUMBER of steps per frame changes, never\n * the dt (0-4 calls per frame). The home of simulation that must match another machine's - a\n * multiplayer player sim, dt-dependent motion that may not drift with the frame rate. `controller.move()`\n * / velocity writes here feed the same step; between steps the world is consistent, so `Physics.raycast`\n * is fine. Anything that looks at the screen (cameras, HUD, FX) stays in `updateBefore` / `update`.\n */\n protected updateFixed?(dt: number): void;\n /** Tick order within a phase and rank — ascending; default 0, ties keep attach order. A declared\n * `static after` / `static before` constraint always beats this number. Read once, at attach —\n * set it as a class field. */\n protected updateOrder: number;\n /** Keep ticking while `Time.paused` (a HUD fade, the pause menu). `dt` is still 0 then — read\n * `Time.unscaledDt` for wall-clock motion. Checked every frame; may be toggled at any time. */\n protected updateWhilePaused: boolean;\n /** Opt-in: only run update(dt) while the node is on-screen. NOOP for now — visibility culling isn't\n * wired yet, so every updater ticks regardless; declared so aspects can opt in ahead of it. */\n protected updateWhenVisible: boolean;\n /** Listen to one of this aspect's events. Chainable. Cleared on detach. */\n on<C extends keyof E & string>(channel: C, callback: E[C]): this;\n /** Remove a listener added with `on` (same function reference). */\n off<C extends keyof E & string>(channel: C, callback: E[C]): this;\n /** Fire one of this aspect's events. Protected: only the aspect itself emits. */\n protected emit<C extends keyof E & string>(channel: C, ...args: Parameters<E[C]>): void;\n}\n/**\n * An aspect of a SCENE: game logic with no single node to live on — input mapping, the FX pools, the\n * HUD, the game mode. Same lifecycle (`onAttach`/`onDetach`), same phases (`updateFixed` / `updateBefore` /\n * `update`), same ordering (`updateOrder`, `static after`) and events as a node aspect; `this.scene` is the\n * scene it was attached to. `S` = the scene kind (`Scene` by default, `Scene2D` for 2D games).\n *\n * class Hud extends System<'hud'> {\n * static after = [Player]\n * update(dt: number) { … }\n * }\n * scene.system(Hud) // attach\n * scene.hud // the typed accessor\n */\nexport declare abstract class System<K extends string, S extends SystemHost = Scene, E extends EventMap = {}> extends Aspect<K, S, E> {\n}\nexport {};\n","types/core/color.d.ts":"export type ColorInput = string | number | readonly [number, number, number] | readonly [number, number, number, number];\nexport declare const Color: {\n /** [r,g,b] in 0..1 — for the 2D engine's float color setters. */\n toRgb01(c: ColorInput): [number, number, number];\n /** [r,g,b,a] in 0..1. */\n toRgba01(c: ColorInput): [number, number, number, number];\n /** 0xRRGGBB packed int — for the 3D engine's color uniforms / skybox. */\n toPackedRgb(c: ColorInput): number;\n /** 0xRRGGBBAA packed int (unsigned). */\n toPackedRgba(c: ColorInput): number;\n /** '#rrggbbaa' (lower-case, always eight digits) — the UI wire form and the 3D material color. */\n toHexString(c: ColorInput): string;\n /** [r,g,b,a] in 0..1, or `null` when `c` is not a color — the non-throwing probe. */\n tryParse(c: unknown): [number, number, number, number] | null;\n};\n","types/core/compWrite.d.ts":"export type CompAxis = \"x\" | \"y\" | \"z\" | \"w\";\n/** Implemented by a class whose vector getters accept component writes (see above). The class also\n * carries `static _comps: string[]` naming those getters — compile-time data, absent at runtime. */\nexport interface CompWriter {\n _writeComp(prop: string, axis: CompAxis, value: number): void;\n}\n/** `<o>.<prop>.<axis> = value`, routed to the owner when it has the hook. Returns the value. */\nexport declare const __compWrite: (o: any, prop: string, axis: CompAxis, value: number) => number;\n/** `<o>.<prop>.<axis> op= v` — `op`: 0 `+=`, 1 `-=`, 2 `*=`, 3 `/=`. The current component is read\n * through the normal getter (one fresh vector), the result written like `__compWrite`. */\nexport declare const __compOp: (o: any, prop: string, axis: CompAxis, op: number, v: number) => number;\n","types/core/events.d.ts":"export type EventMap = Record<string, (...args: any[]) => void>;\nexport declare class Emitter<E extends EventMap> {\n private _listeners;\n addEventListener<K extends keyof E>(channel: K, callback: E[K]): void;\n removeEventListener<K extends keyof E>(channel: K, callback: E[K]): void;\n /** Fire all listeners on a channel. Protected: only the owning class emits. */\n protected dispatch<K extends keyof E>(channel: K, ...args: Parameters<E[K]>): void;\n protected hasListeners<K extends keyof E>(channel: K): boolean;\n /** Drop every listener on every channel (used when the owning object is disposed). */\n protected clearListeners(): void;\n}\n","types/core/fields.d.ts":"/** Editor widget kinds the inspector knows how to render. `\"node\"` = a scene-node reference\n * (`ref('name')` in the file, name dropdown + pick-in-viewport in the inspector) — declare it via\n * `static fields` on fields typed `Node | null`; a `Node | null` type annotation is also picked\n * up syntactically by the editor's source scan. `\"asset\"` = a project-asset path (the editor\n * fills the dropdown with the project's GLBs — `ui.asset()` in windows/tools/cards). */\nexport type FieldEditor = \"number\" | \"text\" | \"color\" | \"switch\" | \"select\" | \"vec2\" | \"vec3\" | \"vec4\" | \"node\" | \"asset\";\nexport type FieldMetaEntry = {\n /** Inspector label (default: the field name). */\n label?: string;\n min?: number;\n max?: number;\n step?: number;\n /** Allowed values — renders a dropdown (editor \"select\"). */\n options?: readonly (string | number)[];\n /** Override the editor inferred from the default value. */\n editor?: FieldEditor;\n /** Exclude the field from the inspector. */\n hidden?: boolean;\n};\n/** Declared on an aspect class as `static fields: FieldMeta<MyAspect> = { … }`. All optional. */\nexport type FieldMeta<T = unknown> = {\n [K in Extract<keyof T, string>]?: FieldMetaEntry;\n};\n/** One editable field: key + default value + resolved editor + merged metadata. */\nexport type FieldDescriptor = {\n key: string;\n label: string;\n /** The default value (from a freshly constructed instance; undefined if only declared in meta). */\n value: unknown;\n /** Resolved editor kind; undefined = no editor known (inspector shows it read-only). */\n editor: FieldEditor | undefined;\n min?: number;\n max?: number;\n step?: number;\n options?: readonly (string | number)[];\n};\nexport type AspectClassInfo = {\n /** The accessor name (`static aspect`, injected by chisel for user aspects). */\n name: string;\n className: string;\n fields: FieldDescriptor[];\n /** True for editor-run classes (`static editor` — generators). The editor routes their\n * structural changes through a re-run instead of a live patch. */\n editor?: boolean;\n /** True when the class declares a custom `static inspector(ui, aspect)` card. */\n inspector?: boolean;\n};\n/** Infer the editor widget from a default value's shape. */\nexport declare const inferFieldEditor: (value: unknown) => FieldEditor | undefined;\n/**\n * Enumerate the editable fields of a class: construct a default instance, take its own enumerable\n * non-underscore fields (minus the Aspect base plumbing), infer editors from the default values, and\n * merge the class's optional `static fields` metadata (which can also add keys that have no runtime\n * default, e.g. fields declared without an initializer).\n */\nexport declare const describeFields: (ctor: abstract new () => unknown) => FieldDescriptor[];\n/** Describe an aspect class for the inspector: accessor name + class name + editable fields. */\nexport declare const describeAspect: (ctor: abstract new () => unknown) => AspectClassInfo;\n","types/core/InspectorUI.d.ts":"import type { FieldEditor } from \"./fields\";\n/** One user interaction coming back from the editor panel: the widget's id (+ value for fields). */\nexport type InspectorEvent = {\n id: string;\n value?: unknown;\n};\nexport type InspectorFieldWidget = {\n kind: \"field\";\n id: string;\n /** The bound key — an aspect field (doc-bound) or an editor-state key. */\n key: string;\n label: string;\n editor: FieldEditor | undefined;\n value: unknown;\n /** True = persisted to the scene file by the editor; false = transient editor state. */\n doc: boolean;\n /** True = emitted by `ui.auto()` — the editor may overlay its syntactic hints (options/node). */\n auto?: boolean;\n min?: number;\n max?: number;\n step?: number;\n options?: readonly (string | number)[];\n};\nexport type InspectorWidget = InspectorFieldWidget | {\n kind: \"button\";\n id: string;\n label: string;\n} | {\n kind: \"toolButton\";\n id: string;\n label: string;\n tool: string;\n} | {\n kind: \"header\";\n id: string;\n label: string;\n} | {\n kind: \"info\" | \"warn\";\n id: string;\n text: string;\n};\ntype FieldOpts = {\n label?: string;\n min?: number;\n max?: number;\n step?: number;\n /** Default for EDITOR-STATE keys (doc keys default from the class field). */\n value?: unknown;\n};\n/**\n * The widget builder handed to `static inspector(ui, aspect)` (and to editor windows/tools later).\n * One instance lives per card and persists across runs — it carries the card's editor state.\n */\nexport declare class InspectorUI {\n /** Numeric field (min/max/step render as a slider-style scrub range). */\n number(key: string, opts?: FieldOpts): number;\n /** Alias of `number` — give it min/max/step and the editor renders a scrubable range. */\n slider(key: string, opts?: FieldOpts): number;\n text(key: string, opts?: FieldOpts): string;\n color(key: string, opts?: FieldOpts): string;\n switch(key: string, opts?: FieldOpts): boolean;\n /** Dropdown — `options` may be computed fresh every run (dynamic lists come free). */\n select(key: string, options: readonly (string | number)[], opts?: FieldOpts): string | number;\n vec2(key: string, opts?: FieldOpts): [number, number];\n vec3(key: string, opts?: FieldOpts): [number, number, number];\n vec4(key: string, opts?: FieldOpts): [number, number, number, number];\n /** Scene-node reference (`ref()` fields): name dropdown + pick-in-viewport. Returns the RAW doc\n * value (`{ $ref }` marker or null) — read the resolved live node off the aspect instance. */\n node(key: string, opts?: FieldOpts): unknown;\n /** Project-asset path (the editor renders a dropdown of the project's GLBs). \"\" = none picked. */\n asset(key: string, opts?: FieldOpts): string;\n /** True on the run that consumes this button's click — do the action right there. */\n button(label: string, opts?: {\n id?: string;\n }): boolean;\n /** A toggle that activates/deactivates the named viewport tool (`registerEditorTool`). The\n * editor owns the active-tool state — the click never round-trips into the scene world. */\n toolButton(label: string, tool: string): void;\n header(label: string): void;\n info(text: string): void;\n warn(text: string): void;\n /** Emit the inferred field widgets (all declared aspect fields, or just the named ones) — the\n * zero-ceremony baseline; append custom widgets around it. */\n auto(...keys: string[]): void;\n private _vec;\n private _field;\n}\nexport {};\n","types/core/pins.d.ts":"/** The handle of a wrapper whose resource is gone: `id` 0, nothing to finalize. Replacing `_h`\n * with it drops the real handle, so the runtime's record can go. */\nexport declare const DEAD_HANDLE: Handle;\nexport interface Pinned {\n readonly _h: Handle;\n /** The runtime freed the resource underneath (an ancestor's free): mark the wrapper dead. */\n _freed?(): void;\n}\nexport declare class Pins<T extends Pinned> {\n private readonly map;\n /** Keep `obj` alive and findable while native owns its resource. */\n pin(obj: T | null | undefined): void;\n unpin(id: number): void;\n get(id: number): T | undefined;\n has(id: number): boolean;\n /** The runtime freed these resources: drop the pins, tell the wrappers. */\n freed(ids: number[]): void;\n}\n","types/core/signals.d.ts":"/** Runs every pending effect now instead of waiting for the microtask (test/host hook). */\nexport declare const flushEffects: () => void;\nexport interface Signal<T> {\n value: T;\n /** Read without subscribing the current effect/computed. */\n peek(): T;\n}\nexport interface Computed<T> {\n readonly value: T;\n /** Read without subscribing the current effect/computed (still recomputes if stale). */\n peek(): T;\n}\n/**\n * A reactive value. Reading `.value` inside an `effect`/`computed` (or a function-valued style\n * prop / `UIText` content) subscribes it; writing `.value` re-runs subscribers (batched — once\n * per microtask).\n */\nexport declare function signal<T>(initialValue: T): Signal<T>;\nexport declare function signal<T = undefined>(): Signal<T | undefined>;\n/** A lazily-cached derived value: recomputes on read after any of its dependencies changed. */\nexport declare function computed<T>(fn: () => T): Computed<T>;\n/**\n * Runs `fn` now and again whenever any signal/computed it read changes (batched per microtask).\n * Returns a dispose function; an undisposed effect lives for the rest of the app run.\n */\nexport declare function effect(fn: () => void): () => void;\n/** The shape UINode's Element exposes for binding ownership. */\nexport interface BindingHost {\n}\n","types/core/StateMachine.d.ts":"export type StateGuard<C> = (ctx: C, t: number) => boolean;\nexport type StateHandler<C> = (ctx: C, ...args: any[]) => string | void;\nexport interface StateDef<C> {\n /** The child entered by default when this (compound) state is entered. */\n initial?: string;\n /** Child states — this becomes a compound state; only a leaf is ever \"the\" state. */\n states?: Record<string, StateDef<C>>;\n /** Entered (from = the previous leaf's path, '' at start). */\n enter?: (ctx: C, from: string) => void;\n /** Left (to = the next leaf's path). */\n exit?: (ctx: C, to: string) => void;\n /** Every step while active, outer states first; `t` = seconds in this state. Return a state name\n * to transition. */\n update?: (ctx: C, dt: number, t: number) => string | void;\n /** Guarded transitions, tested every step before `update` — key = target, first true wins. */\n to?: Record<string, StateGuard<C>>;\n /** Leave for `target` after `seconds` in this state. */\n after?: [seconds: number, target: string];\n /** Event handlers for `send(name, …args)`: a target name, or a function returning one (or nothing). */\n on?: Record<string, string | StateHandler<C>>;\n}\nexport interface StatesDef<C> {\n initial: string;\n states: Record<string, StateDef<C>>;\n /** Any-state guards — tested first, in every state. */\n to?: Record<string, StateGuard<C>>;\n /** Any-state event handlers — the fallback when no active state handles the event. */\n on?: Record<string, string | StateHandler<C>>;\n /** Any-state update, runs before the active states' own. */\n update?: (ctx: C, dt: number, t: number) => string | void;\n}\nexport type StateMachineEvents = {\n /** After a transition completed (both are leaf paths; `from` = '' for the initial entry). */\n change: (to: string, from: string) => void;\n};\n/** Identity helper — names the context type once so every callback is typed. */\nexport declare const defineStates: <C>(def: StatesDef<C>) => StatesDef<C>;\nexport declare class StateMachine<C> {\n readonly ctx: C;\n private readonly root;\n private readonly byPath;\n /** the active branch, root's child (index 0) → leaf */\n private chain;\n private prev;\n private listeners;\n private changed;\n constructor(def: StatesDef<C>, ctx: C);\n /** The active leaf's path ('combat.shoot'). */\n get state(): string;\n /** The leaf we came from ('' before the first transition). */\n get previous(): string;\n /** Seconds in the active leaf. */\n get time(): number;\n /** Every active state's path, outermost first. */\n get branch(): string[];\n /** Is `name` (a state name or dotted path) active — as the leaf OR as one of its ancestors? */\n is(name: string): boolean;\n /** Seconds in the named active state (0 when it is not active). */\n timeIn(name: string): number;\n /** Force a transition (a spawn, a reset from outside the table). */\n go(name: string): void;\n /** Deliver an event. Innermost active state first, the root's `on` last. True if handled. */\n send(event: string, ...args: unknown[]): boolean;\n /** One tick: clocks, guards (outer first, chained), then updates (outer first). */\n step(dt: number): void;\n /** Listen for transitions. */\n on(event: \"change\", fn: StateMachineEvents[\"change\"]): this;\n off(event: \"change\", fn: StateMachineEvents[\"change\"]): this;\n private build;\n private link;\n private resolveStrict;\n /** Relative first (siblings of `from`, then of each ancestor), then a dotted path from the root. */\n private resolve;\n /** Guards never re-enter a state that is already active (a `dead` guard staying true does not\n * re-enter `dead` every step) — only an explicit `go()` / event does that. */\n private findTransition;\n private active;\n private leafOf;\n private transition;\n private enterBranch;\n}\n","types/core/time.d.ts":"declare class TimeClock {\n private _scale;\n private _paused;\n /** The fixed step: what `updateFixed(dt)` receives, every time, on every machine (1/60). Under\n * `scale` the NUMBER of fixed steps per frame changes, never this value. */\n readonly fixedDt: number;\n /** Seconds of GAME time since the app started (scaled; stops while paused). */\n now: number;\n /** Seconds of wall-clock time since the app started (never stops). */\n unscaledNow: number;\n /** This frame's delta in game seconds — what `update(dt)` receives. 0 while paused. */\n dt: number;\n /** This frame's wall-clock delta in seconds (the host's frame time, clamped by the engine). */\n unscaledDt: number;\n /** Frames dispatched since the app started (counts paused frames too). */\n frame: number;\n /** Speed of the game relative to wall-clock: 1 normal, 0.5 half speed, 2 double. Applied to\n * `dt`, `now` AND the engines' physics / animation / particle clocks. Negative or NaN → 0. */\n get scale(): number;\n set scale(v: number);\n /** Freeze the game: `dt` reads 0, aspects without `updateWhilePaused` are skipped, the engines'\n * simulations stop. `scale` is remembered and restored on resume. */\n get paused(): boolean;\n set paused(v: boolean);\n /** The scale the engines currently run at (0 while paused). */\n get effectiveScale(): number;\n private _push;\n}\n/** The game clock — scale / pause the whole game, read `dt` / `now` anywhere. */\nexport declare const Time: TimeClock;\nexport {};\n","types/g2/autotile.d.ts":"/** A fill entry: an atlas index, or [index, weight] for seeded scatter variants. */\nexport type FillEntry = number | [number, number];\nexport type Dir4 = [number, number, number, number];\n/** One side's tiles: a single index (used for every cell along that side), or — with `size` > 1 —\n * the `size` indices ALONG it (n/s run left→right, w/e run top→bottom). */\nexport type EdgeSlot = number | number[];\n/** A whole `size`×`size` piece: one index (drawn in every cell of the block), or size² indices\n * row-major. Path pieces and parts are blocks — at size 1 they are just a tile. */\nexport type TileBlock = number | number[];\n/** `size`² indices, row-major within the block. */\nexport type FillBlock = number[];\n/** A named element placed BY HAND (a pedestrian crossing in a road, a gate in a fence). It carries\n * its own `id`, so the map stores it like any material — but it CONNECTS as its parent, so the\n * run continues straight through it. Never picked at random: you paint it from the palette, ONE\n * CELL at a time, and the tile is worked out from where that cell sits. */\nexport type TilePart = {\n /** Stable small int, unique across every material and part of the tileset. */\n id: number;\n /** Which run the art is drawn for — 'v' vertical, 'h' horizontal. It also picks the art: the\n * element varies ACROSS the line (a crossing has one tile per lane) and repeats along it, so\n * `tiles` is `size` long, indexed by row for 'h' and by column for 'v'. */\n axis?: \"v\" | \"h\";\n /** The tiles — one index, `size` across the run when `axis` is set, else the size² block. */\n tiles?: TileBlock;\n};\n/** A block variant: the block, or [block, weight] for seeded scatter. */\nexport type BlockEntry = FillBlock | [FillBlock, number];\n/** One transition set of a patch material — the tiles its border shows against a neighbor. */\nexport type PatchSlots = {\n /** Edge line tiles [n, e, s, w] — e.g. `edges[0]` draws where the patch stops toward the top. */\n edges?: [EdgeSlot, EdgeSlot, EdgeSlot, EdgeSlot];\n /** Convex corner tiles [ne, se, sw, nw] — the patch's outside corners. Always one cell. */\n outer?: Dir4;\n /** Concave corner tiles [ne, se, sw, nw] — the notch where two patch arms meet. One cell. */\n inner?: Dir4;\n};\nexport type PatchMaterial = {\n /** Stable small int — what `cells('…')` stores when a map carries Autotile2D. */\n id: number;\n kind: \"patch\";\n /** Editor swatch color ('#4a7c3a'). */\n color?: string;\n /** Block size in cells (default 1). With 2 or 3 the material is classified block-to-block on a\n * lattice anchored at the map origin, `fill` holds size² tiles and each edge `size` tiles. */\n size?: number;\n /** Interior tile — one index, or an ARRAY of scatter variants (each `index` or\n * `[index, weight]`; bare indices weigh 1): `fill: [261, [262, 0.1], [263, 0.05]]`.\n * With `size` > 1 it is instead the row-major BLOCK of size² indices\n * (`fill: [130, 131, 146, 147]`), or a list of such blocks for scatter variants. */\n fill: number | FillEntry[] | BlockEntry[];\n /** Transition sets keyed by the neighboring material's name; '*' = any other neighbor\n * (including empty). Baked packs draw a material fading into a SPECIFIC background. */\n over?: Record<string, PatchSlots>;\n /** Hand-placed elements that connect as this material (see TilePart). */\n parts?: Record<string, TilePart>;\n};\nexport type PathMaterial = {\n id: number;\n kind: \"path\";\n color?: string;\n /** Cells ACROSS the line (default 1). A `size: 2` road is two lanes wide: connectivity runs\n * block to block and every piece below is a 2×2 block instead of one tile. */\n size?: number;\n /** No connections at all. */\n isolated?: TileBlock;\n /** End caps [n, e, s, w] — `ends[0]` connects toward the top only. */\n ends?: [TileBlock, TileBlock, TileBlock, TileBlock];\n /** [vertical (n+s), horizontal (e+w)]. */\n straights?: [TileBlock, TileBlock];\n /** Elbows [ne, se, sw, nw] — `corners[0]` connects top + right. */\n corners?: [TileBlock, TileBlock, TileBlock, TileBlock];\n /** T pieces [n, e, s, w] — `tees[0]` is the tee MISSING the top connection. */\n tees?: [TileBlock, TileBlock, TileBlock, TileBlock];\n /** All four connections. */\n cross?: TileBlock;\n /** Hand-placed elements that connect as this material (see TilePart). */\n parts?: Record<string, TilePart>;\n};\nexport type TileMaterial = PatchMaterial | PathMaterial;\nexport type TilesetDef = {\n /** The atlas image — write `asset('./TileSet.png')`. */\n image: string;\n /** Atlas cell size in image pixels — a number (square) or [w, h]. */\n tile: number | [number, number];\n /** Named materials; names are the editor/`over:` vocabulary, `id`s are what maps store. */\n materials?: Record<string, TileMaterial>;\n};\nexport declare const normalizeFill: (fill: number | FillEntry[]) => [number, number][];\n/** A material's block size — 1 unless it declares `size` (clamped to a positive int). */\nexport declare const blockSize: (mat: TileMaterial) => number;\n/** One cell of a block: a scalar covers the whole block, an array reads row-major. Undefined =\n * unassigned (missing, or the negative sentinel the editor writes for a blank slot). */\nexport declare const blockTile: (block: TileBlock | undefined, n: number, lx: number, ly: number) => number | undefined;\n/** How many tiles a part holds: `size` across the run when it declares an axis, else the block. */\nexport declare const partSlots: (part: TilePart, n: number) => number;\n/** The cell value that draws atlas tile `index` verbatim in a material map. */\nexport declare const rawCell: (index: number) => number;\n/** True for a cell holding a raw atlas tile rather than a material id. */\nexport declare const isRawCell: (v: number) => boolean;\n/** The atlas index behind a raw cell (garbage in, garbage out — guard with isRawCell). */\nexport declare const rawIndex: (v: number) => number;\nexport declare const TILE_INDEX_MASK = 268435455;\n/** The atlas index behind a (possibly oriented) tile value. */\nexport declare const tileIndex: (v: number) => number;\n/** Clockwise quarter-turns (0–3) of a tile value. */\nexport declare const tileTurns: (v: number) => number;\n/** Whether the tile is mirrored horizontally (the mirror applies before the rotation). */\nexport declare const tileFlip: (v: number) => boolean;\n/** True when the value carries any orientation (renderers keep the fast path otherwise). */\nexport declare const tileOriented: (v: number) => boolean;\n/** Build an oriented tile value: `index`, mirrored when `flip`, then `turns` quarter-turns CW. */\nexport declare const packTile: (index: number, turns?: number, flip?: boolean) => number;\n/** The value rotated a further 90° clockwise. */\nexport declare const rot90: (v: number) => number;\n/** The value rotated a further 180°. */\nexport declare const rot180: (v: number) => number;\n/** The value rotated a further 270° clockwise (90° counter-clockwise). */\nexport declare const rot270: (v: number) => number;\n/** The value mirrored horizontally (on screen — existing turns are re-based, group math). */\nexport declare const flipX: (v: number) => number;\n/** The tile a part draws in a cell — indexed ACROSS the run ('h' by row, 'v' by column) so one\n * element covers a lane each and repeats along the run; without an axis it is a plain block. */\nexport declare const partTile: (part: TilePart, n: number, lx: number, ly: number) => number | undefined;\n/** `fill` as weighted BLOCKS of `size`² indices (row-major). Size 1 keeps the scalar/scatter\n * reading; with size > 1 a flat number array is one positional block, an array of arrays is the\n * variant list, and a bare number fills the whole block. Missing entries read as -1. */\nexport declare const fillBlocks: (fill: PatchMaterial[\"fill\"], size?: number) => [number[], number][];\n/**\n * Derive display atlas indices from a material-id grid (row-major, row 0 = top, -1 = empty).\n * Values that match no material id pass through unchanged (so converting maps degrades\n * gracefully); -1 stays -1. Deterministic: same inputs + seed → same output on every platform.\n */\nexport declare const deriveCells: (def: TilesetDef, cols: number, rows: number, cells: ArrayLike<number>, seed?: number) => Int32Array;\n","types/g2/Camera2D.d.ts":"import { Vec2, type Vec2Like } from \"../math/vec\";\nimport type { CompAxis, CompWriter } from \"../core/compWrite\";\nexport declare class Camera2D implements CompWriter {\n private _x;\n private _y;\n private _zoom;\n private _rotation;\n private readonly sceneId;\n constructor(sceneId: number);\n get position(): Vec2;\n set position(v: Vec2Like);\n _writeComp(_prop: string, axis: CompAxis, v: number): void;\n get zoom(): number;\n set zoom(z: number);\n get rotation(): number;\n set rotation(deg: number);\n screenToWorld(screenX: number, screenY: number): Vec2;\n worldToScreen(worldX: number, worldY: number): Vec2;\n}\n","types/g2/cells.d.ts":"export type CellsData = {\n cols: number;\n rows: number;\n /** Row-major tile values (row 0 = the top row), length cols*rows. */\n data: Int32Array;\n};\n/** Encode a grid into a `cells()` payload (the editor / tools side of the codec). */\nexport declare const encodeCells: (cols: number, rows: number, data: ArrayLike<number>) => string;\n/**\n * Decode a `cells('…')` payload into the grid a tilemap block consumes. Scene files call this via\n * the injected global; the value is plain data, so hand-written code may pass any\n * `{ cols, rows, data }` of its own instead (procedural maps).\n */\nexport declare const cells: (payload: string) => CellsData;\n","types/g2/CharacterController2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { FieldMeta } from \"../core/fields\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport type { CompWriter } from \"../core/compWrite\";\nimport { PhysicsGroup2D } from \"./groups2d\";\nimport { type Node2D } from \"./Node2D\";\n/** Where the character's feet are, as reported by the solver after the last step. */\nexport type GroundState2D = \"ground\" | \"slope\" | \"air\";\n/** One surface the mover pushed out of this step. `normal` points back at the character. */\nexport type Collision2D = {\n node: Node2D | null;\n normal: Vec2;\n};\nexport declare class CharacterController2D extends Aspect<\"controller\", Node2D> implements CompWriter {\n static readonly aspect = \"controller\";\n static fields: FieldMeta<CharacterController2D>;\n private _id;\n private _gravityScale;\n private _maxSlope;\n private _group;\n private _dropThrough;\n private _repush;\n onAttach(): void;\n onDetach(): void;\n /** Native character id (0 until attached / no physics support). */\n get id(): number;\n /**\n * This frame's movement command, in world units/s — NOT normalized, NOT a per-frame displacement\n * (that is what Unity's `Move` takes; passing `v * dt` here gives a character 60× too slow).\n *\n * ONE component = horizontal, the everyday platformer call. TWO = the whole velocity, for free mode\n * (`gravityScale = 0`); with gravity on, a two-component call fights the ballistic vertical and the\n * character hangs in the air, so that combination warns once.\n *\n * Sticky only within the frame: the command expires once the engine consumes it. It also **takes the\n * axis back from a latched `velocity`** — commanding is claiming ownership, which is what keeps the\n * two horizontal sources from ever fighting.\n */\n move(x: number): void;\n move(x: number, y: number): void;\n move(v: Vec2Like): void;\n private _warnFree;\n /** Vertical velocity (world units/s) — LATCHED: gravity works on it, you seed it. `= 700` to jump,\n * `+= 300` to stack an explosion on top of the current motion. No ground check: guard it yourself\n * with `grounded` (or don't, for a double jump). Does nothing in free mode. `velocity.y = 700` is\n * the same channel — pick whichever reads better. */\n get velocityY(): number;\n set velocityY(v: number);\n /**\n * READ — the velocity the solver ended up with after the most recent step (world units/s, fresh\n * Vec2): what HAPPENED, not what you asked for. Walking into a wall reads ~0, sliding along one\n * reads the tangent.\n *\n * WRITE — LATCH the whole velocity: a knockback, a wall jump, a launch pad. Unlike `move()` it does\n * not expire, so the character keeps flying, and gravity still pulls the vertical down into a real\n * ballistic arc. It stays until `move()` takes the axis back — so a game simply doesn't call\n * `move()` while the throw lasts, and ends it on its own terms:\n *\n * hero.controller.velocity = [dir.x * 600, 400] // hit by the blast\n * if (thrown) { if (hero.controller.grounded) thrown = false } // landing ends it\n * else hero.controller.move(ix * SPEED) // …and this reclaims the axis\n *\n * Nothing clears the latch by itself, landing included — a kinematic controller has no friction.\n * Reading is not the inverse of writing: against a wall the read is ~0 and would cancel the throw.\n *\n * `c.velocity.y = 700` (the direct spelling) is a jump — the compiler routes it to the exact\n * `velocityY` channel via `_writeComp` below — and `c.velocity.x = 300` latches the whole vector\n * with the measured vertical filling in. A STORED copy is still a copy (`const v = c.velocity`).\n */\n get velocity(): Vec2;\n set velocity(v: Vec2Like);\n /** Compile-time list (chisel reads it, then strips it) — see CharacterController / core/compWrite.ts. */\n static _comps: string[];\n /** True while standing on walkable ground. */\n get grounded(): boolean;\n /** Where the feet are after the last step: walkable ground, too-steep ground, or the air. */\n get groundState(): GroundState2D;\n /** The surface normal under the feet — for orienting a sprite to a slope, or deciding a slide. */\n get groundNormal(): Vec2;\n /** What the character is standing on: a moving platform, a hazard, an ice patch whose `friction`\n * the game can read. The engine already carries the character along a kinematic platform. */\n get groundNode(): Node2D | null;\n /**\n * Every surface the mover pushed out of during the last step, with the normal pointing back at the\n * character. This is what wall jumps and box pushing are written against — a kinematic mover is not\n * a body, so those contacts do not arrive as 'enter' events.\n *\n * const wall = c.collisions.find(h => Math.abs(h.normal.x) > 0.7)\n * if (wall && jumpPressed) c.velocity = [-wall.normal.x * KICK, JUMP]\n *\n * for (const h of c.collisions) h.node?.physics?.applyImpulse([-h.normal.x * PUSH, 0])\n */\n get collisions(): Collision2D[];\n /** Multiplier over the world gravity; default 1. **0 = free mode**: no gravity, no ground, no\n * stick-to-floor — a swimmer, a drone, a ladder climber, or a top-down hero, driven by the\n * two-component `move()`. */\n get gravityScale(): number;\n set gravityScale(v: number);\n /** Max ground slope (degrees) the character treats as walkable; default 45. Live. */\n get maxSlope(): number;\n set maxSlope(v: number);\n /** Which collision group the character belongs to. Live. */\n get group(): PhysicsGroup2D | undefined;\n set group(g: PhysicsGroup2D | undefined);\n /**\n * While this names a node, that node's `OneWay2D` surfaces are not solid for this character — how\n * you drop off a semisolid platform. A plain latch: whoever sets it clears it.\n *\n * if (downPressed && jumpPressed && c.grounded) {\n * const platform = c.groundNode\n * c.dropThrough = platform\n * setTimeout(() => { if (c.dropThrough === platform) c.dropThrough = null }, 200)\n * }\n *\n * Because it names ONE node, the timeout is not delicate: too long merely means you could have\n * re-landed on that platform for a moment, and the platform below stays solid either way.\n */\n get dropThrough(): Node2D | null;\n set dropThrough(n: Node2D | null);\n /**\n * True while a requested collider resize hasn't taken — you asked to stand up and there is something\n * overhead. Resizing goes through the `Shape2D` aspect itself:\n *\n * hero.aspect(Shape2D, { capsule: CROUCHED }) // always fits — you are shrinking\n * hero.aspect(Shape2D, { capsule: STANDING }) // may be refused under a low ceiling\n * if (hero.controller.resizing) … // still crouched; call it again next frame\n *\n * A refusal changes nothing, so the retry is just the same call again — and it is an exact headroom\n * test against the real capsule, unlike a hand-rolled raycast (a ray is a line; a capsule has\n * girth). The FEET stay planted across a resize, so the character neither hovers nor sinks.\n */\n get resizing(): boolean;\n private _state;\n}\n","types/g2/defineScene2d.d.ts":"import type { ColorInput } from \"../core/color\";\nimport type { Vec2Like } from \"../math/vec\";\nimport { type AspectEntry, type MakeEntry as SharedMakeEntry } from \"../scene/grammar\";\nimport { Scene2D } from \"./Scene2D\";\nimport { Node2D } from \"./Node2D\";\nimport { Sprite } from \"./Sprite\";\nimport { Tilemap } from \"./Tilemap\";\nimport { SpriteSheet } from \"./SpriteSheet\";\nimport type { SpriteAnimation } from \"./SpriteAnimation\";\nimport type { CellsData } from \"./cells\";\nimport type { With } from \"../core/Aspect\";\nexport type Scene2dEnv = {\n /** Background color — '#5a6b3b', 0x5a6b3b, or [r,g,b] in 0..1. */\n background?: ColorInput;\n /** Texture sampling: 'nearest' (crisp pixel art, engine default) or 'linear'. */\n filter?: \"nearest\" | \"linear\";\n /** Pixel-art crispness: snap the camera to whole screen pixels (seeds CameraFollow's\n * `pixelSnap`, and the initial camera position lands on whole world units). */\n pixelPerfect?: boolean;\n /** Physics world gravity (Y-up: down is negative). Presence configures the world before any\n * body is created — `[0, 0]` for top-down worlds. Omit to leave the world unconfigured. */\n gravity?: Vec2Like;\n};\n/** A sprite node: one named entry of an imported `.sprite.ts` sheet. The sheet is ART only —\n * colliders/bodies are scene semantics: put Shape2D / Physics2D / Trigger2D in `aspects`. */\nexport type SpriteSourceDef = {\n /** The imported sheet handle: `import props from './props.sprite'` … `sheet: props`. */\n sheet: SpriteSheet;\n /** The entry name; omit when the sheet declares exactly one sprite. */\n name?: string;\n /** Start this clip immediately (sliced entries with clips). */\n clip?: string;\n /** Initial facing for `perDirection` clips. */\n direction?: string;\n};\nexport type TilemapSourceDef = {\n /** The tileset image — `asset('./TileSet.png')`. */\n texture: string;\n /** On-screen cell size in world units — a number (square) or [w, h]. */\n tile: number | [number, number];\n /** Atlas grid: how the texture slices into tiles, [atlasCols, atlasRows]. */\n atlas: [number, number];\n /** The map: a `cells('…')` payload — or any `{ cols, rows, data }` of your own. */\n cells: CellsData | {\n cols: number;\n rows: number;\n data: number[] | Int32Array;\n };\n};\n/** A camera marker node: seeds the scene camera's starting position (+ zoom). To MOVE the camera\n * in play, attach `CameraFollow` to the node being followed — not aspects on this marker. */\nexport type Camera2dNodeDef = {\n zoom?: number;\n};\nexport type Scene2dNodeDef = {\n sprite?: SpriteSourceDef;\n tilemap?: TilemapSourceDef;\n camera?: Camera2dNodeDef;\n /** A code-built subtree — `make(factoryFn, { ...literal args })`, factory returns a Node2D. */\n make?: SharedMakeEntry<any, Node2D>;\n position?: Vec2Like;\n /** Degrees, CCW. */\n rotation?: number;\n scale?: Vec2Like | number;\n /** Draw layer (int) — higher renders on top. */\n layer?: number;\n /** Intra-layer depth for non-Y-sorted layers. */\n z?: number;\n /** Sprite tint (sprite nodes only). */\n color?: ColorInput;\n /** Sprite opacity 0..1 (sprite nodes only). */\n opacity?: number;\n flipX?: boolean;\n flipY?: boolean;\n visible?: boolean;\n /** Editor-only: the move gizmo won't target this node (fields still edit). No runtime effect. */\n locked?: boolean;\n aspects?: readonly AspectEntry<any>[];\n children?: Record<string, Scene2dNodeDef>;\n};\nexport type Scene2dCameraDef = {\n position?: Vec2Like;\n zoom?: number;\n};\nexport type Scene2dDef = {\n env?: Scene2dEnv;\n /** Per-layer config, keyed by layer number: `layers: { 1: { ySort: true } }`. */\n layers?: Record<number | string, {\n ySort?: boolean;\n }>;\n /** Starting camera when there's no camera NODE (a camera node wins). */\n camera?: Scene2dCameraDef;\n nodes?: Record<string, Scene2dNodeDef>;\n};\ntype SourceNodeOf<N extends Scene2dNodeDef> = N extends {\n sprite: {\n clip: string;\n };\n} ? Sprite & {\n anim: SpriteAnimation;\n} : N extends {\n sprite: SpriteSourceDef;\n} ? Sprite : N extends {\n tilemap: TilemapSourceDef;\n} ? Tilemap : Node2D;\ntype AspectsOf<N extends Scene2dNodeDef> = N extends {\n aspects: readonly AspectEntry<infer A>[];\n} ? A : never;\ntype NodeOf<N extends Scene2dNodeDef> = [\n AspectsOf<N>\n] extends [never] ? SourceNodeOf<N> : With<SourceNodeOf<N>, AspectsOf<N>>;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\ntype ChildMapsOf<T extends Record<string, Scene2dNodeDef>> = {\n [K in keyof T]: T[K] extends {\n children: infer C extends Record<string, Scene2dNodeDef>;\n } ? NodesOf<C> : never;\n}[keyof T];\ntype NodesOf<T extends Record<string, Scene2dNodeDef>> = {\n [K in keyof T]: NodeOf<T[K]>;\n} & ([ChildMapsOf<T>] extends [never] ? unknown : UnionToIntersection<ChildMapsOf<T>>);\nexport type Scene2dNodes<D extends Scene2dDef> = D[\"nodes\"] extends Record<string, Scene2dNodeDef> ? NodesOf<D[\"nodes\"]> : Record<string, Node2D>;\nexport type LoadedScene2d<D extends Scene2dDef> = {\n scene: Scene2D;\n nodes: Scene2dNodes<D>;\n};\nexport declare class Scene2dHandle<D extends Scene2dDef = Scene2dDef> {\n readonly def: D;\n private _loading?;\n constructor(def: D);\n /** Instantiate the scene (idempotent — subsequent calls return the same instance). Does not open. */\n load(): Promise<LoadedScene2d<D>>;\n /** Load and make active (only the active 2D scene renders). */\n open(): Promise<LoadedScene2d<D>>;\n}\n/**\n * Define a 2D scene as data — the default export of a `.scene2d.ts` file. Returns a typed handle:\n * `const { scene, nodes } = await handle.open()` gives `nodes.<name>` typed by its source block\n * (Sprite / Tilemap / Node2D) with its `use(...)`d aspects attached.\n */\nexport declare const defineScene2d: <const D extends Scene2dDef>(def: D) => Scene2dHandle<D>;\nexport {};\n","types/g2/groups2d.d.ts":"/** Collides with everything. */\nexport declare const ALL_GROUPS = 4294967295;\nexport declare class PhysicsGroup2D {\n /** The single category bit this group owns. */\n readonly bit: number;\n /** Optional debug label, so an inspector says \"bullets\" rather than \"group #3\". */\n readonly label: string;\n private _ignored;\n /**\n * Stop colliding with these groups — symmetric, so naming it on one side is enough. Safe to call\n * after bodies exist: their filters are re-pushed.\n */\n ignore(...groups: PhysicsGroup2D[]): this;\n /** Members of this group don't collide with EACH OTHER — bullets, debris, a ragdoll's own bones. */\n ignoreSelf(): this;\n}\n","types/g2/loop.d.ts":"export declare const onUpdate: (callback: (dt: number) => void) => void;\nexport declare const offUpdate: (callback: (dt: number) => void) => void;\nexport declare const ensureAnimEvents: () => void;\nexport declare const ensurePhysicsEvents: () => void;\n","types/g2/Node2D.d.ts":"import { AspectHost } from \"../core/Aspect\";\nimport type { CompAxis, CompWriter } from \"../core/compWrite\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport type { Animation } from \"../animate/tween/Animation\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\n/** Animatable transform props of a 2D node; an array of values is a keyframe list. */\nexport type Node2DTweenProps = {\n x?: number | number[];\n y?: number | number[];\n position?: Vec2Like | Vec2Like[];\n /** Degrees. */\n rotation?: number | number[];\n scale?: number | Vec2Like | (number | Vec2Like)[];\n};\nexport { Vec2, type Vec2Like };\nexport type Node2DEvents = {\n /** A looping animation clip wrapped around (fires each loop). */\n loopReached: (clip: string) => void;\n /** A non-looping animation clip finished. */\n completed: (clip: string) => void;\n /** A physics contact / sensor overlap began (the other node, plus where and how hard). The\n * contact's `normal` points AWAY from the other node, so `normal.y > 0.7` reads as \"I landed on\n * top of it\". Sensor overlaps and `exit` carry zeros. */\n enter: (other: Node2D, contact: Contact2D) => void;\n exit: (other: Node2D, contact: Contact2D) => void;\n /** Pointer up over this node's Physics2D shape (a tap/click). */\n click: (ev: ClickEvent<Node2D | null>) => void;\n /** Pointer down on this node's Physics2D shape. Call ev.track(...) to capture the drag. */\n touchstart: (ev: TouchStartEvent<Node2D | null>) => void;\n};\n/** Where a contact happened, delivered as the second argument of 'enter'. `speed` is the approach\n * speed at impact (world units/s) — scale an impact sound with it. Zeros on sensor and 'exit'\n * events, which have no manifold. */\nexport type Contact2D = {\n point: Vec2;\n normal: Vec2;\n speed: number;\n};\nexport declare class Node2D extends AspectHost<Node2DEvents> implements CompWriter {\n /** Native entity id. */\n get id(): number;\n /** Optional debug/editor name (plain JS data — scene2d files stamp their node names here). */\n name?: string;\n protected _x: number;\n protected _y: number;\n protected _rotation: number;\n protected _sx: number;\n protected _sy: number;\n protected _layer: number;\n protected _z: number;\n protected _visible: boolean;\n private _pushXf;\n constructor(internalId?: number | Handle);\n private _pull;\n get x(): number;\n set x(v: number);\n get y(): number;\n set y(v: number);\n _writeComp(_prop: string, axis: CompAxis, v: number): void;\n get position(): Vec2;\n set position(v: Vec2Like);\n /** Rotation in degrees (CCW). */\n get rotation(): number;\n set rotation(deg: number);\n get scale(): Vec2;\n set scale(v: Vec2Like | number);\n /** Tween the transform — `node.animateTo({ x: 120, rotation: 90, duration: 400, easing: 'outBack' })`;\n * arrays are keyframes. Game clock unless `clock: 'ui'`. Returns the {@link Animation} handle. */\n animateTo(props: Node2DTweenProps & TweenMeta): Animation;\n /** Tween FROM the given values to the node's current transform. */\n animateFrom(props: Node2DTweenProps & TweenMeta): Animation;\n /** Draw layer (int). Higher layers render on top. */\n get layer(): number;\n set layer(v: number);\n /** Intra-layer depth for non-Y-sorted layers (higher z = on top). */\n get z(): number;\n set z(v: number);\n get visible(): boolean;\n set visible(v: boolean);\n get parent(): Node2D | null;\n set parent(p: Node2D | null);\n get children(): readonly Node2D[];\n /** Attach children to this node (each keeps its current world transform). Returns this. */\n add(...children: Node2D[]): this;\n /** Detach a direct child (reparents it to root, keeping its world transform). Returns this. */\n remove(child: Node2D): this;\n /**\n * Reparent this node. `keepWorld` (default true) recomputes the local transform so the on-screen\n * position/rotation/scale is unchanged; pass false to keep the local transform and move with the\n * new parent. Self/descendant parents are rejected natively (no cycles).\n */\n setParent(parent: Node2D | null, keepWorld?: boolean): this;\n /** World-space position (composes all ancestors). */\n get worldPosition(): Vec2;\n /** Convert a world-space point into this node's local space (and back). */\n worldToLocal(p: Vec2Like): Vec2;\n localToWorld(p: Vec2Like): Vec2;\n private _syncLocalFromNative;\n addEventListener<K extends keyof Node2DEvents>(channel: K, callback: Node2DEvents[K]): void;\n /** Destroy this node and its whole subtree (children go with it — the 3D / UI contract). Every\n * aspect in the subtree detaches first (physics bodies released, updaters unregistered). */\n destroy(): void;\n}\n","types/g2/OneWay2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { Node2D } from \"./Node2D\";\nexport declare class OneWay2D extends Aspect<\"oneWay\", Node2D> {\n static readonly aspect = \"oneWay\";\n private _normal;\n private _arc;\n private _enabled;\n /** Which side is solid. Default `[0, 1]` — solid from above, i.e. a floor you pass through from\n * below. `[1, 0]` is a wall you can only enter from the left. */\n get normal(): Vec2Like;\n set normal(v: Vec2Like);\n /** How far off `normal` an approach still counts as coming from the solid side, in degrees.\n * Default 90 — the whole half-plane, which is what a platform wants. */\n get arc(): number;\n set arc(v: number);\n /** Turn the one-way behaviour off, making the surface solid from both sides again. */\n get enabled(): boolean;\n set enabled(v: boolean);\n onAttach(): void;\n onDetach(): void;\n onReconfigure(): void;\n private _push;\n}\n","types/g2/Physics2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport { type Node2D } from \"./Node2D\";\nimport { PhysicsGroup2D } from \"./groups2d\";\nexport type MotionType = \"static\" | \"kinematic\" | \"dynamic\";\n/** A neutral solid surface. Deliberately the same default as 3D `Physics.friction`. */\nexport declare const DEFAULT_FRICTION = 0.6;\nexport interface PhysicsConfig {\n /** Gravity in world units/s² (Y-up: down is negative). Default [0, -980]. */\n gravity?: Vec2Like;\n /** Pixels per meter — tunes Box2D's internal tolerances; you still author in world units. Default 64.\n * Only applies before the world exists (it is a global solver tolerance). */\n pixelsPerMeter?: number;\n /** Solver sub-steps per fixed step. Default 4. */\n subSteps?: number;\n}\n/** Closest raycast hit. */\nexport interface RayHit {\n node: Node2D | null;\n point: Vec2;\n normal: Vec2;\n fraction: number;\n}\nexport declare class Physics2D extends Aspect<\"physics\", Node2D> {\n static readonly aspect = \"physics\";\n private _motion;\n /** Static (walls, floors), kinematic (script-driven platforms), or dynamic (fully simulated).\n * Default \"dynamic\", and LIVE: freeze a crate into `'static'`, hand a ragdoll to `'dynamic'`. */\n get motion(): MotionType;\n set motion(m: MotionType);\n /** Lock rotation (essential for platformer characters). */\n fixedRotation: boolean;\n /** Continuous collision for fast-moving bodies (projectiles). */\n bullet: boolean;\n private _mass;\n private _friction;\n private _bounce;\n private _gravityScale;\n private _linearDamping;\n private _angularDamping;\n private _group;\n private _repush;\n private _h;\n /** Which collision group this body belongs to (see Physics2D.addGroup). Live. */\n get group(): PhysicsGroup2D | undefined;\n set group(g: PhysicsGroup2D | undefined);\n /** Mass in world units. Omitted (or 0) = derived from the collider's AREA, so a big crate really is\n * heavier than a small one. Setting it scales the shape-derived mass data, keeping the rotational\n * inertia in the same ratio — a lopsided collider still tips the way its geometry says. */\n get mass(): number;\n set mass(v: number);\n /** Surface friction. 0 is frictionless, ~1 grippy; two bodies COMBINE as sqrt(a×b), so the lower\n * value wins the argument. Default 0.6 — a neutral solid, matching 3D. */\n get friction(): number;\n set friction(v: number);\n /** Bounciness, 0..1 — the fraction of the approach speed returned on impact. Two bodies combine as\n * MAX (the bouncier one wins — the opposite of friction), and below ~64 units/s no bounce is\n * applied at all, which is what stops a ball jittering on the floor forever. */\n get bounce(): number;\n set bounce(v: number);\n private _pushMaterial;\n /** Native physics body id. 0 until attached, or if the build has no physics support. Mirrors 3D `Physics.id`. */\n get id(): number;\n onAttach(): void;\n onDetach(): void;\n /** Re-applying options (`node.aspect(Physics2D, {…})`) pushes the live ones through. */\n onReconfigure(): void;\n /** Linear velocity in world units/second (fresh Vec2 on read). */\n get velocity(): Vec2;\n set velocity(v: Vec2Like);\n /** Angular velocity in degrees/second. */\n get angularVelocity(): number;\n set angularVelocity(degPerSec: number);\n /** Per-body gravity multiplier: 1 = full world gravity, 0 = floats, <0 = repelled. */\n get gravityScale(): number;\n set gravityScale(scale: number);\n get linearDamping(): number;\n set linearDamping(d: number);\n get angularDamping(): number;\n set angularDamping(d: number);\n /** Pause this body — it stops simulating and stops colliding until re-enabled. */\n set enabled(v: boolean);\n /** Box2D puts resting bodies to sleep; wake one to make it react to a change you made by hand. */\n set awake(v: boolean);\n /** Apply an instantaneous impulse at the centre of mass (never spins the body) and wake it. */\n applyImpulse(v: Vec2Like): this;\n /** Apply an impulse at a WORLD point — the lever arm becomes spin. Use this when the push has a real\n * point of contact: a bullet's hit point, a blast pushing a prop at its base. */\n applyImpulseAt(v: Vec2Like, worldPoint: Vec2Like): this;\n /** Apply a continuous force (world units) and wake the body. */\n applyForce(v: Vec2Like): this;\n /** Set the world's gravity / solver settings. OPTIONAL: the world is created on the first body with\n * gravity [0, -980], 64 px/m and 4 sub-steps. Calling this later changes gravity LIVE and leaves\n * bodies alone. */\n static configure(config?: PhysicsConfig): void;\n /** World gravity, live. */\n static get gravity(): Vec2;\n static set gravity(g: Vec2Like);\n private static _gravity;\n /** Whether this build has physics support (CREATOR_2D_PHYSICS). NOTE: this reports the BUILD, not\n * the world — there is nothing else to guard, since the world creates itself. */\n static get supported(): boolean;\n /** Render interpolation of body transforms between the fixed 60 Hz steps (global; default on). Turn\n * off to save per-frame transform writes when you have many moving bodies / don't need >60 Hz\n * smoothness — bodies then advance in discrete steps. */\n private static _interpolation;\n static get interpolation(): boolean;\n static set interpolation(on: boolean);\n /**\n * Register a collision group. Groups are SUBTRACTIVE and SYMMETRIC (see groups2d.ts):\n *\n * const player = Physics2D.addGroup()\n * const bullets = Physics2D.addGroup().ignoreSelf().ignore(player)\n */\n static addGroup(label?: string): PhysicsGroup2D;\n /** The implicit group of every body that never named one - name it to exclude \"everything else\". */\n static get defaultGroup(): PhysicsGroup2D;\n /** Closest body hit by the segment, or null. `node` resolves the hit entity. */\n static raycast(from: Vec2Like, to: Vec2Like, q?: Query2D): RayHit | null;\n /** Every body along the segment, NEAREST FIRST - a piercing bullet, a laser, \"how many walls are\n * between us\". Capped at 32 hits. */\n static raycastAll(from: Vec2Like, to: Vec2Like, q?: Query2D): RayHit[];\n /** Topmost body (solid or sensor) whose shape contains the world point, or null. \"Topmost\" means\n * by DRAW order - layer, then z - so picking agrees with what the player sees. */\n static overlapPoint(p: Vec2Like, q?: Query2D): Node2D | null;\n /** Everything within `radius` of a point - an explosion, an aura, an aggro range. */\n static overlapCircle(centre: Vec2Like, radius: number, q?: Query2D): Node2D[];\n /** Everything inside an axis-aligned box (centre + HALF-extents) - a room, a camera bound. */\n static overlapBox(centre: Vec2Like, half: Vec2Like, q?: Query2D): Node2D[];\n /**\n * Everything touching a capsule from-to of the given radius. A capsule is the shape a DIRECTED\n * question has: a beam with width, a sword arc, \"does my radius fit through this gap\" - none of\n * which an axis-aligned box can express.\n *\n * It is also the SWEPT test: a circle of radius r moving from A to B during a frame sweeps exactly\n * this capsule, so a fast projectile checked this way cannot tunnel through a thin wall the way two\n * separate position checks do.\n */\n static overlapCapsule(from: Vec2Like, to: Vec2Like, radius: number, q?: Query2D): Node2D[];\n}\n/** Which groups a query may hit, and what to skip. */\nexport type Query2D = {\n /** Only hit bodies in these groups. Omitted = everything. */\n groups?: PhysicsGroup2D[];\n /** Skip these nodes - the \"don't hit myself\" case a ray fired from inside its own body needs. */\n ignore?: Node2D | Node2D[];\n};\n","types/g2/scenarios2d.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { Node2D } from \"./Node2D\";\nimport type { Scene2D } from \"./Scene2D\";\n/**\n * Ease the scene camera toward this node every frame (attach it to the player). In a `.scene2d.ts`\n * file the loader wires `scene` automatically; from hand-written code pass it yourself:\n * `hero.aspect(CameraFollow, { scene })`.\n *\n * The eased position accumulates at full precision and only the value PUSHED to the camera is\n * snapped — reading the snapped camera back as the ease-from value would let tiny sub-pixel steps\n * round to zero near settle (the follow would stall a few px off-centre, then jump).\n */\nexport declare class CameraFollow extends Aspect<\"cameraFollow\", Node2D> {\n static readonly aspect = \"cameraFollow\";\n /** The scene2d loader injects the scene into aspects that declare this. */\n static readonly wantsScene = true;\n /** The scene whose camera follows (wired by the scene file loader). */\n scene: Scene2D | null;\n /** Exponential time constant in seconds; smaller = snappier, 0 = pin the node to centre. */\n smooth: number;\n /** Camera offset from the node, in world units. */\n offset: [number, number];\n /** Quantize the camera to whole screen pixels so eased motion never shimmers pixel art.\n * Defaults to the scene's `env.pixelPerfect` (true when unset). */\n pixelSnap: boolean;\n private _x;\n private _y;\n private readonly _grid;\n update(dt: number): void;\n}\n","types/g2/Scene2D.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Aspect, type AspectCtor, type FieldOf, type TargetOf } from \"../core/Aspect\";\nimport { Presentable, type DismissOptions, type PresentOptions } from \"../ui/presentable\";\nimport { type UIWidgetContent } from \"../ui/UILayer\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport { Camera2D } from \"./Camera2D\";\nimport { type Node2D } from \"./Node2D\";\nexport type Scene2DOptions = {\n /** Background color — '#10131a', 0x10131a, or [r,g,b]/[r,g,b,a] in 0..1. */\n background?: ColorInput;\n /** Texture sampling for the 2D renderer: `'nearest'` (default — crisp pixel art) or `'linear'`\n * (smooth — for hi-res / non-pixel-art assets). Applied when the scene is opened, so switching\n * scenes restores the active scene's choice. NOTE: this is a GLOBAL renderer setting (one sampler\n * for ALL textures, not per-texture), so the currently-open scene's filter wins. Omit to leave the\n * current setting (engine default is nearest). */\n filter?: 'nearest' | 'linear';\n};\n/** Returned by scene2d.layer(n); chain .ySort() to enable top-down depth sorting for that layer. */\ndeclare class LayerHandle {\n private readonly sceneId;\n private readonly layer;\n constructor(sceneId: number, layer: number);\n /** In this layer, lower-on-screen sprites overlap higher ones (top-down feet sorting). */\n ySort(enabled?: boolean): this;\n}\nexport declare class Scene2D implements Presentable {\n /** Native scene handle. */\n readonly id: number;\n readonly camera: Camera2D;\n private static _active;\n static get active(): Scene2D | null;\n readonly _touchStartListeners: Array<(ev: TouchStartEvent<Node2D | null>) => void>;\n /** Texture filter to (re)assert on open(); the sampler is global, so each scene reclaims it. */\n private readonly _filter?;\n constructor(options?: Scene2DOptions);\n set background(color: ColorInput);\n /** Address a draw layer to configure it, e.g. scene2d.layer(1).ySort(). */\n layer(n: number): LayerHandle;\n /** Topmost visible sprite whose world bounds contain the world point, or null. Body-free\n * hit-test for tap/click picking — pair with camera.screenToWorld(). */\n pick(worldPoint: Vec2Like): Node2D | null;\n /** Scene-level pointer events. The handler fires for every tap/press in the scene, with\n * `ev.target` = the hit Physics2D node (or null). On 'touchstart' you can ev.track(...) a drag. */\n addEventListener(channel: \"click\", callback: (ev: ClickEvent<Node2D | null>) => void): void;\n addEventListener(channel: \"touchstart\", callback: (ev: TouchStartEvent<Node2D | null>) => void): void;\n removeEventListener(channel: \"click\" | \"touchstart\", callback: (ev: any) => void): void;\n add(...nodes: Node2D[]): this;\n remove(...nodes: Node2D[]): this;\n /** Attach (and configure) a system, or reconfigure it if already present. Returns the scene typed\n * as now-having it (`scene.system(Hud).hud`). A 3D `System<'x'>` (target Scene) is rejected here. */\n system<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;\n /** Safe access — undefined if the system isn't attached. */\n get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;\n /** Existence check AND type guard: inside `if (scene.has(Hud))`, `scene.hud` is present. */\n has<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this is this & FieldOf<A>;\n /** Detach a system (runs its onDetach). Chainable. */\n removeSystem<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this;\n readonly cl: (() => void)[];\n _backButtonCallback?: () => void;\n private _vd?;\n /** Fires when the scene becomes the visible destination (incl. a pop revealing it). */\n onOpen(callback: () => void): this;\n /** Fires when the scene stops being visible (closed, replaced, or covered by a push). */\n onClose(callback: () => void): this;\n /** Hardware/system back while the scene is current. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n /** The UI over the scene — widgets (a HUD, a dialog), laid out over the scene while it is\n * presented; touches outside a widget's box reach the scene. */\n setContent(content: UIWidgetContent): this;\n /** Make this the active scene — shows it as the current destination (replaces a screen /\n * another scene; only the active scene renders). */\n open(options?: PresentOptions): this;\n close(options?: DismissOptions): this;\n destroy(): void;\n}\nexport {};\n","types/g2/Shape2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { Node2D } from \"./Node2D\";\nexport declare class Shape2D extends Aspect<\"shape\", Node2D> {\n static readonly aspect = \"shape\";\n /** Box half-extents [hw, hh] (world units). */\n box?: Vec2Like;\n /** Circle radius. */\n circle?: number;\n /** Capsule between two local points, with a radius. */\n capsule?: {\n from: Vec2Like;\n to: Vec2Like;\n radius: number;\n };\n /** Thin segment (an edge) between two local points. */\n segment?: {\n from: Vec2Like;\n to: Vec2Like;\n };\n /** Convex polygon, up to 8 local points (a convex hull is computed — a CONCAVE outline silently\n * becomes its hull; use `chain` for those). */\n polygon?: Vec2Like[];\n /**\n * A polyline of connected segments — the one shape that expresses a long CONCAVE surface (rolling\n * terrain, a cave wall) in one piece, seam-free. Pass only the points that should be solid; the\n * tangent points Box2D needs at the ends are synthesised here.\n *\n * STATIC bodies only (a polyline has no area, so no mass), at least 2 points (4 with `loop`), and it\n * must not self-intersect. It is ONE-SIDED: solid on the right of the point order — walk the points\n * so that the solid material is on your right, or set `flip`.\n */\n chain?: Vec2Like[];\n /** `chain`: close the contour (an island / a room boundary). Needs at least 4 points. */\n loop?: boolean;\n /** `chain`: put the solid side on the other side of the line. */\n flip?: boolean;\n /** The collider's centre relative to the node, in world units. Applies to EVERY kind — it\n * translates a capsule's / segment's / polygon's / chain's points too, unlike the old `offset`. */\n origin?: Vec2Like;\n private _handle;\n onDetach(): void;\n /**\n * Re-configuring the aspect swaps the fixture in place — same body, same id, same velocity, same\n * position. Nothing happens when the geometry is unchanged, so re-applying the same options in a\n * loop is free.\n */\n onReconfigure(): void;\n private _create;\n /**\n * Box2D's chain wants the two TANGENT points as extra entries and does not collide on its first or\n * last edge — pass it your outline verbatim and you lose both end segments (four points give ONE).\n * So the caller passes only the solid points and the ends are extrapolated here: `p0 + (p0 - p1)`.\n * A loop needs none of that (every point is interior) but does need 4 of them.\n */\n private _createChain;\n private _signature;\n}\n","types/g2/Sprite.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport { Canvas } from \"../canvas/Canvas\";\nimport { Node2D, type Node2DTweenProps } from \"./Node2D\";\nimport type { Texture2D } from \"./Texture2D\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport type { Animation } from \"../animate/tween/Animation\";\n/** Animatable sprite props on top of the 2D transform. */\nexport type SpriteTweenProps = Node2DTweenProps & {\n opacity?: number | number[];\n color?: ColorInput | ColorInput[];\n};\n/** Anything that can back a sprite: a texture, or a Canvas (baked to a texture on assign). */\nexport type TextureSource = Texture2D | Canvas;\nexport type SpriteOptions = {\n texture?: TextureSource;\n /** Pivot, [0,0] = top-left .. [1,1] = bottom-right. Use [0.5, 1] (feet) for Y-sorted depth. */\n anchor?: Vec2Like;\n /** World size; defaults to the texture's pixel dimensions. */\n size?: Vec2Like;\n /** Normalized UV sub-rect [u0,v0,u1,v1]. */\n frame?: [number, number, number, number];\n /** Tint multiplied with the texture. */\n color?: ColorInput;\n opacity?: number;\n layer?: number;\n position?: Vec2Like;\n};\nexport declare class Sprite extends Node2D {\n private _texture?;\n private _anchor;\n private _color;\n private _opacity;\n private _flipX;\n private _flipY;\n private _size;\n constructor(options?: SpriteOptions);\n get texture(): Texture2D | undefined;\n set texture(t: TextureSource | undefined);\n /** Current world size: explicit override if set, else the texture's pixel dimensions (a Canvas-backed\n * sprite defaults to the canvas's LOGICAL size, so pixelRatio is crispness only, not size). */\n get size(): Vec2;\n set size(v: Vec2Like);\n get anchor(): Vec2;\n set anchor(v: Vec2Like);\n /** Set the UV sub-rect (normalized). */\n set frame(uv: [number, number, number, number]);\n /** Set the sub-rect in texture pixels. */\n setFramePx(px: number, py: number, pw: number, ph: number): this;\n /** Tween `opacity` / `color` and the transform — see {@link Node2D.animateTo}. */\n animateTo(props: SpriteTweenProps & TweenMeta): Animation;\n animateFrom(props: SpriteTweenProps & TweenMeta): Animation;\n get color(): ColorInput;\n set color(c: ColorInput);\n get opacity(): number;\n set opacity(a: number);\n get flipX(): boolean;\n set flipX(v: boolean);\n get flipY(): boolean;\n set flipY(v: boolean);\n}\n","types/g2/SpriteAnimation.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { Sprite } from \"./Sprite\";\n/** Per-clip frame list, or an object for per-clip fps/loop/direction overrides. */\nexport type Clip = number[] | {\n frames: number[];\n fps?: number;\n loop?: boolean;\n perDirection?: boolean;\n};\nexport declare class SpriteAnimation extends Aspect<\"anim\", Sprite> {\n static readonly aspect = \"anim\";\n /** Grid cell size in texture pixels (defaults to the full texture). */\n size?: [number, number];\n /** Grid columns override — for sheets with padding; defaults to floor(texWidth / cellWidth). */\n cols?: number;\n /** Pixel origin of the grid in the texture — cells index from here (a SpriteSheet region). */\n origin?: [number, number];\n /** Default fps for clips that don't override it. */\n fps: number;\n /** Default loop for clips that don't override it. */\n loop: boolean;\n /** Named clips; frame indices are row-major into the grid. Set via the attach opts. */\n clips: Record<string, Clip>;\n /** Facing names in texture-row order (row i = directions[i]) for `perDirection` clips. */\n directions?: string[];\n private _clipIds;\n private _clipNames;\n private _current;\n private _defined;\n private _queued;\n private _dir;\n onAttach(): void;\n /** (Re)build native clips from `this.clips`. Called on attach; call again after changing clips. */\n define(): this;\n private _define;\n /**\n * Play a clip by name. Re-playing the active clip is a no-op (keeps it running smoothly).\n * For a `perDirection` clip, `dir` picks the facing — a direction name or a movement vector\n * (nearest compass row wins); omitted, the last direction (or the first row) is kept.\n */\n play(name: string, dir?: string | Vec2Like): this;\n stop(): this;\n /** Current facing (last direction resolved by play()), or null before the first directional play. */\n get direction(): string | null;\n set speed(value: number);\n get current(): string | null;\n get frame(): number;\n private _resolveDir;\n}\n","types/g2/SpriteSheet.d.ts":"import { type Vec2Like } from \"../math/vec\";\nimport { Sprite } from \"./Sprite\";\nimport { SpriteAnimation, type Clip } from \"./SpriteAnimation\";\nimport { Texture2D } from \"./Texture2D\";\n/**\n * A named region of the image. Just a rect is a static sprite; `slice` subdivides the rect into an\n * animation grid ([cols, rows] — the cell is rect size / counts); `clips` names frame runs over\n * that grid (local, row-major). A sliced entry with NO clips loops all of its cells in order.\n */\nexport type SheetSprite = {\n /** Pixel rect [x, y, w, h] in the image. */\n rect?: [number, number, number, number];\n /** Subdivide the rect into an animation grid: [cols, rows]. */\n slice?: [number, number];\n /** Playback fps for this sprite's animation (defaults to the sheet fps, then 12). */\n fps?: number;\n /** Named clips over the local grid (see SpriteAnimation). Omit to loop every cell. */\n clips?: Record<string, Clip>;\n /** Facing names in local-row order for `perDirection` clips (compass tokens: S/SE/E/…). */\n directions?: string[];\n /** Overrides the sheet anchor. */\n anchor?: Vec2Like;\n};\nexport type SpriteSheetDef = {\n /** The image URL — write `asset('./sheet.png')`. */\n image: string;\n /** Default pivot for every sprite made from this sheet ([0.5, 1] = feet, for Y-sorted worlds). */\n anchor?: Vec2Like;\n /** Default fps for sliced sprites / clips that don't override it. */\n fps?: number;\n /** The named sprites. */\n sprites?: Record<string, SheetSprite>;\n};\nexport type SpriteMakeOptions = {\n position?: Vec2Like;\n layer?: number;\n /** Overrides the sheet/sprite anchor. */\n anchor?: Vec2Like;\n /** Start this clip immediately (sliced sprites with clips). */\n clip?: string;\n /** Initial facing for `perDirection` clips. */\n direction?: string;\n};\nexport declare class SpriteSheet {\n private _def;\n private _tex;\n private _loading;\n constructor(def: SpriteSheetDef);\n /** The sheet definition (read-only by convention — the editor owns the file). */\n get def(): SpriteSheetDef;\n /** The loaded texture, or null before load() resolves. */\n get texture(): Texture2D | null;\n /** Load the sheet's texture (idempotent). make() starts this automatically. */\n load(): Promise<Texture2D>;\n /** Names of the sheet's sprites. */\n get spriteNames(): string[];\n /** Build a named sprite; starting a clip hands back the animation handle. */\n make(name: string, opts: SpriteMakeOptions & {\n clip: string;\n }): Sprite & {\n anim: SpriteAnimation;\n };\n make(name: string, opts?: SpriteMakeOptions): Sprite;\n /** The pixel rect [x, y, w, h] of a named sprite's REGION (the whole rect, sliced or not). */\n rectOf(name: string): [number, number, number, number] | null;\n private _applyTexture;\n}\n/** Declare a sprite sheet (the default export of a `.sprite.ts` file). */\nexport declare const defineSpriteSheet: (def: SpriteSheetDef) => SpriteSheet;\n","types/g2/Texture2D.d.ts":"import { type FetchResponse, type File } from \"../runtime/fetch\";\nexport declare class Texture2D {\n /** Native texture handle. */\n readonly id: number;\n readonly width: number;\n readonly height: number;\n constructor(id: number, width: number, height: number);\n static fromCanvas(canvas: {\n _bakeSurface(): number;\n width: number;\n height: number;\n pixelRatio: number;\n }): Texture2D;\n static load(source: string | FetchResponse | File): Promise<Texture2D>;\n destroy(): void;\n}\n","types/g2/Tilemap.d.ts":"import { Node2D } from \"./Node2D\";\nimport type { Texture2D } from \"./Texture2D\";\nexport type TilemapOptions = {\n texture: Texture2D;\n /** Map grid size (in tiles). */\n cols: number;\n rows: number;\n /** On-screen cell size in world units — a single number (square) or [w, h]. */\n tile: number | [number, number];\n /** Atlas grid: how the texture is sliced into tiles, [atlasCols, atlasRows]. */\n atlas: [number, number];\n /** Row-major tile indices into the atlas (-1 = empty), length cols*rows. Row 0 is the top row. */\n data: number[] | Int32Array;\n};\nexport declare class Tilemap extends Node2D {\n readonly cols: number;\n readonly rows: number;\n constructor(options: TilemapOptions);\n setTile(x: number, y: number, index: number): this;\n}\n","types/g2/Tileset.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { Node2D } from \"./Node2D\";\nimport { type TilesetDef, type TileMaterial } from \"./autotile\";\nexport declare class Tileset {\n private _def;\n constructor(def: TilesetDef);\n /** The tileset definition (read-only by convention — the editor owns the file). */\n get def(): TilesetDef;\n /** Names of the declared materials, in file order. */\n get materialNames(): string[];\n /** A material by name. */\n material(name: string): TileMaterial | undefined;\n /** The cell value maps store for a named material (what you paint / pass in `data`). */\n id(name: string): number | undefined;\n /** Derive display atlas indices from a material-id grid (what Autotile2D does at load). */\n derive(cols: number, rows: number, data: ArrayLike<number>, seed?: number): Int32Array;\n}\n/** Declare a tileset (the default export of a `.tiles.ts` file). */\nexport declare const defineTileset: (def: TilesetDef) => Tileset;\n/**\n * Marks a tilemap node's `cells` as MATERIAL ids of a tileset instead of raw atlas indices:\n * `aspects: [use(Autotile2D, { tileset: world })]`. The scene2d loader derives the display\n * indices (neighbor-mask autotile + seeded scatter, deterministic) before building the tilemap;\n * the aspect itself holds no behavior. Change `seed` to reshuffle scatter variants.\n */\nexport declare class Autotile2D extends Aspect<\"autotile\", Node2D> {\n static readonly aspect = \"autotile\";\n /** The imported `.tiles.ts` handle. */\n tileset: Tileset | null;\n /** Scatter seed — same seed, same map, same result on every platform. */\n seed: number;\n}\n","types/g2/touch.d.ts":"/** Register the host pointer callback once, on the first click/touchstart listener (node or scene). */\nexport declare const ensurePointerEvents: () => void;\n","types/g2/Trigger2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { PhysicsGroup2D } from \"./groups2d\";\nimport type { Node2D } from \"./Node2D\";\nexport declare class Trigger2D extends Aspect<\"trigger\", Node2D> {\n static readonly aspect = \"trigger\";\n private _h;\n private _enabled;\n private _group;\n private _repush;\n /** Which collision group this zone belongs to. Live. */\n get group(): PhysicsGroup2D | undefined;\n set group(g: PhysicsGroup2D | undefined);\n /** Native physics body id (0 if no physics support). Mirrors 3D `Trigger.id`. */\n get id(): number;\n onAttach(): void;\n onDetach(): void;\n /** Switch the zone off and on — a spent pickup, a hitbox that is only live during a swing. */\n get enabled(): boolean;\n set enabled(v: boolean);\n}\n","types/gl/animation/AnimationClip.d.ts":"import { type FetchResponse } from \"../../runtime/fetch\";\nimport type { Vec3Like } from \"../../math/vec\";\nimport type { QuatLike } from \"../../math/quat\";\n/** A keyframe: `[time (s), value]`. */\nexport type ClipKey<V> = [number, V];\nexport type ClipInterpolation = \"linear\" | \"step\";\n/** Curves for one target node (bone name), any subset of the three channels. */\nexport type ClipTrackDef = {\n position?: ClipKey<Vec3Like | [number, number, number]>[];\n rotation?: ClipKey<QuatLike | [number, number, number, number]>[];\n scale?: ClipKey<Vec3Like | [number, number, number]>[];\n interpolation?: ClipInterpolation;\n};\nexport type ClipDef = {\n /** Clip length in seconds — defaults to the last key time across all tracks. */\n duration?: number;\n /** Target node name → its curves. Names bind to bones (or any child node) at Animator attach. */\n tracks: Record<string, ClipTrackDef>;\n};\nexport type ClipInfo = {\n name: string;\n duration: number;\n trackCount: number;\n};\n/** What `AnimationClip.from(clip, …)` derives from a clip. */\nexport type DeriveOptions = {\n /** The clip MIRRORED — left ↔ right, the motion on the other side of the body (a stop that brakes on the\n * left foot brakes on the right). Derived on the rig of the clip's own file (joints pair by name, the\n * sagittal plane comes from the rest pose), so the result is the same on every model: its contacts,\n * phase, root motion and heading are the mirrored ones, its name is `<name>_M`. Only clips from a GLB\n * carry a rig; a curve-built clip cannot be mirrored. */\n mirror?: boolean;\n /** Start of the window, seconds of the source (default 0). */\n from?: number;\n /** End of the window, seconds of the source (default the clip's end). */\n to?: number;\n};\nexport declare class AnimationClip {\n /** Source name (the clip's name inside its file; `\"clip\"` for procedural clips). Informational —\n * an Animator addresses clips by the key YOU give it. */\n readonly name: string;\n /** Length in seconds. */\n readonly duration: number;\n /** Number of animated (node, channel) tracks. */\n readonly trackCount: number;\n private constructor();\n /** Mark a moment of the clip (SECONDS from its start) with an event name: `kick.addEvent(0.4, 'hit')`\n * → `anim.on('hit', (clip, layer) => …)` fires when the playhead crosses it, loops included.\n * Events are part of the clip: every model playing it gets them; `AnimationClip.from(clip, { from, to })`\n * keeps the ones inside the window, re-timed. Chainable. */\n addEvent(time: number, name: string): this;\n private _pushEvents;\n /** ANCHOR SPANS for a bone — what an anchored IK chain ending in `bone` rides while this clip plays\n * (`IK.TwoBone` with `anchor`; the sockets come from `anim.sockets(...)`). `donor` names the socket\n * set of the gun the take was AUTHORED on ('' = the live set: no delta); `spans` = `[from, to,\n * socket, rotation?, pin?]` in SECONDS — the socket the hand is on through that window (`''` = free:\n * it rides the joint itself), `rotation` 0..1 how much of the socket's turn it takes (default 1),\n * `pin` 0..1 how much it sits ON the socket instead of keeping its own relation to it (default 0: a\n * magazine is REACHED, and the take's motion is what carries the hand there).\n * Gaps between spans = the chain's own socket, pinned by the chain's `anchorPin` — that is where a\n * hand holding the gun is nailed to the grip, so the layers below cannot slide it. A clip WITHOUT\n * anchors takes no part: the hand keeps the take's own relation to the gun. Part of the clip, like\n * events; `AnimationClip.from` carries them re-timed. Chainable.\n * reload.anchors('hand_l', { donor: 'tr15', spans: [[0.9, 1.4, 'mag'], [1.4, 2.0, ''], [2.0, 2.4, 'mag'], [2.4, 2.7, 'bolt']] }) */\n anchors(bone: string, def: {\n donor?: string;\n spans?: readonly (readonly [number, number, string, number?, number?])[];\n }): this;\n /** Drop a bone's anchor spans. */\n clearAnchors(bone: string): this;\n private _pushAnchors;\n /** Load ONE clip from a GLB: the file's only/first clip, or the one named / at the given index. */\n static load(source: string | FetchResponse, clip?: string | number): Promise<AnimationClip>;\n /** Load EVERY clip of a GLB (library files), keyed by clip name. */\n static loadAll(source: string | FetchResponse): Promise<Record<string, AnimationClip>>;\n /** Build a clip from curves in code — no DCC needed. Keys are `[time, value]`; a track binds to the\n * node of that name when the clip is used by an Animator (bones, or any child node). */\n static fromCurves(def: ClipDef): AnimationClip;\n /** A NEW clip derived from `clip`: its mirror (`{ mirror: true }` — the other side of the body), a window\n * of it (`{ from, to }` seconds of the source, re-timed to 0; array-slice semantics), or both. Cut a\n * too-long take down to the action, carve several sub-clips out of one packed timeline, get the\n * left-footed stop from the right-footed one:\n *\n * clips: { Kick: AnimationClip.from(kick, { from: 0.2, to: 1.1 }), StopM: AnimationClip.from(stop, { mirror: true }) }\n *\n * A window drops the keys outside it and interpolates exact boundary values in, so the clip starts and\n * ends precisely on the source's pose at the cut points. Everything downstream (blend spaces, events'\n * times, root motion, foot contacts, phase sync) sees a normal clip. */\n static from(clip: AnimationClip, options: DeriveOptions): AnimationClip;\n private static _label;\n private static _loadSet;\n}\n","types/gl/animation/Animator.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport { type QuatLike } from \"../../math/quat\";\nimport type { Node } from \"../Node\";\nimport type { AnimationClip } from \"./AnimationClip\";\nimport { type ActiveClip, type ClipInfo, type ClipEventHandler, type LayerOptions, type LoopDef, type LoopOptions, type PlayOptions, type StopOptions } from \"./core\";\nimport { Feet } from \"./Feet\";\nimport { Warp } from \"./Warp\";\nimport type { Loop } from \"./Loop\";\nimport type { Layer } from \"./Layer\";\nimport type { Playback } from \"./Playback\";\n/** Level of detail for a GLB instance (docs/lod-plan.md): `'auto'` = the engine's pick by screen size and\n * visibility, or a fixed level 0 (full) … 3 (coarsest mesh, animation every 4th frame without fingers). */\nexport type LodMode = \"auto\" | 0 | 1 | 2 | 3;\nexport declare class Animator extends Aspect<\"anim\", Node> {\n static readonly aspect = \"anim\";\n private _c;\n private _rootMotion;\n private _rootRotation;\n /** The feet: the contact bones, the foot lock, ground IK, footstep events. See `Feet`. */\n feet: Feet;\n /** The warp: stride and orientation fitted to the body's real motion, the step warp dials. See `Warp`. */\n warp: Warp;\n onAttach(): void;\n onDetach(): void;\n /** The clip list, in order: the GLB's embedded clips, then the clips you added (an added clip with an\n * embedded clip's name takes its place). */\n get clips(): readonly AnimationClip[];\n /** One clip by name or index — the resource: its name, duration, tracks, events. `undefined` if none. */\n clip(ref: string | number): AnimationClip | undefined;\n /** Add a clip under a name (default: its own) — from another file, procedural, or sliced. Chainable. */\n addClip(name: string | AnimationClip, clip?: AnimationClip): this;\n /** What the engine measured about a clip on THIS skeleton (unlike `clip()`, which is the file's data):\n * speed, travel, turn, the foot contacts, the gait phase, its cycle, and comparisons with other clips.\n * Binds the clip on first ask. `undefined` if there is no such clip. */\n clipInfo(clip: string | number): ClipInfo | undefined;\n /** Play a one-shot: by name, index, or the first clip. It takes the layer over from whatever it showed,\n * transitioned over `fade`. `await` the Playback: it resolves at the hand-over (`true`, or `false` if cut\n * short), and what you start right then is what the clip hands over to (nothing = back to the loop). */\n play(clip?: string | number, options?: PlayOptions): Playback;\n /** Set the LOOP — what shows when no one-shot plays: a clip, or a blend space (`{ Idle: 0, Run: 6 }`, drive\n * the returned object's `value`). Takes the layer over, a one-shot included. `stop()` removes it. */\n playLoop(def: LoopDef, options?: LoopOptions): Loop | undefined;\n /** Fade everything out, on every layer → the rest pose. */\n stop(options?: StopOptions): this;\n /** The current loop (the object the last `playLoop()` returned), if any. */\n get loop(): Loop | undefined;\n /** A one-shot hasn't handed over yet. */\n get busy(): boolean;\n /** What every layer shows this frame, with weights: a one-shot, or a loop's members with their shares. */\n get active(): ActiveClip[];\n /** Where the base layer is in the GAIT CYCLE: 0 at a left-foot-down, 0.5 at a right-foot-down; -1 when\n * what plays has no cycle. What `play(clip, { phase: 'match' })` matches against. */\n get phase(): number;\n /** A clip's playhead, seconds (-1 = not bound). */\n time(clip: string | number): number;\n /** Scrub a clip's playhead, seconds — inspectors and debug boards (pair with `speed = 0`). Nothing is\n * faded or re-picked. */\n seek(clip: string | number, time: number): void;\n /** Re-aim a playing turn clip's warp (`play({ turn })`) to `deg` for the rest of the clip; `undefined` = off. */\n setTurn(clip: string | number, deg: number | undefined): void;\n /** Global playback rate: 0.3 = slow-mo, 0 = pause. */\n get speed(): number;\n set speed(v: number);\n /** Clip events (`clip.addEvent(0.4, 'hit')` → `anim.on('hit', …)`). */\n on(event: string, cb: ClipEventHandler): this;\n off(event: string, cb: ClipEventHandler): this;\n /** A new layer on top (masked override / additive); the returned object is its handle. */\n addLayer(options?: LayerOptions): Layer;\n /** The root bone's horizontal travel comes OFF the pose and moves the node — or its CharacterController\n * (on this node or an ancestor) as a velocity, so it collides. For clips whose hips actually travel. A\n * character under a `Locomotion` gets this from its displacement mode instead. */\n get rootMotion(): boolean;\n set rootMotion(on: boolean);\n /** With `rootMotion`: the root bone's TURN is root motion too — it comes off the pose and turns the node,\n * so a turn clip leaves the character facing where it took it. Off by default (a walk's hip sway is a\n * turn too); on for a rig whose root carries the heading (`lecodes assets retarget --root-rotation yaw`). */\n get rootRotation(): boolean;\n set rootRotation(on: boolean);\n /** The body's WORLD velocity this frame (m/s): what `anim.warp`'s stride and orientation fit the clips\n * to. A `Locomotion` feeds it itself; when you drive the gait by hand set it every frame (the\n * CharacterController's velocity, or your own). Reads back the last value fed. */\n get motion(): readonly [number, number, number];\n set motion(v: {\n x: number;\n y: number;\n z: number;\n } | readonly [number, number, number]);\n private _motion;\n /** SOCKETS: named frames on a bone of this rig — a weapon's grip / magazine / bolt empties, placed in\n * the scene editor. A NODE socket is read by the engine every frame (a socket on a moving part\n * follows it); a `{ position, quaternion }` one is fixed in the bone's space. The default set is the\n * LIVE one (the weapon in the hands); `set: 'tr15'` names a DONOR set — the same sockets on the gun a\n * take was authored on, which a clip's `anchors()` refer to. Chainable.\n * arms.anim.sockets('ik_hand_gun', { grip_r: w.gripR, grip_l: w.gripL, mag: w.mag })\n * arms.anim.sockets('ik_hand_gun', { grip_l: { position: [0.03, -0.12, -0.05] } }, { set: 'tr15' }) */\n sockets(joint: Node | string, table: Record<string, Node | {\n position?: Vec3Like;\n quaternion?: QuatLike;\n }>, options?: {\n set?: string;\n }): this;\n /** Drop a socket (the live set, or `set`). */\n removeSocket(name: string, set?: string): this;\n /** `'auto'` (default): a character small on screen or out of view is evaluated every 2nd / 4th frame\n * without its finger, toe and twist joints; `'full'`: every frame, every joint (a hero seen through a\n * scope). Independent of `Model.lod`, the mesh level. */\n get lod(): \"auto\" | \"full\";\n set lod(v: \"auto\" | \"full\");\n /** The native animator's id — 0 until something is played or bound. */\n get _id(): number;\n /** Bind a clip to the base layer without playing it; its native slot (-1 = no such clip). */\n _slot(clip: string | number): number;\n}\n","types/gl/animation/core.d.ts":"import { AnimationClip } from \"./AnimationClip\";\nimport { Loop } from \"./Loop\";\nimport { Layer } from \"./Layer\";\nimport { Playback } from \"./Playback\";\nimport { Vec3 } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\n/** A position on a blend axis (1D) or plane (2D). */\nexport type BlendPosition = number | readonly [number, number];\nexport type PlayOptions = {\n /** Transition seconds — how long the difference to the pose the layer SHOWED (its loop, a one-shot,\n * or rest) takes to decay. Default `0` = cut: a fade is always asked for, never implied. Also the\n * transition back to the loop at the end unless `fadeOut` overrides it. */\n fade?: number;\n /** Transition seconds for the way in only (overrides `fade`). */\n fadeIn?: number;\n /** One-shots: the transition BACK to the loop after the end (overrides `fade`; `0` = cut at the end).\n * The clip plays to its last frame; the loop then takes over and the difference between the two poses\n * (and their velocities) decays over this time, so no part of the clip is cut — to play less of it,\n * give it an `end`. On a layer with no loop the clip HOLDS its last frame (a rock that broke stays\n * broken) — `anim.stop({ fade })` is the way back to rest. */\n fadeOut?: number;\n /** Playback rate for this clip (default 1). */\n speed?: number;\n /** Rewind even if the clip is already playing (default: rewind only if it isn't). */\n restart?: boolean;\n /** Play a WINDOW of the clip, seconds of the clip: enter at `start` (default 0; only when the play\n * rewinds — see `restart`) and treat `end` (default the clip's end) as the end — the hand-over fires\n * there, the last frame held there, events beyond it never fire. Only the swing of a longer take, the\n * wind-up without the recovery. A window that lives in the clip table belongs in\n * `AnimationClip.from(clip, { from, to })` instead. Not combined with `phase`. Hosts without the\n * window play the whole clip. */\n start?: number;\n end?: number;\n /** Enter the clip at a point in the GAIT CYCLE instead of at its start: `'match'` = the phase the\n * layer shows right now (the walk's left foot is down → the turn clip starts where its left foot\n * is down too, so nothing slides), or a number 0–1. Clips without a gait cycle ignore it. */\n phase?: number | \"match\";\n /** TURN WARP (degrees, + = left): the node turns this much in total over the clip instead of what the\n * clip's baked heading says — its turn curve scaled, so the difference grows where the clip turns and\n * pivots about the planted foot. A 45° start played with `turn: 60` turns 60; played with `turn: 45`\n * it lands on 45 exactly whatever the clip's own run-off. Needs `rootMotion` + `rootRotation` and a\n * clip with a baked heading (`lecodes assets marks` / `retarget`); a clip that turns under 10° is\n * left alone. Ignored by hosts without it. */\n turn?: number;\n};\nexport type StopOptions = {\n fade?: number;\n};\nexport type LoopOptions = {\n /** Transition seconds from whatever the layer shows — its previous loop, a one-shot still playing,\n * or rest. Default `0` = cut: a loop wanting a transition asks for one (`{ fade: 0.2 }`). */\n fade?: number;\n /** Playback rate of the loop's clips (default 1). */\n speed?: number;\n /** Where in the CYCLE to start, 0–1, or `'match'` = where the layer is now (what a gait loop taking\n * over from a start / turn clip wants). The members share one clock, so this is every member's phase. */\n phase?: number | \"match\";\n};\n/** A blend member with its CYCLE given explicitly: `at` = its position, `offset` = its gait phase at t = 0\n * (0 = a left-foot-down, 0.5 = a right-foot-down, 0–1), `cycles` = how many gait cycles the clip holds\n * (a two-stride loop: 2). Both are measured offline from the clip's foot marks. Members given as a\n * bare position run in normalized time and have no cycle (nothing phase-matches to them). */\nexport type BlendMember = {\n at: BlendPosition;\n offset?: number;\n cycles?: number;\n};\n/** What a layer loops: one clip (name / index), or a blend space `{ name: position | { at, offset, cycles } }`. */\nexport type LoopDef = string | number | Record<string, BlendPosition | BlendMember>;\n/** One clip the layer shows this frame — `layer.active` / `anim.active` (a debug overlay's list). */\nexport type ActiveClip = {\n name: string;\n clip: AnimationClip;\n /** contribution to the pose, 0–1: the shown one-shot 1, a loop member its blend share */\n weight: number;\n /** clock (s) */\n time: number;\n /** a member of the layer's loop (else the layer's one-shot) */\n loop: boolean;\n};\nexport type LayerOptions = {\n /** Bone name(s): the layer drives only these subtrees (`'Spine1'` = upper body). Default: the whole rig. */\n mask?: string | string[];\n /** Blend each clip's DELTA from its own first frame on top of the layers below (lean, breathe, recoil)\n * instead of overriding them. */\n additive?: boolean;\n /** Layer contribution 0–1 (default 1). */\n weight?: number;\n};\nexport type ClipEventHandler = (clip: string, layer: Layer) => void;\n/** A foot planted: which one, and where in the world it landed. */\nexport type StepHandler = (side: \"left\" | \"right\", position: Vec3) => void;\n/** A loop's GAIT CYCLE as two numbers — what a blend member's `{ offset, cycles }` wants: φ(t) = offset +\n * cycles · t / duration, 0 = a left-foot-down. `residual` = the worst foot-down's distance from that line\n * (cycles; a clean loop sits under 0.03), `steps` = the foot-downs it was fitted through. */\nexport type ClipCycle = {\n offset: number;\n cycles: number;\n residual: number;\n steps: number;\n};\n/** A loop's cycle found by POSE against a reference loop (`clipInfo(clip).alignTo(ref)`): the `{ offset,\n * cycles }` under which it shows the reference's pose at the reference's phase. `score` = the fit at that\n * alignment (metres, the joint distance + velocity measure), `margin` = how much worse the runner-up\n * alignment ≥ 0.2 cycle away is — near 0 means ambiguous (a mirror pair, an in-place idle). */\nexport type ClipAlign = {\n offset: number;\n cycles: number;\n score: number;\n margin: number;\n};\n/** What the engine measured on a clip once it was bound to this skeleton (`anim.clipInfo('Walk')`).\n * The root curves are of the clip's ROOT bone — its travel is what root motion would move. */\nexport type ClipInfo = {\n /** total horizontal root travel, metres */\n travel: number;\n /** mean root speed over the clip, m/s */\n speed: number;\n /** total root yaw, radians (+ = left) */\n turn: number;\n /** the root barely moves — an in-place clip */\n inPlace: boolean;\n /** The gait cycle fitted through the foot contacts (a foot already down at t = 0 is not a step) —\n * the numbers a blend member takes as `{ offset, cycles }`. Undefined: no steps. */\n cycle(): ClipCycle | undefined;\n /** This loop's cycle found by POSE against `reference` (its cycle given, else `reference`'s `cycle()`,\n * else offset 0 / one cycle — the answer is then relative to the reference's own time). Reads no marks:\n * a markless loop (swimming, breathing, an upper-body sway) gets a cycle, and a marked one gets a\n * second opinion — a mirrored anchor shows as a 0.5 disagreement with `cycle()`. Undefined: nothing to compare. */\n alignTo(reference: string | number, cycle?: {\n offset: number;\n cycles: number;\n }): ClipAlign | undefined;\n /** the clip has a gait cycle (feet planting in turn) — `phaseAt` is meaningful */\n hasPhase: boolean;\n /** When each foot TOUCHES the ground, seconds — the phase anchor. `still` is the window inside it\n * where the foot is genuinely STATIONARY (a touching foot still rolls for its first beats, and a\n * stop take's final plant touches long before the body has braked); absent = never still.\n * `at` = where the foot is at the touch's start ([x, y, z], model space). */\n contacts: {\n side: \"left\" | \"right\";\n from: number;\n to: number;\n at: [number, number, number];\n still?: {\n from: number;\n to: number;\n };\n }[];\n /** the HANDS on the ground (a cartwheel, a roll, a vault) — from the clip's marks in the GLB; empty when none */\n hands: {\n side: \"left\" | \"right\";\n from: number;\n to: number;\n at: [number, number, number];\n still?: {\n from: number;\n to: number;\n };\n }[];\n /** A CLIMBING clip's tread levels (a stair or slope take): the model-space heights its feet plant\n * at, sorted ascending, with the riser (median level spacing — the step height the clip was\n * authored for). Absent on a flat clip. */\n treads?: {\n riser: number;\n levels: number[];\n };\n /** the gait phase at `time`: 0 at a left-foot-down, 0.5 at a right-foot-down; -1 without a cycle */\n phaseAt(time: number): number;\n /** cumulative root travel (m) at `time` */\n travelAt(time: number): number;\n /** cumulative root yaw (rad, + = left) at `time` */\n turnAt(time: number): number;\n /** the root's own speed at `time`, m/s — how fast the clip is moving the body right there */\n speedAt(time: number): number;\n /** the PELVIS' yaw relative to the clip's heading at `time` (rad, + = left, wrapped to ±π): the stance twist\n * the heading leaves out — an idle stands ~43° off the course it starts along, a stop's tail turns into that\n * stance while the heading holds. A controller that switches clips mid-pose can keep the PELVIS continuous\n * (turn the node by the difference between the two clips' values) where keeping the course would swing\n * the body. Without a baked heading: the pelvis' yaw at frame 0 throughout. */\n pelvisYawAt(time: number): number;\n /** the unit travel direction at `time` ([x, z], model space, held through stills) — integrate\n * direction × d(travel) to reconstruct the root's 2D path (a treadmill display, a turn's arc) */\n directionAt(time: number): [number, number];\n /** the first time the clip has turned `yaw` radians (+ = left): where to enter a turn a body has\n * already begun, so the clip continues the move instead of restarting it */\n timeAtTurn(yaw: number): number;\n /** How far this clip's pose is from `target`'s, in metres — the joint distance plus the velocity\n * difference over a tenth of a second, the planted foot weighted most. That difference is exactly\n * what a hand-over hands the transition to decay away, so it says what switching to `target` would\n * cost at `time`. The two are lined up by cycle PHASE (a clip that continues the walk) or by TIME\n * (`align: 'time'` — two clips that both begin from standing share no cycle). */\n fitTo(target: string | number, time: number, options?: {\n align?: \"phase\" | \"time\";\n }): number | undefined;\n /** The earliest moment (seconds) at which handing over to `target` costs no more than `within`\n * metres — a start's last steps ARE the walk, so this is where it stops being worth playing.\n * `atContact` (default true) snaps to the next foot-down: a switch under a planted foot is the one\n * the eye forgives. -1 = the clip never gets that close. */\n exitTo(target: string | number, options?: {\n within?: number;\n atContact?: boolean;\n align?: \"phase\" | \"time\";\n }): number;\n /** The knee's bend plane at `time`, predicted from the skeleton's calibrated hinge axis carried by\n * this clip's own thigh rotation — continuous even where the leg is straight (where a plane\n * derived from positions is pure noise). `pole` = unit direction from the hip→ankle line toward\n * the knee (a two-bone solver's bend direction), `normal` = the plane's normal; both in the model\n * pose's frame. Undefined = no leg chain, or no knee motion bound to calibrate from. */\n kneePoleAt(side: \"left\" | \"right\", time: number): {\n pole: [number, number, number];\n normal: [number, number, number];\n } | undefined;\n /** The clip's baked physics at `time` (unit body mass, model space): `com` = the body's center of\n * mass (biomechanical segment fractions on the classified bones), `velocity` = its velocity\n * (= linear momentum per kg), `angular` = the angular momentum about the COM (m²/s per kg,\n * low-passed ~0.5 s — the REGULATED component, e.g. a turn's sustained yaw; the per-stride\n * pitch/roll exchange between the limbs and the trunk is filtered out),\n * `support` = per-foot load [left, right] — contact-gated, split by where the COM stands between\n * the feet, scaled by the vertical force proxy (above 1 on a landing impact, 0 in flight).\n * A model, not a measurement — meant for ranking transitions and display, both sides of any\n * comparison sharing the same model. Undefined = nothing classified on this skeleton. */\n physicsAt(time: number): {\n com: [number, number, number];\n velocity: [number, number, number];\n angular: [number, number, number];\n support: [number, number];\n } | undefined;\n /** The clip's MATCHING FEATURE ROW at `time` — a fresh Float32Array(37) in the clip's heading\n * frame at that time (x lateral, + left; y up; z forward): 0–5 feet positions relative to the\n * pelvis' ground point, 6–11 feet velocities, 12–14 pelvis velocity, 15 pelvis height, 16–18\n * COM velocity, 19–20 support L/R, 21–22 contact phase L/R, 23 yaw angular momentum, 24–31 the\n * clip's own path 0.3/0.6/1.0/1.5 s ahead as (lateral, forward) pairs, 32–35 facing change at\n * those horizons (rad, + = left), 36 cyclic flag. What a trajectory-and-state matcher compares.\n * Undefined = no leg chain. */\n featuresAt(time: number): Float32Array | undefined;\n /** The take is a LOOP by measurement: its seam is continuous (feet back where they started\n * relative to the root, no turn). Starts, stops and turns are not. */\n cyclic: boolean;\n};\n/** The calibrated knee hinge-axis report (`anim.feet.kneeAxis('left')`): the axis in the thigh's local\n * frame, and the calibration's own confidence — the angular spread of its measurements (radians;\n * a real knee comes in at a few degrees) over `samples` consecutive-frame deltas of the pack.\n * `plant` = the calibrated PLANT HEIGHTS (model space): where the ankle / toe actually sit under\n * full weight, the median of the pack's still-window lows — absent when nothing plants. */\nexport type KneeAxisReport = {\n axis: [number, number, number];\n spreadMean: number;\n spreadMax: number;\n samples: number;\n plant?: {\n ankleY: number;\n toeY: number;\n };\n};\n/** A clip bound to a layer — one per (clip, layer), reused by every play. `playback` = the most recent\n * one-shot on it (`playing` while it still owns the layer; kept after that so its handle can still be\n * read — a restart re-enters the same slot with a new record). */\nexport type SlotRec = {\n name: string;\n clip: AnimationClip;\n slot: number;\n layer: LayerRec;\n inBlend: boolean;\n playback?: PlaybackRec;\n};\nexport type PlaybackRec = {\n slot: SlotRec;\n playing: boolean;\n done: Promise<boolean>;\n resolve: (natural: boolean) => void;\n};\nexport type LayerRec = {\n index: number;\n view: Layer;\n slots: SlotRec[];\n loop?: LoopRec;\n weight: number;\n mask: string;\n additive: boolean;\n};\nexport type LoopRec = {\n layer: LayerRec;\n members: {\n name: string;\n slot: SlotRec;\n }[];\n value: BlendPosition;\n view: Loop;\n dead: boolean;\n};\nexport declare class Core {\n id: number;\n /** Added clips by name (`addClip`) — the lookup index; an added name overrides an embedded one. */\n readonly table: Map<string, AnimationClip>;\n readonly layers: LayerRec[];\n speed: number;\n private _embedded?;\n private readonly _added;\n private _list?;\n private readonly _listeners;\n readonly node: Node;\n constructor(node: Node);\n embedded(): AnimationClip[];\n /** The ordered clip list: the GLB's clips in file order (an added clip of the same name takes the\n * embedded one's place), then the remaining added clips in insertion order. Cached until addClip. */\n clips(): AnimationClip[];\n addClip(name: string, clip: AnimationClip): void;\n /** A clip by name (added first, then embedded), or by index into `clips()` (none = the first). */\n resolveClip(ref: string | number | undefined): [string, AnimationClip] | undefined;\n private clipNames;\n /** Create the native animator on demand. False = nothing to animate (warned). */\n ensure(): boolean;\n /** The native animator for the RIG alone — an IK chain or a socket on a model that has no clips\n * still needs the joint tree described to the engine. False = no transform hierarchy (warned). */\n ensureRig(): boolean;\n destroy(): void;\n newLayer(options?: LayerOptions): LayerRec;\n addLayer(options: LayerOptions): Layer;\n /** Arm the layer's next transition with a wind-up: see `Layer.anticipate`. */\n anticipate(L: LayerRec, amount: number): void;\n pushLayer(L: LayerRec): void;\n /** The layer's slot for the clip — bound on first use, reused after that. */\n slotFor(L: LayerRec, name: string, clip: AnimationClip): SlotRec | undefined;\n /** The base layer's native slot for a clip, bound on first ask (-1 = no such clip / no animator). */\n slotIndex(ref: string | number): number;\n play(L: LayerRec, ref: string | number | undefined, o: PlayOptions): Playback;\n /** A one-shot on the layer hasn't handed over yet. */\n busy(L: LayerRec): boolean;\n settle(p: PlaybackRec, natural: boolean): void;\n /** Resolve every pending playback on the layer as cut short. */\n private settleLayer;\n stopSlot(s: SlotRec, fade: number): void;\n stopLayer(L: LayerRec, fade: number): void;\n stopAll(fade: number): void;\n loop(L: LayerRec, def: LoopDef, o: LoopOptions): Loop | undefined;\n /** The phase the layer shows, 0–1 through the gait cycle (-1 = nothing / no cycle). */\n layerPhase(L: LayerRec): number;\n /** The entry phase of a play / playLoop: a number as given, `'match'` = what the layer shows now\n * (undefined when it shows no cycle — then the clip starts at its own beginning). */\n private entryPhase;\n /** The loop's phase through its cycle, 0–1 (the members share one clock). */\n loopPhase(b: LoopRec): number;\n setLoopPhase(b: LoopRec, phase: number): void;\n setLoopValue(b: LoopRec, v: BlendPosition): void;\n /** What the layer shows this frame: its source — the one-shot, or the loop's members with their\n * blend shares — in binding order (stable rows). */\n active(L: LayerRec): ActiveClip[];\n slotWeight(s: SlotRec): number;\n /** The slot's gait phase now, wrapped into 0–1 (-1 without a cycle). */\n slotPhase(s: SlotRec): number;\n /** A baked curve of the slot at its current time: 1 travel (m) / 2 yaw (rad) / 3 speed (m/s). */\n slotCurveAt(s: SlotRec, which: 1 | 2 | 3): number;\n /** The clip's total root yaw, radians (+ = left). */\n slotTurn(s: SlotRec): number;\n slotTime(s: SlotRec): number;\n seek(s: SlotRec, time: number): void;\n /** Scrub: set a bound clip's playhead directly, seconds — an inspector's tool. */\n seekTime(ref: string | number, time: number): void;\n /** Re-aim a playing clip's TURN WARP (see `PlayOptions.turn`): the clip's baked heading is scaled so that the\n * whole clip turns `deg` — set mid-play, the scale applies to what is still to come, so a controller that\n * wants a different heading while a turn plays asks for (the clip's total × what it still needs / what\n * the clip still turns). Undefined `deg` switches the warp off. */\n setTurnOf(ref: string | number, deg: number | undefined): void;\n /** A bound clip's current playhead, seconds (-1 = not bound). */\n timeOf(ref: string | number): number;\n /** What the engine measured on the clip once it was bound to this skeleton — binds it if needed. */\n clipInfo(ref: string | number): ClipInfo | undefined;\n /** The skeleton's calibrated knee hinge axis for a side, with its confidence report — measured once\n * over every bound clip's knee rotation track. Undefined = no leg chain / no knee motion bound. */\n kneeAxis(side: \"left\" | \"right\"): KneeAxisReport | undefined;\n /** STEP WARP v2 (the warp rewrite's knobs): `stride` scales each foot's travel-direction offset\n * from its hip — the step shortens or lengthens, uniformly through stance and swing; `lift` is\n * METRES added to each foot's height, gated to the swing by the contact marks (0 = neutral,\n * negative = a shuffle — no probing), and half of what it adds raises the pelvis so the body\n * steps higher with the foot; `pitch` (degrees, + = toes up) rotates each foot about its\n * own lateral axis — a slope's foot rotation; `slope` (degrees, + = ascending) is the INVISIBLE\n * STAIRCASE: foot heights follow the incline (leading foot higher) and the feet auto-pitch by\n * the same angle — pair it with raising the character by tan(slope) × the stride-scaled clip\n * travel (`clipInfo(clip).travelAt`), which holds every planted foot's world height constant on\n * its own tread. Solved in the calibrated knee hinge plane with a SOFT reach (a leg at its limit\n * keeps a residual knee bend instead of popping against the clamp), and whenever a leg would\n * overreach — a descent, a long stride — the pelvis lowers by exactly the excess (weighted by\n * the contact marks, spring-followed; zero when nothing overreaches, so an ascent or a shorter\n * stride is untouched). Omit / null = stage off. */\n setStepWarp(options?: {\n stride?: number;\n lift?: number;\n pitch?: number;\n slope?: number;\n } | null): void;\n /** A slot for a clip on the base layer, bound on demand — what the pair-wise measures address. */\n private slotOf;\n /** The baked distance curve between two clips, cached per pair (the engine caches the bake itself;\n * this keeps the samples on the JS side so a controller can read them per frame without copying). */\n private readonly _fit;\n private fitCurve;\n /** The earliest moment handing `src` over to `target` costs no more than `within` metres. */\n private fitExit;\n /** The contact bones, '\n '-joined per side (\"\" = classify by name). */\n private _feet?;\n setFeet(left: string, right: string): void;\n /** Stride / orientation warping, as the engine's fixed-order parameter array. */\n private _warp?;\n setWarp(params: Float32Array): void;\n /** The body's world velocity this frame (m/s) — the game side of the stride / orientation fit. Nothing\n * to feed before the animator exists; hosts without the warp stage have no method. */\n setMotion(vx: number, vy: number, vz: number): void;\n /** The feet stage (lock / ground IK), as the engine's fixed-order parameter array. */\n private _feetParams?;\n setFeetParams(params: Float32Array): void;\n /** One foot's lock state after this frame's evaluation into `out` (8 floats); false = no such foot\n * or no feet stage on this host. */\n footState(side: 0 | 1, out: Float32Array): boolean;\n private static _warnedIk;\n private hasIk;\n /** A chain ending in `endEntity` (kind 0 two-bone: the bone, its parent, its grandparent; 1 look-at). 0 = none. */\n ikCreate(kind: 0 | 1, endEntity: number): number;\n ikDestroy(ik: number): void;\n ikSet(ik: number, params: Float32Array): void;\n ikNodes(ik: number, target: number, pole: number, rotation: number): void;\n ikAnchor(ik: number, socket: string): void;\n ikState(ik: number, out: Float32Array): boolean;\n /** Sockets by \"set/name\", replayed when the animator is (re)created. */\n private readonly _sockets;\n /** Define a socket on joint `joint` (a bone's entity): a NODE socket (read by the engine every frame) or a\n * fixed TRS in the joint's space. set \"\" = the live set, any other name = a donor's. */\n setSocket(set: string, name: string, joint: number, node: number, trs: Float32Array | null): void;\n removeSocket(set: string, name: string): void;\n private pushSocket;\n private readonly _steps;\n onStepHandler(cb: StepHandler): void;\n offStepHandler(cb: StepHandler): void;\n private onStep;\n setSpeed(v: number): void;\n setRootMotion(on: boolean, rotation?: boolean): void;\n on(event: string, cb: ClipEventHandler): void;\n off(event: string, cb: ClipEventHandler): void;\n /** Native slot event: 0 completed / 1 loop / 2 settled (no longer a source) / 3 hand-over / 4+i clip event i. */\n private onEvent;\n}\n","types/gl/animation/DynamicBone.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { Node } from \"../Node\";\n/** One value for the chain, or `[root, tip]` interpolated down it by depth. */\nexport type DynamicBoneCurve = number | readonly [root: number, tip: number];\n/** `'none'`, `'probe'` (a ray from the chain root down against the physics world, every frame), a\n * height (a horizontal plane at that world y) or a world point (a plane through it, `floorNormal` up). */\nexport type DynamicBoneFloor = \"none\" | \"probe\" | number | Vec3Like;\n/** `'auto'` = every DynamicBoneCollider under the model; `'humanoid'` = those plus capsules generated\n * on the standard humanoid bones (hips, spine, head, limbs — the Ragdoll's layout); `'none'`; or the\n * nodes carrying the colliders to use. */\nexport type DynamicBoneColliders = \"auto\" | \"humanoid\" | \"none\" | Node[];\n/** The cloth's SIDE of every collider marked `oneSided`: `'none'` = no side, every collider pushes a bone to\n * its nearest surface (tails, ropes); `'auto'` = away from the root bone's own axis (a cloak's strips round\n * a spine face out from it); a vector = a fixed direction in the root bone's frame (a cape hanging BEHIND\n * the arms: the body's backward). A one-sided collider that is moving AWAY from that side — an arm swinging\n * forward under the cape — puts a bone it has run into over to the side instead of carrying it: the arm\n * passes through the cloth and the cape hangs behind it again, instead of being dragged round the body.\n * Still, or moving toward the cloth, it pushes like any other collider, so cloth draped on an arm at rest\n * stays where it is. Two-sided colliders (the body's) never read the side. */\nexport type DynamicBoneSide = \"none\" | \"auto\" | Vec3Like;\n/** A capsule (or a sphere) riding a bone — what dynamic bones stay out of. Attach to a body bone:\n * `hips.aspect(DynamicBoneCollider, { radius: 0.12, to: 'Spine' })`. The capsule runs from\n * `offset` (the bone's origin by default) to the `to` bone's origin, or to `end` (both in the bone's\n * local space); neither = a sphere at `offset`. Picked up by every DynamicBone on the same model\n * with `colliders: 'auto'` / `'humanoid'`, or listed explicitly. */\nexport declare class DynamicBoneCollider extends Aspect<\"dynamicBoneCollider\", Node> {\n static readonly aspect = \"dynamicBoneCollider\";\n /** Radius in metres, in the world: the bone's scale does not touch it (`offset` / `end` are in the bone's own units). */\n radius: number;\n /** Start of the capsule in the bone's local space (default: the bone's origin). */\n offset: Vec3Like;\n /** End of the capsule in the bone's local space (a sphere when neither `end` nor `to` is set). */\n end?: Vec3Like;\n /** The bone the capsule reaches (its origin), instead of `end`. */\n to?: string;\n /** ONE-SIDED: the cloth belongs on the chain's `side` of this capsule (see DynamicBone.side). While the capsule\n * moves away from that side it puts a bone it has run into over to the side instead of carrying it — an arm\n * under a cape may push the cape back, never drag it forward round the body. Needs a `side` on the DynamicBone. */\n oneSided: boolean;\n static fields: FieldMeta<DynamicBoneCollider>;\n private _id;\n private _segment;\n onAttach(): void;\n onReconfigure(): void;\n onDetach(): void;\n}\nexport declare class DynamicBone extends Aspect<\"dynamicBone\", Node> {\n static readonly aspect = \"dynamicBone\";\n /** Only these bones (by name) join the chain — the root always does, a bone left out takes its\n * subtree with it. Default: the root's whole subtree. */\n bones?: string[];\n /** Depth limit under the root (0 = no limit). */\n depth: number;\n /** Particle radius for the collisions, metres. */\n radius: DynamicBoneCurve;\n /** 0..1 — how fast a bone returns to the animated shape (per 1/60 s). 0 = a rope, 1 = rigid. */\n stiffness: DynamicBoneCurve;\n /** 0..1 — velocity lost per 1/60 s. 0.02 swings like a rope, 0.1 settles like a tail, 0.3 is honey. */\n damping: DynamicBoneCurve;\n /** m/s² downward. A hanging rest pose feels none of it (the bone length cancels it); a pose that\n * sticks out droops by as much as `stiffness` lets it. */\n gravity: DynamicBoneCurve;\n /** Max deviation from the animated direction, degrees per bone (0 = free). */\n angleLimit: DynamicBoneCurve;\n /** Relative mass per bone. A bone-length constraint moves its two ends in inverse proportion to\n * their masses (the root is kinematic): `[3, 1]` makes a tail's base carry its tip, `1` shares\n * evenly like a rope. */\n mass: DynamicBoneCurve;\n /** Bones (by name) that ride the animation exactly while their subtrees still simulate: a sheet's\n * several roots under one anchor (a cloak's seven strips under the spine), so ONE chain owns them all\n * and `link` ties neighbouring strips — neighbours in THIS order, so list the strips round the ring\n * (front-left … back … front-right); the front stays open. */\n pinned?: string[];\n /** Metres a PINNED bone may be pushed off its animated place by a collider — a soft pin. Its particle\n * collides and takes the edge pushes like a free bone (the strip below hangs from where it IS) and is\n * drawn back to the animation when the collider leaves; the bone's local translation follows. A hard\n * pin (0) at a capsule's edge made the first free bone below it jitter: the edge push on a segment\n * with an immovable end is a lever, and a touch near the root threw the child out. 2–3 cm for a\n * cloak's roots under a shoulder capsule. */\n pinGive: number;\n /** 0..1 of the character's travel the chain takes rigidly (0 = the full whip on a dash, 1 = it\n * moves with the body and only the pose's own motion swings it). */\n follow: number;\n /** World wind, m/s². */\n wind: Vec3Like;\n /** The BODY'S TURN, ≥ 0. Above 0 the chain lives in the parent bone's ROTATING frame: `damping` acts\n * against the body's rigid motion (its travel plus its spin), so a heavily damped cloak RIDES a turn —\n * sweeps round with the back — instead of standing in the world while the character spins under it and\n * being dragged round after. The turn's inertia comes back as the frame's forces, scaled by this value:\n * a centrifugal push `ω² · r` along each bone's animated direction from the axis (the hem, farthest\n * from the spine, flies out and, on the chain's length, up). The frame's own physics is built in: the\n * whip back when the turn starts and forward when it stops, Coriolis. 1 = the physical push; more = a\n * bigger fling. With low damping the frame reproduces a free particle (nothing is counted twice);\n * an animation's spine sway is ~1 % of a 900°/s turn. A rotation over 90° in one frame (a respawn\n * facing) counts as a snap, not a spin. 0 = the plain translational frame, no turn forces. */\n spin: number;\n /** With `spin`: the cloth's INERTIA against the body's turn, seconds — the cloth's own rotation follows the\n * body's with this time constant. It falls behind when a turn starts (by about ω·τ: 45° at 900°/s and 0.05),\n * rides once caught up, and keeps turning past the back when the body stops (the same angle, eased out over\n * τ). Smooth by construction. 0 = glued to the turn; large = the cloth stays in the world while the body spins. */\n spinInertia: number;\n /** 0..1 strength of the ties between neighbouring columns at the same depth (a cloak). */\n link: number;\n /** 0..1 blend from the animation (0) to the simulation (1). At 0 nothing is simulated and the\n * chain re-arms on the animated pose when it comes back. */\n weight: number;\n /** Substep rate, Hz (≤ 4 substeps per frame). */\n rate: number;\n /** A root jump longer than this in one frame (metres) resets the chain instead of whipping it. */\n teleport: number;\n /** What the particles stay above: `'none'`, `'probe'`, a height, or a world point. */\n floor: DynamicBoneFloor;\n /** The floor plane's normal when `floor` is a point. */\n floorNormal: Vec3Like;\n /** Friction against the floor, a Coulomb coefficient: a resting bone's slide loses up to\n * `floorFriction · gravity · dt` of speed per substep (0 = ice, 1 = a rubber sole). While a bone\n * rests on the floor or a collider, `stiffness` and `angleLimit` let go of it: the surface's\n * reaction outranks the spring, or a hem folded on the floor would run away along it. */\n floorFriction: number;\n /** Constraint passes per substep (1..8, default 4). Each pass shares every bone length between its\n * ends, so a pull needs passes to travel down a long chain: a long rope may want 8, a short tail is\n * fine with 2. */\n iterations: number;\n /** What the chain collides with (see DynamicBoneColliders). */\n colliders: DynamicBoneColliders;\n /** The cloth's outside — makes the colliders one-sided (see DynamicBoneSide). */\n side: DynamicBoneSide;\n /** How firmly `guide()` targets are HELD through the constraint passes, 0..1. At 0 a guide is applied once\n * before the passes and the length / link passes may drag the bone back toward its un-guided neighbours\n * within the same frame; at 0.5 it is re-pulled after every pass with half its weight (converges with the\n * passes), at 1 with its full weight (a target the bone length cannot reach then jitters). */\n guideHold: number;\n /** The chain's EDGES collide with the capsules too — every bone segment and every link, not only the bones'\n * particles: a capsule thinner than a bone's length (a forearm) no longer passes through the cloth between\n * two bones. Off = particles only. */\n edges: boolean;\n static fields: FieldMeta<DynamicBone>;\n private _id;\n private _chain;\n private _depths;\n private _blob;\n private _sent;\n private _floorKey;\n private _colliderKey;\n private _collidersDirty;\n private _collidersRef;\n private _own;\n private _colliderSet;\n /** The bones of the chain, the root first. */\n get chain(): readonly Node[];\n onAttach(): void;\n onReconfigure(): void;\n /** Every field is live: what changed since the last frame is pushed here, before the engine's stage. */\n update(): void;\n onDetach(): void;\n /** Snap the chain onto the animated pose next frame (a teleport, a camera cut). */\n reset(): void;\n /** GUIDES: world points the bones' particles are drawn to each substep before the constraints —\n * weight 1 = there before them, the rest of the chain hangs, collides and links as before (a cape's\n * strips riding the arms). Replaces the previous set; an empty list clears. A late-phase script\n * (after the animator, before the engine's chain stage) refreshes it every frame. */\n guide(rows: readonly {\n bone: Node;\n at: Vec3Like;\n weight: number;\n }[]): void;\n /** The particles' world positions (the bones, then the leaves' virtual tips) — for a debug draw. */\n get particles(): Vec3[];\n private _collect;\n private _fill;\n /** Neighbour links: the bones at the same depth tied pairwise, the columns in the order of `pinned` (a cloak's\n * strips listed round the ring) — columns not listed there follow in tree order. Tree order alone is the\n * engine's child order, which for a GLB is the file's node order REVERSED (Filament prepends each child), so\n * strips added to a rig later were tied across the body instead of to their neighbours: the ermine's cloak\n * had one true neighbour pair out of eight, the rest were rods through the chest. */\n private _links;\n private _sync;\n private _pushFloor;\n private _pushColliders;\n /** Capsules on the standard humanoid bones, sized like the Ragdoll's parts. */\n private _makeHumanoid;\n}\n","types/gl/animation/Feet.d.ts":"import { Vec3 } from \"../../math/vec\";\nimport type { KneeAxisReport, StepHandler } from \"./core\";\n/** The feet settings (`anim.feet.set()` / the properties of `anim.feet`). Distances are metres, times\n * seconds. Every key is optional and only the keys given change. */\nexport type FeetOptions = {\n /** The contact bones per side — `'LeftFoot'`, or with a toe / ball `['LeftFoot', 'LeftToeBase']`.\n * Default: classified from the bone names (Mixamo / Unity / Blender / UE). Setting them re-bakes\n * every clip's contacts and phase. */\n left?: string | string[];\n right?: string | string[];\n /** FOOT LOCK: a foot the shown clip calls planted is pinned where it landed — heel to ball, rolling\n * as the clip rolls — and the leg re-solved to keep it there while the body moves on. Off by default. */\n lock?: boolean;\n /** GROUND IK: each foot is put on the ground the engine probes under it (stairs, a slope, a kerb),\n * aligned to its normal, the pelvis lowered so the leg can reach. Needs a physics world to probe;\n * without one the ground is the node's own plane. Off by default. */\n ik?: boolean;\n /** How far the pelvis may drop for the ground (default 0.35). */\n pelvis?: number;\n /** A locked foot never absorbs more residual than this — beyond it the anchor follows the animation\n * instead of fighting it (default 0.10). */\n unlockDistance?: number;\n /** The lock's ease in / out, seconds (default 0.08 / 0.12). */\n lockIn?: number;\n lockOut?: number;\n /** 0..1: how much the foot tilts onto the ground normal (default 1). */\n align?: number;\n /** The probe ray's reach above and below the ankle (default 0.6). */\n probe?: number;\n /** The lock plants only once the animated ankle moves slower than this, m/s (default 0.2). Raise it\n * to pin a foot a transition is still dragging. */\n plantSpeed?: number;\n};\n/** One foot after this frame's evaluation (`anim.feet.state(side)`): whether the lock holds it, the\n * lock's weight (eased 0…1), where it was pinned and where the leg was asked to put the ankle — all world. */\nexport type FootState = {\n locked: boolean;\n weight: number;\n anchor: Vec3;\n target: Vec3;\n};\nexport declare class Feet {\n private readonly _c;\n private readonly _o;\n /** Change several settings at once; only the keys given change. Chainable. */\n set(options: FeetOptions): this;\n /** The current settings (what was set; unset keys are the engine's defaults). */\n get options(): Readonly<FeetOptions>;\n get lock(): boolean;\n set lock(v: boolean);\n get ik(): boolean;\n set ik(v: boolean);\n get pelvis(): number;\n set pelvis(v: number);\n get unlockDistance(): number;\n set unlockDistance(v: number);\n get lockIn(): number;\n set lockIn(v: number);\n get lockOut(): number;\n set lockOut(v: number);\n get align(): number;\n set align(v: number);\n get probe(): number;\n set probe(v: number);\n get plantSpeed(): number;\n set plantSpeed(v: number);\n /** The contact bones (`undefined` = classified from the names). */\n get left(): string | string[] | undefined;\n set left(v: string | string[] | undefined);\n get right(): string | string[] | undefined;\n set right(v: string | string[] | undefined);\n /** One foot's state after this frame's evaluation — where the lock holds it and with what weight\n * (a debug beam under the foot). `undefined` on a host without the feet stage, or before anything played. */\n state(side: \"left\" | \"right\"): FootState | undefined;\n /** The skeleton's calibrated KNEE HINGE AXIS for a side (thigh-local, unit) with its confidence report —\n * measured once over every bound clip's knee rotation track. `undefined` = no leg chain, or no knee\n * motion bound to calibrate from. */\n kneeAxis(side: \"left\" | \"right\"): KneeAxisReport | undefined;\n /** A foot planted (world position) — audio, dust, decals. Fires for what the BASE layer shows, from\n * the clip's own contacts; a clip with no contacts fires nothing. */\n onStep(cb: StepHandler): this;\n offStep(cb: StepHandler): this;\n private pushBones;\n private push;\n}\n","types/gl/animation/IK.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport { Quat } from \"../../math/quat\";\nimport type { Node } from \"../Node\";\nimport type { Core } from \"./core\";\ntype Target = Node | Vec3Like;\n/** What both chains share: the native handle, the parameter push, the readback. */\ndeclare abstract class Chain<Name extends string> extends Aspect<Name, Node> {\n protected _rig?: Core;\n protected _ik: number;\n protected _weight: number;\n protected _enabled: boolean;\n protected abstract readonly kind: 0 | 1;\n /** 0–1 contribution (blend in/out, e.g. foot planting only while grounded). */\n get weight(): number;\n set weight(v: number);\n /** Solve every frame (default). */\n get enabled(): boolean;\n set enabled(v: boolean);\n /** After the last solve: how far the end bone still is from its target, metres (0 = reached). */\n get error(): number;\n onAttach(): void;\n onDetach(): void;\n onReconfigure(): void;\n protected params(): Float32Array;\n /** Push the description to the engine (a no-op until attached). */\n protected abstract push(): void;\n}\n/** Two-bone analytic IK (limbs). Attach to the END bone: `foot.aspect(IK.TwoBone, { target })` solves\n * upper (grandparent) + mid (parent) so the end reaches `target`; `pole` steers the bend (knee /\n * elbow) — a Node or world point; `anchor` makes it ride a socket of the rig instead (see the file\n * header). */\ndeclare class TwoBone extends Chain<\"ik\"> {\n static readonly aspect = \"ik\";\n protected readonly kind: 0;\n private _target?;\n private _pole?;\n private _rotation?;\n private _rotationWeight;\n private _anchor;\n private _anchorTime;\n private _anchorPin;\n /** Where the end bone should be (a Node — read by the engine every frame — or a world position). */\n get target(): Target | undefined;\n set target(v: Target | undefined);\n /** Bend hint — the mid joint is pulled toward it (a Node or a world point). */\n get pole(): Target | undefined;\n set pole(v: Target | undefined);\n /** World rotation the END bone takes after the solve — a Node (its world rotation) or a Quat. Unset =\n * the end bone keeps its animated rotation (a hand on a grip, a foot on a slope want it set). Blended\n * by `weight · rotationWeight`. An anchored chain takes its rotation from the socket instead. */\n get rotation(): Node | Quat | undefined;\n set rotation(v: Node | Quat | undefined);\n /** 0–1 contribution of `rotation` (on top of `weight`); for an anchored chain, of the socket's turn. */\n get rotationWeight(): number;\n set rotationWeight(v: number);\n /** ANCHORED: the name of the LIVE socket the end bone rides (`anim.sockets(...)`) — its target and\n * rotation come from the socket and the playing clips' anchor spans; `target` / `pole` / `rotation`\n * are ignored. '' = a plain chain. */\n get anchor(): string;\n set anchor(v: string);\n /** Anchored: how fast the hand moves between sockets — the halflife (s) of the spring the applied\n * delta follows the wanted one with (default 0.05). */\n get anchorTime(): number;\n set anchorTime(v: number);\n /** Anchored: 0..1 how hard the end bone is PINNED on its socket while the playing clips leave it there\n * (a GAP in their spans — the hand is holding the gun). 1 = it sits exactly on the socket, so nothing\n * in the pose below can slide it along the gun; 0 (default) = it keeps the take's own relation to the\n * socket, moved by the delta. A clip's SPANS carry their own pin and default to 0, because a hand on\n * its way to a magazine must keep the take's motion — so this knob is about holding, not reaching. */\n get anchorPin(): number;\n set anchorPin(v: number);\n /** After the last solve: the anchor delta applied — how far (m) and how much (rad) the live socket\n * moved the hand off the take's own pose. 0 for a plain chain. */\n get anchorDelta(): {\n distance: number;\n angle: number;\n };\n protected push(): void;\n}\n/** Aim a bone at a target (head / eyes / turret). Attach to the bone itself:\n * `head.aspect(IK.LookAt, { target: camera, limit: 70 })`. `axis` is the bone's LOCAL forward\n * (the direction that should point at the target) — rigs differ; default −Z, Mixamo heads look\n * along +Z of the head bone in most exports, so pass `axis: [0, 0, 1]` there if it faces backwards. */\ndeclare class LookAt extends Chain<\"lookAt\"> {\n static readonly aspect = \"lookAt\";\n protected readonly kind: 1;\n private _target?;\n private _axis;\n private _limit;\n /** What to look at (a Node — read by the engine every frame — or a world position). */\n get target(): Target | undefined;\n set target(v: Target | undefined);\n /** The bone's local axis that should point at the target. */\n get axis(): Vec3Like;\n set axis(v: Vec3Like);\n /** Max deflection from the animated direction, in degrees (default 80). */\n get limit(): number;\n set limit(v: number);\n protected push(): void;\n}\n/** Inverse kinematics aspects — attach to bones (see file header). */\nexport declare const IK: {\n TwoBone: typeof TwoBone;\n LookAt: typeof LookAt;\n};\nexport type IKTwoBone = TwoBone;\nexport type IKLookAt = LookAt;\nexport {};\n","types/gl/animation/Layer.d.ts":"import type { ActiveClip, LoopDef, LoopOptions, PlayOptions, StopOptions } from \"./core\";\nimport type { Loop } from \"./Loop\";\nimport type { Playback } from \"./Playback\";\nexport declare class Layer {\n private readonly _r;\n private readonly _c;\n /** Play a one-shot on this layer (transitioned over `fade`); resolves at its hand-over. */\n play(clip?: string | number, options?: PlayOptions): Playback;\n /** Set / transition this layer's loop (a clip, or a blend space) — over `fade` from whatever the\n * layer shows, a one-shot included (it is cut short). */\n playLoop(def: LoopDef, options?: LoopOptions): Loop | undefined;\n /** Fade everything on this layer out — one-shots and its loop. */\n stop(options?: StopOptions): this;\n /** ANTICIPATION for the NEXT play / playLoop on this layer (consumed by it): the transition begins with\n * every joint moving AGAINST the new clip's motion - `amount` x its velocity - and the transition's\n * spring brings it round: a wind-up before the swing. Position and rotation, the joints the layer\n * drives. 0.3-1 reads as a natural anticipation; the duration is the transition's own fade.\n * Ignored by hosts without it. */\n anticipate(amount: number): this;\n /** This layer's current loop (the object the last `playLoop()` returned), if any. */\n get loop(): Loop | undefined;\n /** Where this layer is in the gait cycle, 0–1 (-1 = what it shows has no cycle). */\n get phase(): number;\n /** Layer contribution 0–1. */\n get weight(): number;\n set weight(v: number);\n /** A one-shot on this layer hasn't handed over yet. */\n get busy(): boolean;\n /** What this layer shows this frame with its weight — its one-shot, or its loop's members. */\n get active(): ActiveClip[];\n}\n","types/gl/animation/Locomotion.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { Animator } from \"./Animator\";\nimport type { FeetOptions } from \"./Feet\";\nimport type { WarpOptions } from \"./Warp\";\nimport type { Node } from \"../Node\";\n/** How fast the character wants to go: the gait picks its clips and its speed. */\nexport type Gait = \"walk\" | \"run\" | \"sprint\";\n/** What the engine shows: the idle, a start, the gait loop, a turn while moving, a stop, a turn on the spot —\n * an ACTION (`act()`): a one-shot that owns the body until it hands over — or the STRAFE blend (`move({ strafe })`). */\nexport type LocomotionState = \"idle\" | \"start\" | \"move\" | \"turn\" | \"stop\" | \"spin\" | \"action\" | \"strafe\";\n/** Who moves the body:\n * `'hybrid'` (the default) — the clip's own recorded motion moves it; while the gait loop shows it\n * is ADJUSTED toward what the simulation wants by at most `tuning.adjust` metres a second, and a\n * start / turn / stop / spin moves it alone. The recording keeps the feet honest, the clamp keeps\n * the player in charge of the arcs. What a pack authored with root motion wants.\n * `'code'` — the simulation moves it and the animation has to be warped to follow (stride warping);\n * for packs recorded in place.\n * `'data'` — the clips' root motion moves it and nothing adjusts it; the simulation only predicts. */\nexport type Displacement = \"hybrid\" | \"code\" | \"data\";\n/** One clip of the set: its name, or the name with what the clip itself cannot say — `gait` (which\n * gait a transition belongs to: a walking body plays the walking starts, stops and turns; left out =\n * any gait) — and overrides for what the engine would otherwise measure: `angle` (degrees the clip\n * turns the body, + = left) for a start / turn / spin, `speed` (m/s) for a gait clip. */\nexport type LocomotionClip = string | {\n clip: string;\n gait?: Gait;\n angle?: number;\n speed?: number;\n};\n/** The clips the selector may show. Everything but `idle` is a list; an empty one simply means the\n * engine never shows that kind (a pack without turns steers through them instead). */\nexport type LocomotionSet = {\n /** standing still */\n idle?: LocomotionClip;\n /** the gait loop's members, slowest first — walk, run, sprint. Blended by the simulated speed. */\n gaits?: LocomotionClip[];\n /** standing → moving, one per direction (the engine picks by the turn each one makes) */\n starts?: LocomotionClip[];\n /** moving → standing */\n stops?: LocomotionClip[];\n /** turns taken while moving */\n turns?: LocomotionClip[];\n /** turns on the spot — what a facing still owed by a standing body plays */\n spins?: LocomotionClip[];\n /** the STRAFE set: the same gait recorded forward, backward, to either side and on the diagonals — the members of\n * the directional blend `move(dir, { face, strafe: true })` shows. `angle` = the way a take travels in the body's\n * frame (degrees, + = left); left out, the engine reads it off the take's root. */\n strafes?: LocomotionClip[];\n};\n/** The tuning. Times are seconds, speeds m/s, angles degrees. */\nexport type LocomotionTuning = {\n /** How briskly the simulated speed reaches the wanted one — the halflife of the difference, per\n * gait (default 0.27 walking, 0.2 running). Smaller = more responsive, larger = heavier. */\n responseWalk?: number;\n responseRun?: number;\n /** How briskly the body brakes when nothing is asked for (default 0.15). Braking is not\n * acceleration backwards: a body plants and stops in far less than it takes to reach a run, and\n * with the gait's own number the tail of the curve is a long, visible glide. */\n responseStop?: number;\n /** The same for the facing (default 0.15). */\n responseFacing?: number;\n /** Top speed per gait. Left out (the default), each gait travels at the speed its own clip was\n * recorded at — which is what keeps the feet from sliding. */\n speeds?: Partial<Record<Gait, number>>;\n /** The step warp's split when a gait is asked for at a speed that is not its clip's own: the\n * STRIDE (spatial squash of the leg's reach) gets ratio^strideShare, clamped to `strideBand`,\n * and the cadence takes all the rest — the asked speed is always delivered exactly.\n * 0 = all cadence (slow motion), 1 = all stride (within the band). Default 0.5. */\n strideShare?: number;\n /** How far the stride's share may squash or stretch the legs' reach (default [0.85, 1.15]) —\n * past it the warp re-bends legs the clip authored straight. */\n strideBand?: [number, number];\n /** PIN the step warp's stride ratio (a tuning bench's knob): the step width is held at exactly\n * this, whatever speed is asked — the body's speed falls out of stride × cadence instead of\n * driving the split. Leave out (or 0) for automatic. */\n warpStride?: number;\n /** PIN the step warp's cadence ratio the same way — the animation's pace held at exactly this.\n * With both pinned, stride and pace are fully independent. Leave out (or 0) for automatic. */\n warpCadence?: number;\n /** Cap on how fast the body may turn by STEERING, deg/s (default: uncapped) — the arc it walks when\n * the heading is off by less than `turnMin`. A start / turn / spin clip owns the facing while it\n * turns: the body then turns exactly as much as the (warped) animation does. */\n turnRate?: number;\n /** Heading error that plays a turn clip instead of steering through it (default 60°). Which turn\n * clip is not a threshold: every one is entered where the gait phase allows nearest to its pivot,\n * and the one whose turn LEFT from there best answers the error wins. */\n turnMin?: number;\n /** Facing still owed by a standing body that turns it on the spot (default 30°). Less than this it\n * accepts — a standing body never rotates by code, that is the one thing no tuning makes look right. */\n spinMin?: number;\n /** Transition seconds between clips (default 0.2), and into the idle after a stop (default 0.3). */\n blend?: number;\n stopBlend?: number;\n /** How far a start / turn / spin clip's recorded turn may be SCALED so it delivers exactly the heading\n * asked for, as a fraction (default 0.3 = ×0.7 … ×1.3). What lies beyond the clamp is steered once\n * the body moves. 0 = the recording is law. */\n yawWarp?: number;\n /** A start or a turn hands over to the gait loop at the first foot-down after its turn is delivered\n * at which its pose is within this many metres of the loop's — the engine's baked fit curve —\n * instead of at its end (default 0.15). 0 = at the end. */\n exitTolerance?: number;\n /** A stop asked to move again resumes the gait loop while the body still travels at this fraction of\n * the gait's speed or more (default 0.5); slower, it starts afresh. */\n resumeSpeed?: number;\n /** …and then let it play this many more FOOT-DOWNS before handing over (default 0). `exitTolerance`\n * answers \"when has this pose become the walk's\", which is the earliest honest moment and not always\n * the best-looking one — a start that has just found the gait still reads as a start for another step\n * or two. 1 or 2 gives a take room to finish its thought; a take that runs out hands over at its own\n * end regardless, so nothing can hang. */\n exitSteps?: number;\n /** How much braking room, in metres, to trade for each second of a stop take's lead-in that would\n * otherwise be skipped (default 0). A stop cannot be rewound — the variants are one cycle long, so\n * no earlier frame has the same foot down — so the only way to begin a stop nearer its own start is\n * to prefer the VARIANT that starts there for the foot the body happens to be on. Raise it (0.5…1.5)\n * to see the whole braking gesture; leave it at 0 to land exactly where the body should stop. */\n stopEarly?: number;\n /** How much braking room, in metres, one extra FOOT-DOWN in the stop is worth (default 0). A stop\n * take is one cycle long, so wanting another step means wanting a LONGER variant, and a longer one\n * lands the body further along than it asked to stop — the trade is this number. Around 1 buys a\n * second step on a pack like Mobility Pro; 0 lands exactly where the body should stop. */\n stopSteps?: number;\n /** How far a stop take's pose may be from the one showing, in metres, for it to be entered BEFORE\n * its own first foot-down (default 0.25). Ahead of that footfall a take's phase curve is an\n * extrapolation: it can match the body's phase arithmetically with the legs at a different stage\n * of the stride, which is why the pose is asked directly. 0 = never enter a take early — the body\n * then takes whatever later entry matches its foot, which on a walk can be three quarters of the\n * way through a take, on top of one of its plants. */\n stopFit?: number;\n /** What a metre of POSE distance at the entry is worth against a metre of braking room when the\n * variants are ranked (default 1). Both are metres and the feet pay both: room the body has not\n * got is taken out of the root while a foot is planted, and a pose the transition has to hide is\n * dragged out of that same foot over the blend. 0 = rank by braking room alone, which picks a\n * take by where it ENDS and lets it start from any pose at all. */\n stopPose?: number;\n /** Input magnitude below which a stick counts as released (default 0.2). */\n deadZone?: number;\n /** `displacement: 'hybrid'`: how far, m/s, the body may be pushed off what the animation recorded,\n * toward what the simulation wants, while the gait loop shows (default 0.5) — a start, turn, stop\n * or spin moves the body alone, since pushing it there is its planted foot skating. 0 = the\n * recording is law; large = the code is law — responsive, and the feet start lying. */\n adjust?: number;\n};\n/** One stop take as the selector weighed it, from `stopReport()`. A stop is chosen for the foot the\n * body stands on and the room it needs: `phaseOk` and `afterFirstStep` are the two pass/fail rules,\n * `score` ranks whatever passed (lower wins), and `chosen` marks the one that plays. */\nexport type StopCandidate = {\n /** the take's clip name */\n clip: string;\n /** seconds into it the entry would be — near its end means its braking gesture is skipped */\n at: number;\n /** metres it still travels from that entry */\n room: number;\n /** metres this body needs to come to rest (the same for every row) */\n need: number;\n /** seconds from the entry to its next foot-down */\n wait: number;\n /** foot-downs left after the entry: 0 = it plants where it stands */\n steps: number;\n /** does it have a frame at the body's own cycle phase (the right foot down)? */\n phaseOk: boolean;\n /** is that frame at or after its own first foot-down? Ahead of it the phase curve is an\n * extrapolation — it can match arithmetically at the wrong stage of the stride */\n afterFirstStep: boolean;\n /** …and it is ahead of it, but its POSE matched what is showing closely enough to be let in\n * anyway (`fit` under `tuning.stopFit`) */\n earlyByPose: boolean;\n /** the one that is playing */\n chosen: boolean;\n /** |room − need| + the pose distance + how late in the take (lower wins) */\n score: number;\n /** how far this entry's pose is from the one showing, in the fit measure's metres (-1 = not\n * measured). Under `tuning.stopFit` an entry ahead of the take's first foot-down is allowed. */\n fit: number;\n};\nexport type LocomotionEvents = {\n /** What the selector shows changed. */\n state: (state: LocomotionState) => void;\n};\nexport declare class Locomotion extends Aspect<\"loco\", Node, LocomotionEvents> {\n static readonly aspect = \"loco\";\n /** The animator whose clips are shown. Default: the first one on this node or under it (a Model\n * child), which is the usual character — a capsule node with the model inside. */\n animator?: Animator;\n /** The clips the selector may show. */\n set: LocomotionSet;\n /** Who moves the body (see `Displacement`). */\n displacement: Displacement;\n /** The feel (see `LocomotionTuning`). */\n tuning: LocomotionTuning;\n /** Fit the POSE to what the body does — stride and orientation warping (see `Animator.warp`, which\n * this simply sets). The simulation feeds the engine the body's motion every frame, so here it\n * only has to be turned on: `warp: true`, or `{ stride: [0.7, 1.4], orientation: 45 }`. Off by\n * default — a pack whose gaits already cover the speeds it is played at does not need it. */\n warp?: WarpOptions | boolean;\n /** The FEET (see `Animator.feet`, which this simply sets). Default: the foot lock on, ground IK off\n * — a planted foot stays where it landed through every transition the selector makes, which is the\n * last of the slide once the recording moves the body. `true` = lock + ground IK (stairs, slopes);\n * `false` = neither; or the options themselves. */\n feet?: FeetOptions | boolean;\n private _loco;\n private _dir;\n private _face;\n private _mag;\n private _gait;\n private _seq;\n private _act;\n private _strafe;\n private readonly _in;\n private readonly _out;\n private readonly _names;\n private _report?;\n private get anim();\n private get controller();\n protected onAttach(): void;\n protected onDetach(): void;\n /** Re-read the set and the tuning — after changing either at runtime (a weapon that changes the\n * walk, a slowed-down character). */\n rebuild(): void;\n /** Register one clip of the set: the engine measures the clip's own turn / speed unless given. */\n private enter;\n /** Why the stop that is playing is the one that plays: every candidate the selector weighed, in\n * the order it weighed them. Read it when a stop looks wrong — the answer is usually that the\n * take that would have looked right was rejected by one of the two rules, not that the score\n * picked badly. Empty until a stop has been chosen (and on hosts without the debug read). */\n stopReport(): StopCandidate[];\n /** Re-push the TUNING alone — the numbers, not the clip set. What a live tweak wants (a debug\n * slider, a character that gets heavier when hurt): `rebuild()` also re-measures the set, which\n * mid-clip is more than a changed number asks for. */\n retune(): void;\n private pushTuning;\n /** State the movement intent for this frame: a world direction (its length is the stick's pull,\n * clamped to 1) and the gait. `null` = no movement — the body stops, but it keeps facing where it\n * was last asked to, and turns there on the spot if it still owes the turn.\n * `face` states a facing of its own (aiming, a camera-relative shooter) — and with `strafe: true` the body MOVES\n * where the direction points while it faces there: the loop becomes the directional blend of `set.strafes` (a\n * guard, a lock-on), the facing is steered standing too, state `'strafe'`. Stated every frame like the rest. */\n move(direction: Vec3Like | null | undefined, options?: {\n gait?: Gait;\n face?: Vec3Like;\n strafe?: boolean;\n }): void;\n /** Play an ACTION: a one-shot that OWNS the body the way a start or a stop does — a roll, a backstep, a lunging\n * attack. Its recording moves the body alone (in every displacement mode but `'data'`, where the host does),\n * the steering and the selector stand by, and when it hands over the usual rules carry on: a direction held\n * starts (or, still carrying speed, runs on), nothing held stands.\n *\n * `direction` is where its TRAVEL must go, world (`Vec3`, or a heading in degrees, 0 = +Z, + = toward +X). A\n * clip travels some way relative to the body — forward, left, back; measured off its own root, or `angle`\n * (degrees, + = left) — and the body is turned by what is left between that and `direction`, over `turn`\n * seconds (default 0.12), so the travel lands exactly where it was pointed. Which clip to play is yours to\n * pick: the one whose travel is nearest the direction IN THE BODY'S FRAME (`direction − facing`) leaves the\n * least to turn. Left out = it plays where the body faces.\n *\n * `at` enters the clip that many seconds in (a wind-up skipped), `rate` plays it faster or slower (its metres\n * stay, the time changes), `travel` takes only that share of its recorded travel (an attack aimed at a target:\n * 0.3 to stop at the blade's length from one that is close, 1.3 to reach one a step too far — the pose is\n * untouched, so keep it to a fast step; `{ share, at, after }` takes another share from clip time `at` on: a\n * swing's take travels on after its cut, into a body that stands at the blade's length), `dash` THROWS the body\n * `distance` metres along the action's direction on top of that, inside `time` seconds (default 0.12) from its first\n * step, eased out — the gap to a target closed in the wind-up, the blow struck from where it lands (scaling a take's\n * own step is a slide stretched over the whole swing), `fade` is the transition into it and `out` the one out of it (default: the tuning's\n * `blend`; an action ends in ITS stance, not the idle's, and a longer way out is what hides that), and `exit` is the\n * clip time from which a MOVE intent may take over — the cancel window: along the way the body faces at once, a\n * heading that needs a turn as soon as the body has slowed to where a start can answer; with nothing asked for it plays out, to\n * its end (an action ends in its own recovery, at rest), and the body then STANDS THE WAY THE ACTION LEFT IT:\n * the facing intent that outlives a released key is not a demand after an action — no turn on the spot.\n * WHEN an action may be asked for (out of another one, out of a start) is the caller's rule: this cuts into\n * whatever shows. `state` reads `'action'` while it does. False = no such clip. */\n act(clip: string, options?: {\n direction?: Vec3Like | number;\n angle?: number;\n turn?: number;\n at?: number;\n exit?: number;\n fade?: number;\n out?: number;\n rate?: number;\n travel?: number | {\n share: number;\n at: number;\n after: number;\n };\n dash?: {\n distance: number;\n time?: number;\n };\n }): boolean;\n /** Face this way without moving — the facing intent on its own (`Vec3`, or a heading in degrees,\n * 0 = +Z, + = toward +X). A standing body turns to it on the spot. */\n face(direction: Vec3Like | number): void;\n /** The gait the intent asks for. */\n get gait(): Gait;\n set gait(g: Gait);\n /** Is a movement intent standing right now? (The debug answer to \"is a key held\".) */\n get moving(): boolean;\n /** The direction the intent points, world. */\n get direction(): Vec3;\n /** The heading the intent asks the body to face, degrees (0 = +Z, + = toward +X). */\n get heading(): number;\n /** The speed the intent asks for, m/s — it jumps the moment a key goes down or the gait changes.\n * `speed` is what the body has made of it. */\n get intentSpeed(): number;\n /** What the selector shows. */\n get state(): LocomotionState;\n /** The body's speed, m/s — the simulation's, which is what the animation is fitted to. */\n get speed(): number;\n /** The body's velocity, world m/s. */\n get velocity(): Vec3;\n /** Where the body faces, degrees (0 = +Z, + = toward +X) — the node's yaw, which this drives. */\n get facing(): number;\n /** Where the base layer is in the gait cycle, 0–1 (-1 when what shows has no cycle). */\n get phase(): number;\n /** How far the STOP that is showing was entered from the phase the body was on, in cycles, signed —\n * measured at the switch. 0 while no stop shows; ±0.5 would be the other foot on the ground. */\n get stopFootOffset(): number;\n /** Foot-downs left in the stop that is showing, counted from the frame it was entered at. 0 means it\n * was entered past its own last footfall — the body will not step, it will only settle. -1 when no\n * stop shows. The number behind \"he did not take a step, he just pulled the foot back\". */\n get stopStepsLeft(): number;\n /** Seconds from the frame the shown stop was entered at to its next foot-down. Large means it was\n * entered just AFTER a footfall: the leg is planted and then held still until the one after, which\n * reads as a foot that sticks. -1 when no stop shows. */\n get stopStepWait(): number;\n /** Degrees the clip showing still turns the body by (a start / turn / spin, after its warp); 0 for\n * the loop and the idle — the heading the engine has committed to but not yet delivered. */\n get yawLeft(): number;\n /** The shown transition's clip time and the time it hands over at, seconds (-1 for the loop / idle;\n * `exitAt` -1 = at the clip's end). A debug readout. */\n get clipTime(): number;\n get exitAt(): number;\n /** Where the body will be in 0.2 / 0.4 / 0.7 s if the intent holds — the path the selector judges\n * a turn by, and a debug overlay's dots. */\n get trajectory(): Vec3[];\n protected updateBefore(dt: number): void;\n protected updateFixed(dt: number): void;\n}\n","types/gl/animation/Loop.d.ts":"import type { BlendPosition } from \"./core\";\nexport declare class Loop {\n private readonly _r;\n private readonly _c;\n /** Position on the axis (number) or plane (`[x, y]`) — units are whatever the positions use. Live\n * even while a one-shot plays (the loop returns at the new mix). */\n get value(): BlendPosition;\n set value(v: BlendPosition);\n /** Where the loop is in its GAIT cycle, 0–1: 0 at a left-foot-down, 0.5 at a right-foot-down —\n * one clock for every member, aligned by their contacts (a walk and a run whose feet land at\n * different fractions of their clips still agree). Set it to jump the cycle: `playLoop(def,\n * { phase })` on the way in, or here to re-sync with something else. */\n get phase(): number;\n set phase(v: number);\n /** Each member's share of the mix, 0–1. */\n get weights(): Record<string, number>;\n}\n","types/gl/animation/Playback.d.ts":"import type { AnimationClip } from \"./AnimationClip\";\nimport type { StopOptions } from \"./core\";\nimport type { Layer } from \"./Layer\";\nexport declare class Playback implements PromiseLike<boolean> {\n private readonly _r;\n private readonly _c;\n /** The clip that plays. */\n get clip(): AnimationClip;\n /** The layer it plays on. */\n get layer(): Layer;\n /** Clock (s). */\n get time(): number;\n /** 0–1 through the clip (the current cycle, when looping). */\n get progress(): number;\n /** Where this clip is in the GAIT cycle now, 0–1 (-1 when it has none). */\n get phase(): number;\n /** The root yaw the clip has turned the body by so far, radians (+ = left) — a turn clip's progress. */\n get turned(): number;\n /** The root yaw still to come: where this clip will leave the body facing, relative to now (rad). */\n get turnLeft(): number;\n /** The horizontal distance the clip's root has travelled so far, metres. */\n get travelled(): number;\n /** Not handed over yet (the clip still owns the layer). */\n get playing(): boolean;\n /** Contribution to the pose: 1 while this clip is the layer's source, 0 once something else took\n * the layer over (the difference between the two poses is what decays, not this weight). */\n get weight(): number;\n /** Resolves at the hand-over (`true`) or when cut short (`false`) — the promise `await playback`\n * uses; the one to return from async functions or put in `Promise.all`. */\n get done(): Promise<boolean>;\n then<A = boolean, B = never>(onFulfilled?: ((v: boolean) => A | PromiseLike<A>) | null, onRejected?: ((e: unknown) => B | PromiseLike<B>) | null): Promise<A | B>;\n /** Move the clock (s). */\n seek(time: number): this;\n /** Cut this clip short (the layer's loop comes back if nothing else takes over), over `fade`. */\n stop(options?: StopOptions): this;\n}\n","types/gl/animation/Warp.d.ts":"/** What `anim.warp` turns on. Speeds are m/s, angles degrees, distances metres. */\nexport type WarpOptions = {\n /** Fit the stride to the speed the body actually travels at. `[min, max]` clamps the scale (default\n * 0.85…1.2). A CORRECTION: a pack whose takes already read right at the speeds it is played at wants\n * none of this; open the range for a pack that must cover speeds it was never recorded at. The clip's\n * own speed is its root motion — an in-place loop takes part only with a declared pace (see above). */\n stride?: boolean | [number, number];\n /** Turn the lower body toward where the body really travels; a number caps the turn in degrees\n * (default 20). The whole twist lives in one joint: a few degrees read as a lean, a lot as a broken\n * back. Only applied while the gait LOOP shows — a start, a turn or a stop walks a path of its own. */\n orientation?: boolean | number;\n /** Below this speed — the game's or the clip's — both warps are off (default 0.2). */\n minSpeed?: number;\n /** How far the pelvis may drop to keep a stretched leg from locking straight (default 0.25). */\n pelvis?: number;\n /** The stride scale's own spring, seconds (default 0.15): the shown clip's recorded speed steps at every\n * switch, so the scale is smoothed rather than followed. */\n strideTime?: number;\n};\n/** STEP WARP dials (`anim.warp.step`): `stride` scales each foot's travel-direction offset from its hip,\n * `lift` = metres ADDED to its height (swing-gated; negative = a shuffle; half of it raises the pelvis),\n * `pitch` (degrees, + = toes up) rotates each foot about its lateral axis, `slope` (degrees, + = ascending)\n * the invisible staircase — feet on the incline, auto pitch, the character raised to hold each planted\n * foot on its tread. A tuning bench's dial; locomotion will drive this itself later. */\nexport type StepWarpOptions = {\n stride?: number;\n lift?: number;\n pitch?: number;\n slope?: number;\n};\nexport declare class Warp {\n private readonly _c;\n private _o;\n private _step;\n /** Replace the settings: `true` = both warps with the defaults, `false` / `{}` = off, or the options.\n * (Replaces, does not merge — what is not asked for is off.) Chainable. */\n set(w: WarpOptions | boolean): this;\n /** The current settings. */\n get options(): Readonly<WarpOptions>;\n get stride(): boolean | [number, number];\n set stride(v: boolean | [number, number]);\n get orientation(): boolean | number;\n set orientation(v: boolean | number);\n get minSpeed(): number;\n set minSpeed(v: number);\n get pelvis(): number;\n set pelvis(v: number);\n get strideTime(): number;\n set strideTime(v: number);\n /** The step warp dials; `null` = off. */\n get step(): StepWarpOptions | null;\n set step(v: StepWarpOptions | null | undefined);\n private push;\n}\n","types/gl/audio/AudioSource.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { type PlaySoundOptions, type Rolloff } from \"../../audio/audio\";\nimport type { Sound } from \"../../audio/Sound\";\nimport type { Voice } from \"../../audio/Voice\";\nimport type { Node } from \"../Node\";\nexport type AudioCone = {\n /** Degrees of full volume around the node's −Z. */\n inner: number;\n /** Degrees where the volume has fallen to `outerGain`. */\n outer: number;\n /** Volume behind the source, 0 … 1. */\n outerGain?: number;\n};\nexport declare class AudioSource extends Aspect<\"audio\", Node> {\n static readonly aspect = \"audio\";\n static fields: FieldMeta<AudioSource>;\n private _minDistance;\n private _maxDistance;\n private _rolloff;\n private _cone;\n private _doppler;\n private _spread;\n private _occlusion;\n private _bus;\n /** Metres of full volume around the node. Default 1. */\n get minDistance(): number;\n set minDistance(v: number);\n /** Metres beyond which the source no longer gets quieter. Default 50. */\n get maxDistance(): number;\n set maxDistance(v: number);\n /** `inverse` (default), `linear`, `exponential`, `none`. */\n get rolloff(): Rolloff;\n set rolloff(v: Rolloff);\n /** Directional source along the node's −Z; null = omnidirectional (default). */\n get cone(): AudioCone | null;\n set cone(v: AudioCone | null);\n /** Doppler amount 0 … 1 (0 = off, the default) — needs the node to actually move. */\n get doppler(): number;\n set doppler(v: number);\n /** 0 = pin-point panning (default) … 1 = the same on every speaker (a big, close source). */\n get spread(): number;\n set spread(v: number);\n /** The engine raycasts listener → source (against solid bodies) and muffles the voices when\n * something is in the way. Default false. */\n get occlusion(): boolean;\n set occlusion(v: boolean);\n /** Default bus for voices on this source. Default `sfx`. */\n get bus(): string;\n set bus(v: string);\n /** Live voices on this source. */\n get voices(): number;\n onAttach(): void;\n onDetach(): void;\n /** Play a clip from this node. */\n play(sound: Sound, options?: PlaySoundOptions): Voice;\n /** Stop every voice on this source (fade in seconds). */\n stopAll(fade?: number): void;\n private _push;\n}\n","types/gl/audio/AudioZone.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type ReverbParams, type ReverbPreset } from \"../../audio/Bus\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\nexport declare class AudioZone extends Aspect<\"audioZone\", Node> {\n static readonly aspect = \"audioZone\";\n private _box;\n private _sphere;\n private _reverb;\n private _blend;\n private _bus;\n /** The engine's zone id — what `audio.stats.listenerZone` reports while the listener is inside. */\n get id(): number;\n /** Half-extents [hx, hy, hz]; falls back to the node's Shape box, then a 1 m cube. */\n get box(): Vec3Like | null;\n set box(v: Vec3Like | null);\n /** Radius; falls back to the node's Shape sphere. */\n get sphere(): number | null;\n set sphere(v: number | null);\n /** A preset name or explicit params (see Bus.reverb). */\n get reverb(): ReverbPreset | ReverbParams;\n set reverb(v: ReverbPreset | ReverbParams);\n /** Crossfade depth in metres inside the border (0 = a hard edge). Default 1. */\n get blend(): number;\n set blend(v: number);\n /** The bus the zone's reverb rides on. Default `sfx`. */\n get bus(): string;\n set bus(v: string);\n onAttach(): void;\n onDetach(): void;\n private _push;\n}\n","types/gl/audio/SceneAudio.d.ts":"import type { Node } from \"../Node\";\nexport declare class SceneAudio {\n private _listener;\n private _doppler;\n /** The node the engine listens from; null (default) = the active camera. */\n get listener(): Node | null;\n set listener(node: Node | null);\n /** Multiplies every source's doppler amount (0 = off everywhere). Default 1. */\n get dopplerFactor(): number;\n set dopplerFactor(v: number);\n}\n","types/gl/Camera.d.ts":"import { Vec3 } from \"../math/vec\";\nimport { Node, type NodeTweenProps } from \"./Node\";\nimport { Ray } from \"./Ray\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport type { Animation } from \"../animate/tween/Animation\";\n/** Animatable camera props on top of the node transform. */\nexport type CameraTweenProps = NodeTweenProps & {\n fov?: number | number[];\n near?: number | number[];\n far?: number | number[];\n};\n/** Projection every host starts a scene with (creator-gl scene.cpp / the lite core agree on these). */\nexport declare const CAMERA_DEFAULTS: {\n fov: number;\n near: number;\n far: number;\n};\nexport declare class Camera extends Node {\n private _sceneId;\n /** Tween `fov` / `near` / `far` (a zoom, a dolly) and the transform — see {@link Node.animateTo}. */\n animateTo(props: CameraTweenProps & TweenMeta): Animation;\n animateFrom(props: CameraTweenProps & TweenMeta): Animation;\n /** Live projection matrix (updated by the host when the viewport/fov changes). */\n readonly projectionMatrix: Float32Array<ArrayBuffer>;\n private _fov;\n private _near;\n private _far;\n /** Stay quiet until the app actually sets something — hosts may be configured with their own\n * defaults (the headless core takes a `fov` option) and a blind push would overwrite them. */\n private _projSet;\n private _exposure;\n private _ev;\n private _exposureSet;\n /** Exposure compensation in stops (default 0): +1 doubles how bright the scene renders, −2\n * quarters it. The one exposure knob most games need — a dark interior, a flash of white, or eye\n * adaptation when the sun swings into view (drop it, and the sun stays at the display's peak\n * while everything else darkens). Scene light follows it; particle `emissive` is post-exposure\n * and does not, so a fireball keeps its on-screen brightness. Cheap to animate every frame. */\n /** The camera's EV100 with the compensation in: log2(aperture² / shutterSpeed x 100 / iso) - compensation. Sunny 16 is\n * ~15; a lit surface of luminance L lands on screen at L / (1.2 x 2^ev100). */\n get ev100(): number;\n get exposureCompensation(): number;\n set exposureCompensation(stops: number);\n /** The physical camera: `aperture` in f-stops, `shutterSpeed` in seconds, `iso`, plus the same\n * `compensation` in stops — any subset, one call. `camera.setExposure({ iso: 400 })` is two stops\n * brighter than the default f/16 · 1/125 · ISO 100. */\n setExposure(exposure: {\n aperture?: number;\n shutterSpeed?: number;\n iso?: number;\n compensation?: number;\n }): this;\n /** Hosts that predate the call keep the fixed default (older wasm / native builds). */\n private _applyExposure;\n /** Vertical field of view in degrees (default 60) — a smaller angle is a longer lens. */\n get fov(): number;\n set fov(degrees: number);\n get horizontalFov(): number;\n /** Near clip distance (default 0.01) — nothing closer than this draws. */\n get near(): number;\n set near(distance: number);\n /** Far clip distance / view range (default 1000) — geometry past it is culled. Shadows keep\n * their own (shorter) range, so a long view distance doesn't cost shadow sharpness. */\n get far(): number;\n set far(distance: number);\n /** Set any of fov / near / far in one call: `camera.setProjection({ fov: 45, far: 5000 })`. */\n setProjection(projection: {\n fov?: number;\n near?: number;\n far?: number;\n }): this;\n /** Hosts that predate the call keep the fixed defaults (older wasm / native builds). */\n private _applyProjection;\n private _following;\n /** The node the camera currently follows (`follow()`), or null. */\n get following(): Node | null;\n /**\n * Make the camera ride a node: every late frame the camera takes the node's WORLD pose (−Z =\n * view direction), so movement aspects / animation on that node are camera moves — dolly shots,\n * a cutscene path, a `CameraPlace` in a scene file. A node carrying a `CameraPlace` also hands\n * over its projection (fov / near / far). `follow(null)` releases the camera where it is.\n * One camera per scene: following a new node stops following the previous one.\n */\n follow(target: Node | {\n node: Node;\n applyTo(camera: Camera): void;\n } | null): this;\n get displaySize(): [number, number];\n /** World-space ray direction through a screen pixel. */\n getViewDirection(screenX: number, screenY: number): Vec3;\n /** A pick ray from the camera through a screen pixel. */\n getRay(screenX: number, screenY: number): Ray;\n}\n","types/gl/CameraPlace.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { FieldMeta } from \"../core/fields\";\nimport type { Camera } from \"./Camera\";\nimport type { Node } from \"./Node\";\nexport declare class CameraPlace extends Aspect<\"cameraPlace\", Node> {\n static readonly aspect = \"cameraPlace\";\n /** Vertical field of view in degrees (default 60) — smaller is a longer lens. */\n fov: number;\n /** Near clip distance. */\n near: number;\n /** Far clip distance = view range. */\n far: number;\n /** The place that drives `scene.camera` when the file declaring it RUNS. Exactly one per file;\n * ignored inside prefabs / instantiated subtrees (the host scene owns its camera). */\n active: boolean;\n /** Aspect ratio of the frustum gizmo only (the real aspect is the viewport's). */\n static fields: FieldMeta<CameraPlace>;\n static editor: {\n rebuild: boolean;\n };\n /** Copy this place's projection onto a camera (`camera.follow(place)` does it for you). */\n applyTo(camera: Camera): void;\n /** Edit mode: the frustum marker (−Z = view), anchored on the node so it follows drags live and\n * clicking it selects the node. Play mode never calls this. */\n rebuild(): void;\n}\n","types/gl/controls.d.ts":"import type { Node } from \"./Node\";\nimport type { Scene } from \"./Scene\";\nexport type ControlsOptions = {\n /** Smallest uniform scale the pinch gesture allows (default 0.08). */\n minScale?: number;\n /** Largest uniform scale the pinch gesture allows (default 2). */\n maxScale?: number;\n /** One-finger drag moves the target across the ground plane (default true). */\n pan?: boolean;\n /** Two-finger pinch scales the target (default true). */\n pinch?: boolean;\n /** Two-finger twist rotates the target around its Y axis (default true). */\n twist?: boolean;\n};\n/** Returned by `addControls` — call `remove()` to detach the gesture listeners. */\nexport type ControlsHandle = {\n remove(): void;\n};\nexport declare const attachControls: (scene: Scene, target: Node, options?: ControlsOptions) => ControlsHandle;\n","types/gl/DecalSet.d.ts":"import { Node } from \"./Node\";\nimport { Material } from \"./Material\";\nimport type { Texture } from \"./Texture\";\nimport { type Vec3Like } from \"../math/vec\";\nimport { type QuatLike } from \"../math/quat\";\nimport { type ColorInput } from \"../core/color\";\n/** Per-decal look and life — defaults come from the set's options. */\nexport type DecalOptions = {\n /** Image width and height on the surface (world units); a number = square. Default 0.2. */\n size?: number | [number, number];\n /** Projection depth (world units): how far in front of and behind the hit point the decal still\n * lands. Default = the smaller of width / height. */\n depth?: number;\n /** Atlas cell (row-major from the top-left) for a set with a `sheet`; `\"random\"` picks one.\n * Default 0. */\n frame?: number | \"random\";\n /** Tint multiplied into the image. Default white. */\n tint?: ColorInput;\n /** 0..1 on top of the tint's alpha. Default 1. */\n opacity?: number;\n /** Seconds until the decal is gone; 0 = stays until recycled. Default 0. */\n life?: number;\n /** Seconds to fade in after spawning. Default 0. */\n fadeIn?: number;\n /** Seconds of fade at the end of `life` (ignored with life 0). Default 0. */\n fadeOut?: number;\n /** Opacity multipliers at the image's BOTTOM and TOP edge (−Y / +Y), interpolated along it — a\n * tire mark that darkens as the slide deepens. Default `[1, 1]`. */\n gradient?: [number, number];\n /** Tilt of the image's bottom and top edge, as a unit-space slope (Δy per Δx across the box):\n * the edge pivots on the corner of the side it keeps and cuts INTO the box on the other, so two\n * boxes can meet on one shared line — what `DecalTrail` uses to mitre its joints. `0` = square.\n * Default `[0, 0]`. */\n caps?: [number, number];\n};\nexport type DecalSetOptions = DecalOptions & {\n /** The material — `Material.decal({ map })` by default (`map` below is its shortcut). A custom\n * material must keep decal.mat's vertex contract. */\n material?: Material;\n /** Atlas texture for the default material. */\n map?: Texture;\n /** Tangent-space normal atlas (same cell grid) → a RELIEF decal that bends the surface's\n * lighting instead of painting a colour (`Material.decal` `normalMap`). Footprints and dents\n * need only this; a bullet hole gives `map` too and its colour multiplies in. */\n normalMap?: Texture;\n /** Relief strength for `normalMap`. Default 1. Default material only. */\n bump?: number;\n /** Atlas grid of the map: columns, or [columns, rows]. Default 1 (the whole texture). */\n sheet?: number | [number, number];\n /** Slot budget — the most decals alive at once. Default 256. */\n max?: number;\n /** Soft fraction (0..1) of the box's half depth at both ends, so an oblique surface leaves the\n * box gently. Default 0.3. Default material only. */\n edge?: number;\n /** Surfaces turned more than this away from the projection axis fade out — the cosine of the\n * angle (0.3 ≈ 72°) keeps a floor hit off the wall it meets; 0 = project onto anything.\n * Default 0.3. Default material only. */\n angleFade?: number;\n /** HDR boost of the image (0 = none). Default material only. */\n emissive?: number;\n name?: string;\n /** Coarse draw order, 0 (first) … 7 (last) — see `Mesh.renderPriority`. Default 3: a decal is\n * part of the surface it sits on, so it draws before every other blended thing (meshes 4,\n * particles 5) — the engine's depth sort compares object centres, and a set spread over the\n * level has no useful centre. */\n renderPriority?: number;\n};\n/** `spawn` placement: where the image sits on the surface. */\nexport type DecalSpawnOptions = DecalOptions & {\n /** World direction the image's top points along the surface (projected onto it) — a footprint's\n * travel direction. Default: a random spin. */\n up?: Vec3Like;\n /** Extra spin around the normal, radians. Default: random when `up` is not given, else 0. */\n rotation?: number;\n};\n/** `place` / `update` placement: a full frame, like a node looking INTO the surface (its −Z is the\n * projection direction, +Y the image's top). */\nexport type DecalPlacement = DecalOptions & {\n position: Vec3Like;\n /** A quaternion, or Euler degrees (YXZ) like `Node.eulerAngles`. Default identity = projecting\n * down −Z. */\n rotation?: QuatLike | Vec3Like;\n};\nexport declare class DecalSet extends Node {\n private _material;\n private readonly _max;\n private readonly _cols;\n private readonly _rows;\n private readonly _defaults;\n private readonly _rec;\n private readonly _slots;\n private static _warned;\n constructor(options?: DecalSetOptions);\n get material(): Material;\n /** Decals alive right now. */\n get count(): number;\n /** The slot budget the set was created with. */\n get max(): number;\n /** Coarse draw order, 0 … 7 — see `Mesh.renderPriority`. Write-only. */\n set renderPriority(v: number);\n /** Stamp a decal on a surface: `point` on it, `normal` out of it (a raycast hit, a foot plant\n * with `Vec3.up`). Returns the slot for `update` / `remove` (−1 when the host draws none). */\n spawn(point: Vec3Like, normal: Vec3Like, options?: DecalSpawnOptions): number;\n /** Place a decal by a full frame (an editor-placed stain, a moving marker). Returns the slot. */\n place(placement: DecalPlacement): number;\n /** Move / restyle a placed decal; fields left out keep the values it was placed with. Its birth\n * time (the life clock) is kept. */\n update(slot: number, placement: Partial<DecalPlacement>): this;\n remove(slot: number): this;\n clear(): this;\n private _writePlacement;\n}\n/** A `DecalTrail`'s look: the strip's width, and what every segment carries. */\nexport type DecalTrailOptions = Omit<DecalOptions, \"size\" | \"caps\" | \"gradient\"> & {\n /** Width of the strip on the surface, world units. */\n width: number;\n};\n/**\n * A continuous strip of decals along a path — a tire's skid mark, a dragged body, a tread track.\n * Feed it points (`add`) as the thing moves; every new point becomes one box-decal SEGMENT from the\n * previous point, its image's up along the travel, and the joints between segments are MITRED: each\n * box is cut along the bisector it shares with its neighbour (`caps`), so the strip has no overlaps\n * darkening the outside of a bend and no wedges of gap on the inside. The opacity given with each\n * point is interpolated along the segment (`gradient`), so a mark can darken as a slide deepens and\n * fade as it ends. Segments are the set's decals — same ring, same `max` budget: a set of 900 holds\n * 900 segments across every trail drawn from it.\n *\n * The previous segment is REWRITTEN when the next point arrives (its far cap becomes the shared\n * mitre), through `DecalSet.update`'s path — a recycled slot is simply left alone by the engine.\n */\nexport declare class DecalTrail {\n private _prev;\n private _seg;\n readonly set: DecalSet;\n readonly options: DecalTrailOptions;\n constructor(set: DecalSet, options: DecalTrailOptions);\n /** Extend the strip to `point` on a surface with `normal`, `opacity` (0..1) at that point. The\n * first call after a start / `end()` only anchors the strip. Returns the new segment's slot, or\n * −1 when nothing was drawn (the anchor, a point that did not move, no host support). */\n add(point: Vec3Like, normal: Vec3Like, opacity?: number): number;\n /** Finish the strip. With a `point`, one last segment runs out to it at opacity 0 — a mark that\n * tapers away instead of stopping dead. The next `add` anchors a new strip. */\n end(point?: Vec3Like, normal?: Vec3Like): this;\n private _rewrite;\n /** Write one segment's box: the strip between its joints, extended past each mitred joint by the\n * mitre's reach (w/2 · |slope|) so the tilted cap still passes through the joint's centre. */\n private _box;\n}\n","types/gl/Foliage.d.ts":"import { Model } from \"./Model\";\nimport { Node } from \"./Node\";\nexport type FoliageWind = {\n /** Direction on the ground (x, z); normalised by the engine. Default [1, 0.3]. */\n direction?: [number, number];\n /** The wind speed in m/s — the plants' permanent bend and how fast the field drifts past them. Default 8.3\n * (30 km/h, the pack's demo). 0 = still. */\n speed?: number;\n /** 0..2: the random share of the speed — how far the bend wanders off the mean wind and how much the leaves move.\n * Default 0.4. */\n turbulence?: number;\n /** 0..1: the gusts' strength — waves of extra wind that travel over the level, calm between. Default 0.35. */\n gust?: number;\n /** m/s the gust pattern travels at. Default 5.6 (20 km/h). */\n gustSpeed?: number;\n};\nexport type FoliageOptions = {\n /** The wind, or `false` for none. */\n wind?: FoliageWind | false;\n /** Metres the TOP of a small plant leans away from a bender standing at its centre; the whole plant leans\n * as one, rooted at its base. Plants over ~2 m react less, trees over ~5 m not at all (the engine\n * measures each asset). Default 0.6. 0 = no touch reaction. */\n touch?: number;\n /** 0..1: how far each copy's tint drifts from the texture (warmer/darker to cooler/lighter, by a hash\n * of its position). Default 0.35. */\n variation?: number;\n /** 0..1: wrapped sun lighting — thin leaves let light through. Default 0.5. */\n sunWrap?: number;\n /** A multiplier on every material's shiver drag (the leaves' own motion on top of the bend): 1 = as the\n * model's materials say, 0 = the leaves ride the bend alone. Default 1. */\n shiver?: number;\n /** 0..1: the sun through a thin leaf lit from behind (a back-lit crown glows). Default 0.35. */\n translucency?: number;\n /** 0..1: how much of a light's shadow a leaf card takes. A crown scatters light through itself, so its cards take the\n * shadow map partly — at 1 a distant crown is a dark silhouette lit only on its top layer. Bark always takes the\n * shadow in full. Default 0.6. */\n leafShadow?: number;\n /** 0..1: how far the baked per-vertex sky visibility (the crown's interior, the trunk under it) darkens the ambient.\n * Default 0.7. */\n skyAo?: number;\n /** 0..1: a leaf card's shading normal, from the card's own plane (0) to the crown's hull normal (1) — what hides that a\n * crown is flat quads: each card is lit as the part of the volume it sits in. Default 0.7. */\n canopy?: number;\n /** The cards' normal-map strength (a strong map brings the planes back). Default 0.5. */\n normalMap?: number;\n /** A card seen edge-on dissolves over this much of |N·V| — no paper edges on the silhouette. Default 0.15, 0 = none. */\n edgeFade?: number;\n /** Coverage held over distance: the cards' alpha × (1 + coverage × mip level), so a far crown does not thin out as its\n * atlas mips away. Default 0.25, 0 = none; past ~0.5 a crown turns into a solid mass. */\n coverage?: number;\n};\nexport declare const Foliage: {\n /** Level-wide options; each field given replaces the current value (a scene file's `env.foliage`\n * goes through here). */\n configure(options: FoliageOptions): void;\n /** The wind: fields given replace the current ones; `false` = calm. Live. */\n wind(wind: FoliageWind | false): void;\n /** A node whose live position pushes the vegetation within `radius` metres (the hero: ~0.7; a\n * boulder: its size). Any number may be registered; the 8 nearest the camera act each frame. The\n * engine also tracks the node's velocity (smoothed over ~0.2 s): a plant you run through is brushed\n * forward and settles behind you instead of flipping as you cross its centre.\n * Returns the unregister function; a destroyed node drops out on its own. */\n bend(node: Node, radius?: number): () => void;\n /** Stop a node from bending the vegetation. */\n unbend(node: Node): void;\n /** Distance fade for EVERY copy of this model's asset (present and future): the cards thin out\n * from `start` to `end` metres from the camera and past `end` the copy leaves the frame entirely.\n * Small ground cover (grass, clover, flowers) is the target; `end` 0 = no fade. */\n fade(model: Model, start: number, end: number): void;\n};\n","types/gl/Geometry.d.ts":"import { type Vec3Like } from \"../math/vec\";\nexport type MeshKind = \"triangles\" | \"vertices\" | \"edges\";\n/** A geometry file — what `lecodes assets geometry <model.glb>` writes (`<model>.geometry.json`):\n * one merged, world-space triangle buffer. `Geometry.load(asset('./casing.geometry.json'))`. */\nexport type GeometryData = {\n format?: \"lecodes-geometry\";\n version?: number;\n /** xyz per vertex. */\n vertices: ArrayLike<number>;\n /** xyz per vertex (unit length). */\n normals: ArrayLike<number>;\n /** uv per vertex. */\n uv: ArrayLike<number>;\n /** Triangle list, ≤ 65535 vertices addressed. */\n indices: ArrayLike<number>;\n};\nexport declare class Geometry {\n vertices: Float32Array;\n normals: Float32Array;\n indices: Uint16Array;\n uv: Float32Array;\n /** Lightmap UV set (2 floats per vertex, non-overlapping, inside the unit square) — the\n * `Lightmap` atlas samples a Mesh through it. The box and cylinder builders fill it (their `uv`\n * tiles per face, which would fold every face onto the same texels); absent = the host reuses\n * `uv`, which is right for a plane. */\n uv1?: Float32Array;\n /** Per-vertex COLOURS: 4 bytes (r, g, b, a) per vertex, 0..255. A material that declares\n * `requires: [color]` reads them through `getColor()` — one mesh, many colours, no material per\n * shade (a debug drawer, a gradient along a curve). Absent = every vertex white, which is what\n * the built-in materials expect. */\n colors?: Uint8Array;\n constructor(vertices: Float32Array, normals: Float32Array, indices: Uint16Array, uv: Float32Array);\n translate(x: number, y: number, z: number): this;\n scale(x: number, y: number, z: number): this;\n scaleUV(x: number, y: number): this;\n set kind(kind: MeshKind);\n /** A box; `size` (default 1) scales the vertices AND lays the lightmap chart out in proportion to\n * the faces' areas (a floor's top face gets the texels, not its 1 m side strips). */\n static box(size?: Vec3Like | number): Geometry;\n static sphere(options?: SphereOptions): Geometry;\n static cylinder(options?: CylinderOptions): Geometry;\n /** A capsule along Y, centred at the origin: a cylinder `length` long (between the two cap centres)\n * with a hemisphere of `radius` on each end — one closed surface, smooth across the seams. */\n static capsule(options?: CapsuleOptions): Geometry;\n static plane(options?: PlaneOptions): Geometry;\n /** A Geometry from a geometry file's contents (`GeometryData` — see `Geometry.load`). The arrays\n * are copied into typed buffers, so the source object can be dropped. */\n static fromData(data: GeometryData): Geometry;\n /** Load a geometry file: `lecodes assets geometry casing.glb` → `casing.geometry.json` →\n * `await Geometry.load(asset('./casing.geometry.json'))`. A GLB's triangles as a plain buffer,\n * for `Particles({ mesh })` debris (shell casings, rubble) and `Mesh.from`.\n * A `.json` project file is INLINED by the compiler — `asset('./x.json')` is the parsed data, not\n * a URL — so that form (and `import data from './x.json'`) is read directly, no fetch; a string\n * (a URL, a non-`.json` asset such as `.geo`) is fetched. */\n static load(source: string | GeometryData): Promise<Geometry>;\n}\nexport type SphereOptions = {\n radius?: number;\n widthSegments?: number;\n heightSegments?: number;\n};\nexport type CapsuleOptions = {\n radius?: number;\n /** Distance between the two cap centres (the straight part); 0 = a sphere. Default 1. */\n length?: number;\n /** Segments around the axis. */\n widthSegments?: number;\n /** Rings per hemisphere (pole to equator). */\n capSegments?: number;\n};\nexport type CylinderOptions = {\n radius?: number;\n radiusTop?: number;\n radiusBottom?: number;\n edges?: number;\n smooth?: boolean;\n};\nexport type PlaneOptions = {\n normal?: Vec3Like;\n};\n","types/gl/InstancedMesh.d.ts":"import { Mat4, type Mat4Like } from \"../math/mat4\";\nimport { type QuatLike } from \"../math/quat\";\nimport { type Vec3Like } from \"../math/vec\";\nimport type { Geometry } from \"./Geometry\";\nimport { Material } from \"./Material\";\nimport type { MeshOptions } from \"./Mesh\";\nimport { Node } from \"./Node\";\n/** One instance's placement, local to the InstancedMesh node. Omitted fields mean identity. */\nexport type InstanceTransform = {\n position?: Vec3Like;\n /** Quaternion; wins over `eulerAngles`. */\n rotation?: QuatLike;\n /** Degrees (YXZ), like `Node.eulerAngles`. */\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n};\nexport declare class InstancedMesh extends Node {\n /** Instance capacity, fixed at construction. Unset instances are hidden. */\n readonly count: number;\n private _geometry;\n private _material;\n private _data;\n private _lo;\n private _hi;\n constructor(geometry: Geometry, count: number, options?: MeshOptions);\n get geometry(): Geometry;\n get material(): Material;\n set material(m: Material);\n /** Shadow flags for all instances (both at once — the engine sets them per draw). */\n setShadows(cast: boolean, receive?: boolean): this;\n private _touch;\n /** Place instance `i`. Pending until `commit()`. */\n setAt(i: number, t: InstanceTransform): this;\n /** Place instance `i` from a 4×4 column-major matrix (local to this node). */\n setMatrixAt(i: number, m: Mat4Like): this;\n /** Hide instance `i` (a zero matrix — no geometry is emitted for it). */\n hideAt(i: number): this;\n /** Bulk write: `matrices` holds 16 floats per instance, starting at instance `offset`. */\n setMatrices(matrices: ArrayLike<number>, offset?: number): this;\n /** The 4×4 of instance `i` as stored (a copy). */\n matrixAt(i: number): Mat4;\n /** Upload every change since the last commit (one bridge call covering the dirty range). */\n commit(): this;\n /** Whether edits are waiting for `commit()`. */\n get dirty(): boolean;\n}\n","types/gl/Light.d.ts":"import { type ColorInput } from \"../core/color\";\nimport type { Vec3Like } from \"../math/vec\";\nimport { Node, type NodeTweenProps } from \"./Node\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport type { Animation } from \"../animate/tween/Animation\";\n/** Animatable light props on top of the node transform. */\nexport type LightTweenProps = NodeTweenProps & {\n intensity?: number | number[];\n color?: ColorInput | ColorInput[];\n};\nexport type SunOptions = {\n /** Light direction (points where the light travels). Defaults to a typical key-light angle. */\n direction?: Vec3Like;\n /** Luminous intensity. */\n intensity?: number;\n color?: ColorInput;\n /**\n * Shadow quality (default 1):\n * 0 - no shadows\n * 1 - 1024 map, hard edges (one filtered tap; the cheap level, ~3 % of a frame on an iGPU)\n * 2 - 1024 map, soft edges (variance shadows + blur; ~+15 % of a frame on an iGPU)\n * 3 - 2048 map, contact-hardening soft edges (PCSS: sharp where the caster touches, softer\n * away; discrete-GPU territory, ~+60 % of a frame on an iGPU)\n * A lightmapped level already carries every static shadow, so 0 is a legitimate choice there.\n * On a level with a baked light grid the variance / PCSS filters cannot be used (they need every\n * receiver in the shadow map, and the baked statics are kept out of it): 3 renders as PCSS on the\n * depth map - the same contact-hardening look - and 2 renders as 1.\n */\n shadowsQuality?: 0 | 1 | 2 | 3;\n /**\n * Metres from the camera within which the sun casts shadows (default 100). Shadows fade out by\n * this distance and the shadow map covers only this range, so a shorter distance is crisper for\n * the same quality and puts fewer casters in the shadow pass. 30-40 is plenty in first person.\n */\n shadowDistance?: number;\n /**\n * How many shadow-map cascades split `shadowDistance` (default 1). One map over the whole range gives a tall\n * tree 5-10 cm shadow texels on its own trunk; 3 cascades put a tight map on the first metres and coarser\n * ones behind, fit to their texel grids so the shadow does not swim as the camera moves. Each cascade is\n * another caster pass, so it costs in proportion to what casts: forests, not a lightmapped level.\n */\n shadowCascades?: 1 | 2 | 3 | 4;\n};\nexport type PointOptions = {\n /**\n * Luminous POWER in lumens — the same physical scale as the sun's lux and `environmentIntensity`,\n * so a light keeps its look when the scene's exposure changes. A candle is ~12 lm, a bare 60 W\n * bulb ~800, a car headlight ~1500, a fireball millions. Default 1000.\n */\n intensity?: number;\n color?: ColorInput;\n /**\n * Metres of influence — past it the light contributes nothing. This is the performance knob:\n * overlapping point lights are the expensive case, so keep it as small as the look allows.\n * Default 10.\n */\n range?: number;\n /** Point-light shadows are a cubemap render per light; off by default. */\n castShadows?: boolean;\n /**\n * Whether `lecodes lightmap bake` bakes this light into the level's lightmap. A baked lamp lights the statics\n * from the atlas and the MOVERS from the level's light grid, and is held dark in real time while that grid is\n * loaded (without a grid it keeps lighting the movers live); a light\n * that must reach the statics live too — a flicker, a lamp the player can shoot out, a muzzle flash —\n * says `baked: false`: it is kept out of the bake and put on the statics' light channel. Default true.\n */\n baked?: boolean;\n /**\n * THE BAKE'S SHAPE of this lamp: `[width, height]` in metres = an AREA light - a rectangle in the light's local XZ\n * plane, emitting along its local -Y (down, for an unrotated node) with the same lumens: a ceiling panel. The bake\n * lights from the whole rectangle (soft shadows, light from where the panel is and not from a point inside the\n * fixture). Real time it is still the point light above. Ignored with `baked: false`.\n */\n bakeArea?: readonly [number, number];\n};\nexport type SpotOptions = {\n /**\n * Luminous power in lumens, as a point light's. The cone does not change the brightness: widen it and the\n * same lumens light a larger patch at the same level. On its axis a spot is 4x brighter than a point light of\n * the same lumens (its light is not spread over the whole sphere). Default 1000.\n */\n intensity?: number;\n color?: ColorInput;\n /** Metres of influence along the cone, the performance knob as for a point light. Default 10. */\n range?: number;\n /** The cone's full angle in degrees, up to 180: past it the light contributes nothing. Default 45. */\n angle?: number;\n /** The full angle in degrees of the cone's fully lit core; the light fades from it out to `angle`. Default 0.75 x `angle`. */\n innerAngle?: number;\n /** A spot's shadow is one 2D shadow map (a point light's is a cubemap); off by default. */\n castShadows?: boolean;\n};\nexport declare class Light extends Node {\n private _intensity;\n /** Tween `intensity` / `color` (a flash, a sunrise) and the transform — see {@link Node.animateTo}. */\n animateTo(props: LightTweenProps & TweenMeta): Animation;\n animateFrom(props: LightTweenProps & TweenMeta): Animation;\n /** The most recently created sun. */\n static lastSun: Light | null;\n _shadowDistance: number;\n _shadowCascades: number;\n /** A directional sun light. */\n static sun(options?: SunOptions): Light;\n /**\n * A point light — a lamp, a muzzle flash, a fireball. Position it like any node.\n *\n * Feature-detected: hosts that predate it create the node and light nothing, which keeps a scene\n * that adds atmosphere on top of its sun renderable everywhere. Check `Light.supportsPoint`\n * before making one carry the scene.\n */\n static point(options?: PointOptions): Light;\n /** Whether this host can create point lights at all. */\n static get supportsPoint(): boolean;\n _innerAngle: number;\n /**\n * A spot light — a flashlight, a headlight, a stage light. It shines along the node's forward (-Z): position\n * it like any node and aim it with `lookAt`. Real time only: the lightmap bake takes no spot lights, so a spot\n * lights the baked statics live too.\n *\n * Feature-detected like `Light.point`: on a host without it the node exists and lights nothing\n * (`Light.supportsSpot`).\n */\n static spot(options?: SpotOptions): Light;\n /** Whether this host can create spot lights. */\n static get supportsSpot(): boolean;\n /** A spot's full cone angle in degrees — live (a flashlight's focus). */\n get angle(): number;\n set angle(value: number);\n /** A spot's fully lit core, full angle in degrees — live. Setting `angle` scales it along. */\n get innerAngle(): number;\n set innerAngle(value: number);\n /** Live intensity (sun: lux, point / spot: lumens) — animate a flash without rebuilding the light. */\n get intensity(): number;\n set intensity(value: number);\n _holdDark(dark: boolean): void;\n destroy(): void;\n set color(value: ColorInput);\n get color(): ColorInput;\n /** Sun direction as created (the engine keeps it; a settings menu rebuilds a sun from it). */\n get direction(): [number, number, number];\n /** Sun shadow options as created — creation-time in the engine, so a change means a new sun. */\n get shadowsQuality(): number;\n get shadowDistance(): number;\n}\n","types/gl/Lightmap.d.ts":"import { Node } from \"./Node\";\nimport type { Scene } from \"./Scene\";\nexport type LightmapLoadOptions = {\n /** A DEBUG multiplier on the atlas' lux (default 1): the atlas is physical, so this is a knob for looking,\n * not a look. */\n lightScale?: number;\n /** The level's own radiance of emission 1.0 for the BAKE (cd / m², `BakeConfig.emissiveNits`): an imported pack's\n * emissive values are tuned for a look, not for light - this is where the level says how much its panels really give.\n * The CLI's `--emissive-nits` wins over it; without either the camera's exposure decides. */\n emissiveNits?: number;\n /** `false` = the emissive surfaces light NOTHING in the bake (the level is lit by its lamps, the panels are decoration)\n * while `emissiveNits` still says how bright their glow is drawn. Default true. */\n emissiveBake?: boolean;\n /** FOR THE BAKE: materials that let light THROUGH them, by their glTF name (`\"name*\"` = every name with that start):\n * the share of a shadow ray that passes, tinted by the material's base colour x map - an awning's warm, patterned light\n * on the sand. The surface itself stays opaque: baked, drawn as before, a real-time shadow caster.\n * A number = the share that goes STRAIGHT through (the gaps of a weave: it draws the map's picture on the ground);\n * `{ through, diffuse }` adds the share the fibres SCATTER - the cloth's underside glows like a matte panel and lights\n * what is under it by the solid angle it fills, with no picture. Dense canvas: `{ through: 0.08, diffuse: 0.25 }`. */\n transmit?: Record<string, LightmapTransmit>;\n};\n/** one `transmit` entry (LightmapLoadOptions.transmit): the straight share, or both shares */\nexport type LightmapTransmit = number | {\n through?: number;\n diffuse?: number;\n};\nexport type LightmapInfo = {\n size: number;\n texel: number;\n /** Atlas pages the bake took (`light` / `aux` list them in order). */\n pages: number;\n /** keys applied / keys in the file / registered statics without a rect */\n applied: number;\n total: number;\n missing: string[];\n};\nexport type LightmapFiles = {\n data: string;\n /** The irradiance atlas — one page, or every page in order for a bake that took several. */\n light: string | string[];\n /** The aux atlas (sun / sky visibility + light direction), pages like `light`. */\n aux: string | string[];\n /** DEBUG: the direct-light-only pages a `--split` bake wrote (`<stem>-direct[_n].ktx2`), for the \"direct\" view. */\n direct?: string | string[];\n /** DEBUG: the bounce-only pages of a `--split` bake (`<stem>-indirect[_n].ktx2`), for the \"indirect\" view. */\n indirect?: string | string[];\n /** The reflection probes (`<stem>-probes.ktx2`), when the bake placed some (`lecodes lightmap bake --probe-spacing`). */\n probes?: string;\n /** THE LIGHT GRID for movers (`<stem>.lgrid`, `lecodes lightmap bake --volume`): the baked ambient light of every\n * place a mover can be. Absent = movers keep the scene's IBL. */\n volume?: string;\n};\n/** The lightmap material's data views (`Lightmap.debug`); \"direct\" / \"indirect\" bind a `--split` bake's pages instead. */\nexport type LightmapDebugMode = \"off\" | \"irradiance\" | \"albedo\" | \"normal\" | \"shadingNormal\" | \"share\" | \"skyVis\" | \"atlas\" | \"direction\" | \"lux\" | \"relief\" | \"direct\" | \"indirect\" | \"probe\" | \"probeMap\" | \"skyPath\" | \"probePath\";\nexport type LightmapDebugParams = {\n /** `lux`: the false-colour ramp's log10 range (default 0..5, i.e. 1 lux .. 100 000). */\n luxRange?: [number, number];\n};\n/** What `Lightmap.probe` answers: the baked texel under a screen point. */\nexport type LightmapProbe = {\n key: string;\n entity: number;\n node: string;\n material: string;\n page: number;\n /** The texel's column / row on its page. */\n texel: [number, number];\n uv1: [number, number];\n world: [number, number, number];\n distance: number;\n};\nexport declare class Lightmap {\n /** True while `lecodes lightmap bake` runs the app — skip menus and build the scene straight away. */\n static get baking(): boolean;\n private static entries;\n private static ordinals;\n private static warned;\n /** The bake bound last (`load`): what `probe` reads rects from. */\n private static bound;\n /** Register static geometry — a Model, a Mesh, or any node whose subtree holds them. Statics are\n * both receivers and occluders in the bake. `key` names the entry in the .bake (default:\n * the node's name + a running number, `container#3`); pass one when names are not stable. */\n static add(node: Node, key?: string): Node;\n private static next;\n private static movers;\n private static volumeOn;\n /** A MOVER takes its ambient light from the level's baked LIGHT GRID (`env.lightmap.volume`) at the place it is at,\n * every frame — whatever its shader: the standard glTF one or a custom lit material. Every Model / Mesh under `node`\n * is marked (a character, a weapon with its parts). A scene file does this itself for every node a Physics aspect or\n * a CharacterController moves; call it for what CODE spawns — an enemy, a pickup, a projectile. `on = false` hands\n * the subtree back to the scene's IBL. Safe before the level's bake has loaded. */\n static track(node: Node, on?: boolean): void;\n private static loadVolume;\n /** Forget every registration (a scene rebuild). */\n static clear(): void;\n /** THE MOVERS' SUN SHADOWS ON THE BAKED STATICS (a bot, a barrel, the player's rifle darkening the ground under\n * it): the lightmap shader reads the real-time shadow map and the bake's sun map for it, per pixel. Off, a baked\n * surface takes no real-time shadow at all — the cheapest lighting tier (some 4 ms of a 16 ms 720p frame on an\n * integrated GPU, the yard 2026-09-26); a mover still shades ITSELF and the other movers. Live: it rebinds the\n * level's material instances at once. */\n static get moverShadows(): boolean;\n static set moverShadows(on: boolean);\n private static _moverShadows;\n /** The loaded bake's sun (TO the sun ×3, its illuminance rgb, the sun map's levels), null without a sun map. */\n private static sunArgs;\n private static applySun;\n /** Apply a bake — or, under `lecodes lightmap bake`, run it. Resolves to null when nothing was\n * applied (no bake yet, a host without the feature, bake mode). */\n private static scene;\n static load(scene: Scene, files: LightmapFiles, options?: LightmapLoadOptions): Promise<LightmapInfo | null>;\n /** The bake's `<key>#k` instances by their base key: the parts of a GLB unwrapped in groups (k = extras.lightmapGroup). */\n private static groupsOf;\n /** Switch every lightmapped surface to a DATA view (or back with `\"off\"` / 0). Level-wide, instant —\n * except \"direct\" / \"indirect\", which load that page set the first time (a `--split` bake listed in the scene). */\n static debug(mode: LightmapDebugMode | number, params?: LightmapDebugParams): void;\n /** Bind another page set of the bound bake to every surface (the \"direct\" / \"indirect\" views). */\n private static show;\n private static balls;\n /** DEBUG: a mirror ball at every reflection probe of the bound bake (`on`), or none (`off`) — a ball reflects the\n * probes around its point unoccluded (at a probe's own position that is the probe itself), so a probe inside a\n * wall, a black one or a leak across a wall shows at a glance. Metallic, roughness 0; view \"probe\" shows the\n * probes alone. */\n static debugProbes(on: boolean, radius?: number): number;\n /** The view names in `lightmapDebug`'s order — for a knob that cycles them. */\n static get debugModes(): readonly LightmapDebugMode[];\n /** The baked texel under a screen point (logical px): its instance key, page and texel column / row,\n * so the value can be looked up in the bake's debug layers (`lecodes lightmap inspect`). null when\n * nothing baked is under the point or the host has no triangle pick. */\n static probe(screenX: number, screenY: number): LightmapProbe | null;\n /** A material's colour uniform as \"#rrggbbaa\" (the float4 uniform path sets its alpha); white without one. */\n private static colorUniform;\n /** The lightmap material for a static Mesh, from whatever lit material it carried (colour, map, roughness, metallic). */\n private static meshMaterial;\n private static bake;\n}\n","types/gl/Material.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type FetchResponse } from \"../runtime/fetch\";\nimport { Texture } from \"./Texture\";\nimport type { Canvas } from \"../canvas/Canvas\";\ntype UniformValue = string | Texture | number | boolean | number[] | Float32Array | null;\nexport type MaterialColorOptions = {\n color?: ColorInput;\n map?: Texture | Canvas | null;\n};\n/** How a stencil test / write on a material compares and what it writes. `test` runs against the\n * scene's stencil buffer (`Scene.stencil` must be on); the ops say what the buffer gets when the\n * fragment passes / fails the stencil test / fails the depth test (`replace` writes `ref`). */\nexport type StencilTest = \"always\" | \"never\" | \"less\" | \"lessEqual\" | \"greater\" | \"greaterEqual\" | \"equal\" | \"notEqual\";\nexport type StencilOp = \"keep\" | \"zero\" | \"replace\" | \"increment\" | \"decrement\" | \"invert\";\nexport type MaterialStencil = {\n /** Write the stencil buffer at all. Default `false`. */\n write?: boolean;\n /** The reference value, 0..255. Default 0. */\n ref?: number;\n /** Default `\"always\"`. */\n test?: StencilTest;\n onPass?: StencilOp;\n onFail?: StencilOp;\n onDepthFail?: StencilOp;\n readMask?: number;\n writeMask?: number;\n};\n/** Render state a material instance can override at run time (Filament keeps the defaults in the\n * shader package; these are per-instance overrides on top). */\nexport type MaterialStateOptions = {\n /** Test against the scene's depth buffer. `false` draws over everything already drawn — an\n * editor gizmo, a marker that must never hide behind a wall. Pair it with a high\n * `Mesh.renderPriority` so nothing drawn later covers it. Default `true`. */\n depthTest?: boolean;\n /** Write to the depth buffer. Leave it on for something drawn over the scene whose own parts must\n * still occlude each other (a gizmo's cone in front of its shaft). Unset = the shader's default\n * (on for opaque, off for a blended one). */\n depthWrite?: boolean;\n /** Draw both faces (no back-face culling): a plane seen from behind, a ribbon, cloth, a flat\n * marker. Default `false` = the shader's culling (back faces dropped). */\n doubleSided?: boolean;\n /** A stencil test / write for this material — see `MaterialStencil`. The selection-outline\n * recipe: the object writes `{ write: true, ref: 1, onPass: \"replace\" }`, and a slightly larger\n * copy of it draws with `{ test: \"notEqual\", ref: 1 }` + `depthTest: false` in `renderPriority` 7. */\n stencil?: MaterialStencil;\n};\n/** @deprecated the name before doubleSided / stencil joined it — the same type */\nexport type MaterialDepthOptions = MaterialStateOptions;\n/** `Material.unlit` options. */\nexport type UnlitMaterialOptions = MaterialColorOptions & MaterialStateOptions & {\n /** Alpha-blend this material instead of drawing it opaque. Opaque is the default: a blended draw\n * writes no depth, is sorted back-to-front and casts no shadow, which is rarely what a flat\n * colour wants. Turn it on for anything that must show what is behind it — a glass pane, a\n * fading marker, a sprite whose texture has cut-out alpha. Only then does `color`'s own alpha\n * (`\"#ffffff80\"`) mean anything; the opaque material has no alpha channel at all. */\n transparent?: boolean;\n};\n/** `Material.decal` options — the projected-decal material a `DecalSet` draws with. */\nexport type DecalMaterialOptions = {\n /** The atlas (a `DecalSet`'s `sheet` cuts it into cells). */\n map?: Texture;\n /** A tangent-space normal atlas (same cell grid; +X = the image's right, +Y = its top; LINEAR —\n * `Texture.fromPixels(…, { srgb: false })`). Turns the decal into a RELIEF decal: instead of\n * painting a colour it bends the surface's lighting, so a footprint or a dent shows on any\n * surface without a colour of its own. With `map` too, the colour multiplies in (a crater\n * darkens by the map's alpha). The sun term applies in shadow as well (no shadow read). */\n normalMap?: Texture;\n /** Relief strength — the normal map's xy scale. Default 1. */\n bump?: number;\n /** Soft fraction (0..1) of the box's half depth at both ends. Default 0.3. */\n edge?: number;\n /** Cosine of the surface angle past which the decal fades (0.3 ≈ 72°); 0 = project onto\n * anything. Default 0.3. */\n angleFade?: number;\n /** HDR boost of the image (0 = none). */\n emissive?: number;\n};\n/** `Material.particles` options — the default point-sprite material for particle systems. */\nexport type ParticlesMaterialOptions = {\n /** Sprite texture — a single image or a flipbook sheet of frames. Unset = soft round dot. */\n map?: Texture | null;\n /** Flipbook grid: `N` = an N×N sheet, `[cols, rows]` = a non-square one. Frames run\n * left-to-right, top-to-bottom; drive the index via `particles.frame`. Default 1. */\n sheet?: number | [number, number];\n /** Extra brightness multiplier for a glow look (0 = off). */\n emissive?: number;\n /** (`render` quad / stretch) a second sheet on the same grid, ADDED as `emissiveMap × emissiveColor`\n * — keyed by `map`'s alpha, not tinted by the particle colour. A fireball = a smoke `map` whose\n * colour curve goes dark + a fire `emissiveMap` that keeps glowing while alpha lasts. */\n emissiveMap?: Texture | null;\n /** Multiplier for `emissiveMap`; an `[r, g, b]` array may exceed 1 (HDR glow). Default 0 (off). */\n emissiveColor?: ColorInput;\n /** (`render` quad / stretch) crossfade each flipbook frame into the next by the fractional frame\n * index instead of snapping — smooth sheet playback at any frame rate. Default false. */\n frameBlend?: boolean;\n /** Compositing: `\"alpha\"` (default — smoke, dust) or `\"add\"` (fire, sparks, magic). */\n blend?: \"alpha\" | \"add\";\n /** Soft radial falloff toward the sprite edge. Defaults to true without a map, false with one. */\n soft?: boolean;\n /** Soft particles: fade each sprite out over this many metres as it cuts into the scene geometry\n * behind it (Unity's \"Soft Particles Factor\"), so smoke and dust no longer slice through the\n * ground and walls with a hard edge. 0 = off (default). Reads the scene's depth buffer, which the\n * engine keeps bound while any soft system is on screen — the extra depth pass is only paid then.\n * Filament hosts (desktop / web / Android / Apple); web-lite draws such sprites unfaded. */\n depthFade?: number;\n /** How each particle is drawn: `'point'` (default — GPU point sprites, cheapest), `'quad'`\n * (real camera-facing quads — no driver size cap, geometric rotation), or `'stretch'`\n * (quads stretched along velocity — sparks, rain, speed streaks). `'ribbon'` is what `Trail`\n * uses internally. */\n render?: \"point\" | \"quad\" | \"stretch\" | \"ribbon\";\n /** (`render: 'stretch'`) extra sprite length in world units per unit of speed:\n * length = size + stretch·|velocity|. Default 0.05. */\n stretch?: number;\n};\n/** `Material.lit` options — PBR scalars on top of the color/map pair. */\nexport type LitMaterialOptions = MaterialColorOptions & MaterialStateOptions & {\n /** Perceptual roughness, 0 (mirror) … 1 (matte). Unset = the shader's default. */\n roughness?: number;\n /** Metallic factor, 0 (dielectric) … 1 (metal). Unset = the shader's default. */\n metallic?: number;\n};\nexport declare class Material {\n readonly shader: FetchResponse | \"unknown\";\n readonly uniforms: Record<string, UniformValue>;\n private _colorKey;\n constructor(shader: FetchResponse | Handle | number);\n /** Set a uniform (chainable). */\n set(key: string, value: UniformValue): this;\n set color(c: ColorInput);\n /** Depth test against the scene (write-only; see `MaterialDepthOptions`). A host that predates\n * the call leaves the material as the shader has it. */\n set depthTest(on: boolean);\n /** Depth write (write-only; see `MaterialStateOptions`). */\n set depthWrite(on: boolean);\n /** Both faces drawn (write-only; see `MaterialStateOptions`). */\n set doubleSided(on: boolean);\n /** The stencil test / write (write-only; `null` = back to none). See `MaterialStencil`. */\n set stencil(s: MaterialStencil | null);\n set map(value: Texture | Canvas | null);\n /** The material an instance handle is of; a host that carries none under `name` is an error naming it. */\n private static _builtin;\n /** PBR lit material. */\n static lit(options?: LitMaterialOptions): Material;\n /** Unlit (flat) material — opaque unless `transparent` asks for alpha blending. */\n static unlit(options?: UnlitMaterialOptions): Material;\n /** Default particle material — camera-facing point sprites with tint/opacity/rotation/flipbook\n * driven by the particle curves. Uniforms all default to 0 on a fresh instance, so every look\n * knob is primed here; JS writes after construction override them. */\n static particles(options?: ParticlesMaterialOptions): Material;\n /** Projected-decal material (`DecalSet`): samples the atlas where the decal's box meets the opaque\n * scene behind it. Blended, no depth write, no shadows — the engine keeps the scene depth bound\n * while a set with live decals is on screen. */\n static decal(options?: DecalMaterialOptions): Material;\n /** Material that samples a VideoPlayer's texture. */\n static video(map?: Texture): Material;\n /** The lightmap material (engines/bake): a lit PBR material whose whole DIFFUSE light is the\n * baked irradiance atlas on UV1 (`lightmapLight`, lux) — the real-time sun, lamps and diffuse IBL do not\n * touch it; the specular IBL stays, occluded by the baked sky visibility. Models take it through\n * `Model.load(…, { lightmap: true })`; a static Mesh gets one from here. Parameters use gltfio's names\n * (`baseColorFactor`, `baseColorMap`, `roughnessFactor`, `metallicFactor`) plus `lightmapLight`, `lightmapAux`,\n * `lightmapST`, `lightScale` (the level-wide value `Lightmap.load` sets) and the debug view knobs. */\n static lightmap(): Material;\n /** `Material.lightmap()`'s masked twin (`blending: masked`, same shader and parameters): what the engine\n * gives a lightmapped model's alpha-MASK materials. The cutoff comes from the glTF material. */\n static lightmapMasked(): Material;\n /** THE LIGHTMAP SHADER TIER, engine-wide: `\"full\"` = the target's own blob (desktop: the bicubic atlas fetch, eight\n * probe corners, the sun's highlight on metal), `\"lite\"` = the blob the phones ship (bilinear fetch, one probe\n * corner, no sun highlight; the movers' shadows on the statics stay) — on an integrated GPU some 30 % less per\n * pixel on a baked level, the picture a phone shows. Read when a lightmap material is FIRST made, which\n * `Model.load({ lightmap })` does once per world: set it BEFORE the level loads (a graphics preset applied at\n * boot, like `Texture.maxSize`); a change afterwards takes the next level. A host without the lite material\n * (a phone: its own blob is that shader already) takes the full one. */\n static lightmapShading: \"full\" | \"lite\";\n /** The lite tier's instance, or — said once — that this host has none and the full shader is used. */\n private static _liteTier;\n private static _liteWarned;\n /** The terrain splat material (docs/terrain-plan.md §1.5): four albedo (+ normal-map) layers blended by\n * a control map on the terrain's own grid, per-layer `tiling` (metres per repeat) / `roughness` /\n * `normalScale` / `triplanar`. `Terrain` builds and owns one per terrain; the uniforms are primed here so an\n * unset layer is white. Lit real-time; a BAKED terrain takes `Material.terrainLightmap()`. */\n static terrain(): Material;\n /** `Material.terrain()` for a BAKED terrain (terrain-lightmap.mat): the same layers and uniforms, shaded like\n * `Material.lightmap()` — the whole diffuse light is the baked atlas on the terrain's UV1 (one rect), which\n * `Lightmap.load` binds. A scene file's `terrain:` node that is a lightmap static is built with it; without a\n * bound bake it draws black, like any lightmapped static. No reflection probes (the sampler budget): it reflects the\n * sky through the baked sky visibility. */\n static terrainLightmap(): Material;\n private static _lmTemplate;\n private static _lmMaskedTemplate;\n /** The FOLIAGE tier (`Model.load(…, { foliage: true })`, see `Foliage`): an unlit shader with its own cheap\n * lighting plus a vertex shader that sways in the wind, bends away from benders and thins out with distance,\n * and a per-copy tint. glTF parameters like `Material.lightmap()` plus `wind` / `sway` / `fade` / `benders`,\n * which the engine writes itself. Not baked by the rewritten bake yet. */\n static foliage(): Material;\n /** `Material.foliage()`'s masked twin (`blending: masked`): what the engine gives a foliage model's alpha-MASK\n * materials — the cards. */\n static foliageMasked(): Material;\n /** the glTF-side identity values every provider-handed material starts from */\n private static _glbDefaults;\n private static _lightmapDefaults;\n private static _folTemplate;\n static _foliageMaskedTemplate(): Material | null;\n private static _folMaskedTemplate;\n private static _glbTemplate;\n /** Shadow-catcher material (transparent except where shadows fall). */\n static shadow(color?: ColorInput): Material;\n /** Load a custom compiled shader (.mat URL) as a material. */\n static load(url: string): Promise<Material>;\n}\nexport {};\n","types/gl/Mesh.d.ts":"import { type Vec3Like } from \"../math/vec\";\nimport { Geometry, type CapsuleOptions, type CylinderOptions, type PlaneOptions, type SphereOptions } from \"./Geometry\";\nimport { Material } from \"./Material\";\nimport { Node } from \"./Node\";\n/** Common transform/render options every primitive factory accepts. */\nexport type MeshOptions = {\n material?: Material;\n position?: Vec3Like;\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n name?: string;\n castShadows?: boolean;\n receiveShadows?: boolean;\n /** Coarse draw order, 0 (first) … 7 (last); default 4. See `Mesh.renderPriority`. */\n renderPriority?: number;\n};\nexport declare class Mesh extends Node {\n private _geometry?;\n constructor(geometry?: Geometry, material?: Material);\n get geometry(): Geometry | undefined;\n /** Replace the geometry in place — the node, its transform and its material stay, the vertex and\n * index buffers are rebuilt. What an editor overlay or a debug drawer redraws with. */\n setGeometry(geometry: Geometry): this;\n private _renderPriority?;\n private _culling?;\n private _castShadows?;\n private _receiveShadows?;\n /** A Mesh always carries a material (slot 0) — see Node.setMaterial for the slot API. */\n get material(): Material;\n set material(m: Material);\n set culling(v: boolean);\n /** Coarse draw order within the frame: 0 draws first, 7 last, 4 is the default (Filament's\n * renderable priority; within one priority opaque draws sort front-to-back, blended back-to-front).\n * Something drawn over the scene with `Material.depthTest = false` goes in 7, so nothing drawn\n * after it can cover it. Write-only; a host that predates the call ignores it. */\n set renderPriority(v: number);\n private static _warnedPriority;\n set castShadows(v: boolean);\n set receiveShadows(v: boolean);\n static box(options?: MeshOptions & {\n size?: Vec3Like | number;\n }): Mesh;\n static sphere(options?: MeshOptions & SphereOptions): Mesh;\n static cylinder(options?: MeshOptions & CylinderOptions): Mesh;\n /** A capsule along Y (`radius`, `length` between the cap centres) — a character's or a collider's shape in one mesh. */\n static capsule(options?: MeshOptions & CapsuleOptions): Mesh;\n static plane(options?: MeshOptions & PlaneOptions): Mesh;\n /** Wrap a custom Geometry. */\n static from(geometry: Geometry, options?: MeshOptions): Mesh;\n}\n","types/gl/Model.d.ts":"import { type FetchResponse } from \"../runtime/fetch\";\nimport { Node } from \"./Node\";\nimport { Animator, type LodMode } from \"./animation/Animator\";\n/** One polygon under a screen point — what `Model.pickTriangle` returns. `bones` are the vertex's raw\n * JOINTS_0 / WEIGHTS_0 pairs (weight > 0; empty = unweighted), `bind` its position in mesh space,\n * `world` its skinned position this frame. */\nexport interface TrianglePick {\n /** the Model's root entity, and the mesh node's own entity (0 when the host has no entity for it) */\n entity: number;\n node: number;\n nodeName: string;\n mesh: string;\n primitive: number;\n material: string;\n /** the node's lightmap group (scene-file extras), when it has one */\n lightmapGroup?: number;\n /** triangle index within the primitive (index-buffer order), and whether the ray came from behind */\n triangle: number;\n backface: boolean;\n distance: number;\n point: [number, number, number];\n bary: [number, number, number];\n /** the lightmap uv (TEXCOORD_1) at the hit, when the primitive carries one */\n uv1?: [number, number];\n skin: string;\n vertices: {\n index: number;\n bind: [number, number, number];\n world: [number, number, number];\n bones: {\n name: string;\n weight: number;\n }[];\n }[];\n}\nexport declare class Model extends Node {\n /** The model's Animator — always present, its clip table = the GLB's embedded clips. Configure\n * more (external clips, blend spaces, layers) with `model.aspect(Animator, {...})`. */\n readonly anim: Animator;\n constructor(internalId: number | Handle);\n /** Does this model cast a real-time shadow? Unlike Mesh (one renderable) a GLB is a whole\n * hierarchy, so the flag goes to EVERY renderable of the instance. A first-person viewmodel —\n * arms, weapon, attachments — sets it false: it lives in front of the camera and its shadow\n * is never wanted. */\n get castShadows(): boolean;\n set castShadows(v: boolean);\n /** Is this model lit by other casters' shadows? Same instance-wide reach as castShadows. */\n get receiveShadows(): boolean;\n set receiveShadows(v: boolean);\n /** Frustum culling for the whole instance: a model the camera cannot see skips the draw and the\n * shadow pass. ON by default where the host keeps a skinned mesh's bounds honest — the engine refits\n * them to the joints every frame, so a walking, kneeling or ragdolled body is never culled while on\n * screen (`_creator.skinnedCullingSupported`); OFF (always draw) on hosts without that, where\n * Filament would cull an animated body by its bind-pose box. `false` = always draw (a skybox-sized\n * mesh, a debugging aid); `true` forces it on regardless of the host. */\n get culling(): boolean;\n set culling(v: boolean);\n /** Level of detail (docs/lod-plan.md). `'auto'` (default): the engine shows the `_LOD<n>` mesh level\n * that fits the model's size on screen (`lecodes assets doctor --lod` makes them) and scales the\n * animation rate with it; a number 0–3 pins that level for both — `0` = always full detail (a hero,\n * a showcase), `2`/`3` = always cheap (a crowd filler). `model.anim.lod = 'full'` keeps the animation\n * exact while the mesh still switches. No-op on hosts without the LOD pass. */\n get lod(): LodMode;\n set lod(v: LodMode);\n private static _cullDefault;\n /** DEBUG: the closest polygon of this model under a screen point (logical px — `Input.mouse.position`,\n * a touch event's clientX/Y), tested against the CPU-skinned CURRENT pose, both faces. Names the\n * triangle, its three vertices (bind + skinned positions) and their raw bone weights, so a stretched\n * or misbound polygon can be traced to its binding. One full CPU skin of the model per call: click-rate\n * only. null = miss, or a host without the pick (desktop today). */\n pickTriangle(screenX: number, screenY: number): TrianglePick | null;\n /** Duplicate this model — a deep copy of the GLB (meshes, skeleton, animation clips), attached to\n * the same parent and scene and sharing this model's current transform. The clone has its own\n * independent animation state (reach it via clone.anim). Mirrors this model's culling flag. */\n clone(): Model;\n /** Load a GLB model. Returns its root as a Model; play its baked clips via model.anim. */\n static load(source: string | FetchResponse, options?: {\n /** Frustum culling — see `culling` (default: on where the host refits skinned bounds, else off). */\n culling?: boolean;\n onProgress?: (p: {\n loaded: number;\n total?: number;\n }) => void;\n /** Baked lighting (engines/bake). `true` = a STATIC: loads through the lightmap material so\n * `Lightmap.load` can bind its atlas rect (the GLB needs TEXCOORD_1 — `lecodes assets doctor\n * --lightmap-uv`) and takes nothing from the real-time lights once the bake applies. Omitted / `false` =\n * the standard shader, lit real-time (movers). Hosts without lightmap support ignore it. */\n lightmap?: boolean;\n /** Vegetation: load through the FOLIAGE tier (see `Foliage`) — wind, touch bending, distance fade,\n * per-copy tint. Hosts without the tier fall back to the standard shader. */\n foliage?: boolean;\n }): Promise<Model>;\n}\n","types/gl/nav/NavAgent.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { NavCrowd } from \"./NavMesh\";\nimport type { Node } from \"../Node\";\nexport type NavAgentState = \"idle\" | \"moving\" | \"arrived\" | \"blocked\" | \"offmesh\";\nexport type NavAgentAvoidance = \"off\" | \"low\" | \"medium\" | \"high\";\nexport type NavAgentDrive = \"position\" | \"controller\";\nexport type NavAgentEvents = {\n /** Reached the target (within `stopDistance`). */\n arrive: () => void;\n /** The target cannot be reached — the agent stopped at the closest point (or nowhere near). */\n blocked: () => void;\n};\nexport declare class NavAgent extends Aspect<\"agent\", Node, NavAgentEvents> {\n static readonly aspect = \"agent\";\n /** The crowd advances first, then every agent applies its slot. */\n static after: (typeof NavCrowd)[];\n static fields: FieldMeta<NavAgent>;\n private _radius;\n private _height;\n private _speed;\n private _acceleration;\n private _avoidance;\n private _separation;\n private _include;\n private _exclude;\n /** deg/s the node turns toward its velocity; 0 = never touch the rotation. */\n turnSpeed: number;\n /** How the node follows its slot. */\n drive: NavAgentDrive;\n /** Reached = within this many metres (along the corridor) of the target. */\n stopDistance: number;\n /** Agent radius (metres). Defaults to the navmesh's. */\n get radius(): number;\n set radius(v: number);\n get height(): number;\n set height(v: number);\n /** Top speed (m/s). */\n get speed(): number;\n set speed(v: number);\n get acceleration(): number;\n set acceleration(v: number);\n /** Local (agent-vs-agent) avoidance quality. */\n get avoidance(): NavAgentAvoidance;\n set avoidance(v: NavAgentAvoidance);\n /** Separation force weight (0 = none). */\n get separation(): number;\n set separation(v: number);\n /** Area names this agent may walk (default: all). */\n get include(): string[] | undefined;\n set include(v: string[] | undefined);\n /** Area names this agent never enters. */\n get exclude(): string[] | undefined;\n set exclude(v: string[] | undefined);\n state: NavAgentState;\n /** The current velocity after avoidance (m/s). */\n readonly velocity: Vec3;\n /** The velocity the corridor asked for, before avoidance. */\n readonly desiredVelocity: Vec3;\n /** Metres left along the corridor (-1 = no target). */\n remainingDistance: number;\n /** Where the agent is going, or null. */\n get target(): Vec3 | null;\n get hasPath(): boolean;\n private _crowd;\n private _slot;\n private _target;\n /** velocity-driven (`move`) rather than target-driven */\n private _steering;\n private _dirty;\n private _faceX;\n private _faceZ;\n private _retryAt;\n private _lastSeen;\n private _still;\n private _near;\n private _slow;\n onAttach(): void;\n onReconfigure(): void;\n onDetach(): void;\n /** Walk to a point. False = no walkable polygon near it (or no navmesh) — the current target stays. */\n goTo(target: Vec3Like): boolean;\n /** Drop the target and decelerate to a stop. */\n stop(): void;\n /**\n * Steer by velocity instead of a target — a player on WASD, a scripted push: the crowd keeps\n * the node on the mesh and avoids the other agents, no path and no arrival. Call it every fixed\n * step (the last velocity holds until the next call); `move(0, 0)` stops. Cancels `goTo`.\n * False = no navmesh / off the mesh.\n */\n move(vx: number, vz: number): boolean;\n /** Teleport (a spawn, a respawn). The target, if any, is kept. */\n warp(p: Vec3Like): void;\n private params;\n updateFixed(dt: number): void;\n private finish;\n private face;\n}\n","types/gl/nav/NavMesh.d.ts":"import { System } from \"../../core/Aspect\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\nimport type { Scene } from \"../Scene\";\nexport declare const NAV_AGENT: {\n readonly RADIUS: 0;\n readonly HEIGHT: 1;\n readonly MAX_SPEED: 2;\n readonly MAX_ACCELERATION: 3;\n readonly COLLISION_QUERY_RANGE: 4;\n readonly PATH_OPTIMIZATION_RANGE: 5;\n readonly SEPARATION_WEIGHT: 6;\n readonly AVOIDANCE: 7;\n readonly INCLUDE_FLAGS: 8;\n readonly EXCLUDE_FLAGS: 9;\n readonly ANTICIPATE_TURNS: 10;\n readonly OPTIMIZE_VIS: 11;\n readonly OPTIMIZE_TOPO: 12;\n readonly COUNT: 13;\n};\nexport declare const NAV_READ: {\n readonly POS_X: 0;\n readonly POS_Y: 1;\n readonly POS_Z: 2;\n readonly VEL_X: 3;\n readonly VEL_Y: 4;\n readonly VEL_Z: 5;\n readonly DVEL_X: 6;\n readonly DVEL_Y: 7;\n readonly DVEL_Z: 8;\n readonly STATE: 9;\n readonly TARGET_STATE: 10;\n readonly REMAINING: 11;\n readonly PARTIAL: 12;\n readonly STRIDE: 13;\n};\n/** The agent size a navmesh is built for (and the crowd's defaults). */\nexport type NavAgentSize = {\n /** metres — polygons are eroded by it. Default 0.4 */\n radius?: number;\n /** metres. Default 1.8 */\n height?: number;\n /** the highest step walked over, metres. Default 0.4 */\n climb?: number;\n /** the steepest walkable slope, degrees. Default 50 */\n slope?: number;\n};\nexport type NavMeshLoadOptions = {\n /** `asset('./assets/nav/<scene>.navmesh')` — what `lecodes navmesh bake` writes. */\n data: string;\n /** The agent size the bake uses (the file records it; the crowd reads it back). */\n agent?: NavAgentSize;\n /** Named areas → traversal cost (1 = plain ground). Ids are assigned in this order (1..15); the\n * bake stores the names, queries and agents refer to them (`include` / `exclude`, `cost`). */\n areas?: Record<string, number>;\n};\n/** The file header `lecodes navmesh bake` wrote. */\nexport type NavMeshInfo = {\n version: number;\n agent: {\n radius: number;\n height: number;\n climb: number;\n slope: number;\n };\n cell: number;\n cellHeight: number;\n tileSize: number;\n bounds: [[number, number, number], [number, number, number]];\n stats: {\n tiles: number;\n polys: number;\n verts: number;\n triangles: number;\n volumes: number;\n links: number;\n };\n meta: {\n scene?: string;\n areas?: Record<string, number>;\n costs?: Record<string, number>;\n [k: string]: unknown;\n } | null;\n};\n/** A straight path: the corners to walk, plus whether it stops short of the target. */\nexport type NavPath = Vec3[] & {\n partial: boolean;\n};\nexport type NavQueryOptions = {\n /** Only these areas (names). Default: every area. */\n include?: string[];\n /** Never these areas (names). */\n exclude?: string[];\n /** Search half-extents around each endpoint (how far off the mesh a point may be). Default [2, 4, 2]. */\n extents?: Vec3Like;\n};\nexport type NavRaycastHit = {\n hit: boolean;\n point: Vec3;\n normal: Vec3;\n};\n/** The crowd behind a scene's agents — a system `NavMesh.load` attaches to the scene so the whole\n * crowd advances once per fixed step, BEFORE every `NavAgent` applies its slot (`static after`). */\nexport declare class NavCrowd extends System<\"navCrowd\"> {\n static readonly aspect = \"navCrowd\";\n updateFixed(dt: number): void;\n onDetach(): void;\n}\nexport declare class NavMesh {\n /** True while `lecodes navmesh bake` runs the app — skip menus and build the level straight away. */\n static get baking(): boolean;\n /** The navmesh agents bind to (the last one loaded; one per world at a time). */\n static active: NavMesh | null;\n private static byScene;\n private static overrides;\n private static warned;\n private static baked;\n /** Leave a static body out of the bake (`nav: false` in a scene file). */\n static exclude(node: Node): void;\n /** A static body nobody may walk on (`nav: 'unwalkable'`): its footprint is cut out. */\n static unwalkable(node: Node): void;\n /** A static body's surface belongs to a named area (`navArea: 'road'`; names from `load`'s `areas`). */\n static area(node: Node, name: string): void;\n /** Forget every override (a scene rebuild). */\n static clear(): void;\n static of(scene: Scene): NavMesh | null;\n /** Load the level's navmesh — or, under `lecodes navmesh bake`, dump the collision geometry for\n * it. Resolves null when nothing was loaded (no bake yet, a host without navigation, bake mode). */\n static load(scene: Scene, opts: NavMeshLoadOptions): Promise<NavMesh | null>;\n readonly scene: Scene;\n readonly info: NavMeshInfo;\n /** The agent size the mesh was built for. */\n readonly agent: {\n radius: number;\n height: number;\n climb: number;\n slope: number;\n };\n /** Named areas → ids (from the bake; `load`'s `areas` when the file has none). */\n readonly areas: Record<string, number>;\n private _debug;\n private _seed;\n private _disposed;\n private constructor();\n private static areaIds;\n /** The include/exclude flag mask for a list of area names (undefined = every area). */\n flags(names?: string[]): number;\n private masks;\n /** Traversal cost of a named area (1 = plain ground; > 1 = avoided when a cheaper way exists). */\n cost(area: string, cost: number): void;\n /** The straight (string-pulled) path from → to. Empty when an endpoint is off the mesh;\n * `.partial` when the target is unreachable (the path ends at the closest polygon). */\n findPath(from: Vec3Like, to: Vec3Like, opts?: NavQueryOptions & {\n maxCorners?: number;\n }): NavPath;\n /** The closest point on the mesh (within `extents` of `p`), or null. */\n nearest(p: Vec3Like, opts?: NavQueryOptions): Vec3 | null;\n /** Can an agent walk straight from → to? `hit` = a wall in between (at `point`, facing `normal`). */\n raycast(from: Vec3Like, to: Vec3Like, opts?: NavQueryOptions): NavRaycastHit;\n /** A random reachable point — within walking distance `radius` of `center`, or anywhere on the\n * mesh. Deterministic: the sequence depends only on the calls made (a seeded generator). */\n randomPoint(center?: Vec3Like, radius?: number, opts?: NavQueryOptions): Vec3 | null;\n /** Draw the polygon mesh (a flat unlit surface 3 cm above the walkable area). */\n get debug(): boolean;\n set debug(on: boolean);\n /** Release the host handles (a scene teardown). Agents fall back to inert. */\n dispose(): void;\n private static bake;\n}\n","types/gl/Node.d.ts":"import { AspectHost } from \"../core/Aspect\";\nimport { Vec3, type Vec3Like } from \"../math/vec\";\nimport { Quat, type QuatLike } from \"../math/quat\";\nimport { Mat4, type Mat4Like } from \"../math/mat4\";\nimport type { Geometry } from \"./Geometry\";\nimport { Material } from \"./Material\";\nimport type { CompAxis, CompWriter } from \"../core/compWrite\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport type { Animation } from \"../animate/tween/Animation\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\n/** Animatable transform props of a 3D node: a value tweens from the current one, an ARRAY OF\n * VALUES is a keyframe list (`position: [[0,0,0], [0,2,0]]`). */\nexport type NodeTweenProps = {\n position?: Vec3Like | Vec3Like[];\n scale?: number | Vec3Like | (number | Vec3Like)[];\n quaternion?: QuatLike | QuatLike[];\n /** Degrees, YXZ; interpolated per axis without shortest-arc, so `[0, 720, 0]` spins twice. */\n eulerAngles?: Vec3Like | Vec3Like[];\n};\nexport type NodeEvents = {\n click: (ev: ClickEvent<Node | null>) => void;\n touchstart: (ev: TouchStartEvent<Node | null>) => void;\n /** AR anchors only (`scene.root` / `scene.createAnchor()`): the anchor began tracking. */\n track: () => void;\n /** AR anchors only: the anchor lost tracking. */\n untrack: () => void;\n /** A physics contact/trigger overlap began (the other body's node). Needs a Shape + Physics/Trigger. */\n enter: (other: Node) => void;\n /** A physics contact/trigger overlap ended. */\n exit: (other: Node) => void;\n};\nexport declare class Node extends AspectHost<NodeEvents> implements CompWriter {\n /** Native entity id. */\n get id(): number;\n /** AR anchors only — whether the anchor is currently being tracked. Kept in step with the\n * 'track' / 'untrack' events; `false` for any non-anchor node. */\n isTracked: boolean;\n private _matrix?;\n private _worldMatrix?;\n private _boneCache?;\n /** Materials assigned through setMaterial, by primitive slot (a Mesh fills slot 0 itself). */\n protected _materials?: Material[];\n constructor(internalId?: number | Handle);\n /** Geometry, if this node is a Mesh (used by physics auto-shape). Overridden by Mesh. */\n get geometry(): Geometry | undefined;\n get name(): string;\n set name(value: string);\n get visible(): boolean;\n set visible(value: boolean);\n private _sync;\n get matrix(): Mat4;\n set matrix(m: Mat4Like);\n get worldMatrix(): Mat4;\n set worldMatrix(m: Mat4Like);\n private _setOwnedPosition;\n private _setOwnedRotation;\n get position(): Vec3;\n set position(v: Vec3Like);\n get x(): number;\n set x(v: number);\n get y(): number;\n set y(v: number);\n get z(): number;\n set z(v: number);\n _writeComp(_prop: string, axis: CompAxis, v: number): void;\n get scale(): Vec3;\n set scale(v: Vec3Like | number);\n get quaternion(): Quat;\n set quaternion(v: QuatLike);\n /** Tween the transform to the given values — `node.animateTo({ position: [0, 2, 0], duration: 800,\n * easing: 'inOutCubic' })`; arrays of values are keyframes. Runs on the game clock (pauses with\n * the game) unless `clock: 'ui'`. Returns the {@link Animation} handle. Phase 1: plain nodes —\n * a physics-owned node (a body / character) is not routed through its engine object yet. */\n animateTo(props: NodeTweenProps & TweenMeta): Animation;\n /** Tween FROM the given values to the node's current transform (an entrance). */\n animateFrom(props: NodeTweenProps & TweenMeta): Animation;\n get eulerAngles(): Vec3;\n set eulerAngles(v: Vec3Like);\n get forward(): Vec3;\n get worldPosition(): Vec3;\n get worldScale(): Vec3;\n get worldQuaternion(): Quat;\n get worldEulerAngles(): Vec3;\n get parent(): Node | null;\n get children(): Node[];\n get childCount(): number;\n getChild(index: number): Node | null;\n /** Parent the given nodes under this one. */\n add(...children: Node[]): this;\n setParent(parent: Node | null, worldPositionStays?: boolean): this;\n traverse(callback: (node: Node) => void): void;\n /** The material assigned to slot 0 through this API (null before one is set — a GLB part's own\n * glTF material stays native-side). */\n get material(): Material | null;\n set material(m: Material);\n /** Replace the material of one primitive slot (`index` = the primitive's order in the glTF\n * mesh; a primitive-shape Mesh has one slot). */\n setMaterial(material: Material, index?: number): this;\n /** The material previously assigned to `index` (null when none was — see Mesh for the probe). */\n getMaterial(index?: number): Material | null;\n /** Find a descendant by name — bones of a loaded Model included (`hero.bone('RightHand').add(sword)`).\n * Same rule the Animator binds clips with: exact name first, then the part after the last `:` / `|`\n * (Mixamo `mixamorig:Hips` matches `Hips`); a skinned joint beats a plain node of the same name.\n * Cached per name; null if absent. */\n bone(name: string): Node | null;\n /** Orient the node so the given axis (default \"-z\", \"forward\") points at a world point. */\n lookAt(point: Vec3Like, mode?: \"z\" | \"-z\" | \"x\" | \"-x\" | \"y\" | \"-y\", ortho?: Vec3Like): this;\n addEventListener<K extends keyof NodeEvents>(channel: K, callback: NodeEvents[K]): void;\n /** Destroy this node and its whole subtree. Every aspect in the subtree is detached first (its\n * `onDetach` runs: physics bodies released, updaters unregistered, listeners dropped) — native\n * `destroyEntity` frees the entity tree but knows nothing about JS-side aspects, and a destroyed\n * node's `update()` must not keep ticking. Deepest nodes go first, then this one. */\n destroy(): void;\n}\n","types/gl/Noise.d.ts":"export declare class Noise {\n private readonly _id;\n constructor();\n /** Sample 2D noise. */\n get(x: number, y: number): number;\n /** Sample 3D noise. */\n get3d(x: number, y: number, z: number): number;\n private _frequency;\n get frequency(): number;\n set frequency(v: number);\n private _octaves;\n get octaves(): number;\n set octaves(v: number);\n private _fractalLacunarity;\n get fractalLacunarity(): number;\n set fractalLacunarity(v: number);\n private _fractalGain;\n get fractalGain(): number;\n set fractalGain(v: number);\n}\n","types/gl/Particles.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Vec3Like } from \"../math/vec\";\nimport type { Geometry } from \"./Geometry\";\nimport { Material, type ParticlesMaterialOptions } from \"./Material\";\nimport { Node } from \"./Node\";\ntype Range<T> = T | {\n min: T;\n max: T;\n};\nexport declare class CurveBuilder {\n private _kind;\n private _lo;\n private _hi;\n private _stops;\n constructor(base: Range<number>, mode: \"multiply\" | \"add\");\n /** Curve value at birth (t = 0). Must come before any other stop. */\n from(v: Range<number>): this;\n /** Curve value at `t` (0..1 of the particle's life). Stops must be added in ascending t order. */\n via(t: number, v: Range<number>): this;\n /** Curve value at death (t = 1). */\n to(v: Range<number>): this;\n /** The classic opacity envelope: rise over the first `fadeIn`, fall over the last `fadeOut`. */\n fade(fadeIn?: number, fadeOut?: number): this;\n /** The PARAM_CURVE record payload (sans slot): [kind, baseLo, baseHi, n, (t, lo, hi)×n]. */\n get _data(): Float32Array;\n}\nexport declare class ColorCurveBuilder {\n private _lo;\n private _hi;\n private _stops;\n constructor(base: Range<ColorInput>);\n /** Curve color at birth (t = 0). Must come first. The curve multiplies the base color. */\n from(c: Range<ColorInput>): this;\n /** Curve color at `t` (0..1 of the particle's life), in ascending t order. */\n via(t: number, c: Range<ColorInput>): this;\n /** Curve color at death (t = 1). */\n to(c: Range<ColorInput>): this;\n /** The COLOR_CURVE record payload: [baseLo rgba, baseHi rgba, n, (t, lo rgba, hi rgba)×n]. */\n get _data(): Float32Array;\n}\n/** A value curve over each particle's lifetime. Default mode `multiply` (the curve scales the\n * base); `add` offsets it instead. */\nexport declare const curve: (base?: Range<number>, mode?: \"multiply\" | \"add\") => CurveBuilder;\n/** A color curve over each particle's lifetime — always multiplies the base color. */\nexport declare const colorCurve: (base?: Range<ColorInput>) => ColorCurveBuilder;\nexport type ParticleValue = Range<number> | CurveBuilder | {\n _data: Float32Array;\n};\nexport type ParticleColor = ColorInput | {\n min: ColorInput;\n max: ColorInput;\n} | ColorCurveBuilder | {\n _data: Float32Array;\n};\ntype VelocityValue = {\n speed?: Range<number>;\n /** Cone half-angle in radians — jitter the launch direction uniformly within it. */\n spread?: number;\n /** Asymmetric jitter: two angles (u, v — the x/y components) in radians. */\n randomizeAngle?: {\n min: Vec3Like;\n max: Vec3Like;\n };\n} & ({\n from: Vec3Like;\n} | {\n to: Vec3Like;\n} | {\n dir: Vec3Like;\n} | {});\n/** Where particles are born, in emitter space. Sphere / hemisphere / cone have an axis of +Y (the\n * hemisphere is the +Y half, the cone opens along +Y from its base disc at `center`) — aim the\n * node with `lookAt(target, 'y')`. `thickness` 0 emits from the surface only, 1 (default) from the\n * whole volume. A sphere or cone also sets the LAUNCH DIRECTION (outward / from the cone's apex)\n * when `startVelocity` gives a speed but no direction, like Unity's shapes. */\ntype Shape = {\n type: \"point\";\n v: Vec3Like;\n} | {\n type: \"box\";\n min: Vec3Like;\n max: Vec3Like;\n} | {\n type: \"circle\";\n center: Vec3Like;\n radius: number;\n} | {\n type: \"sphere\";\n center?: Vec3Like;\n radius: number;\n thickness?: number;\n} | {\n type: \"hemisphere\";\n center?: Vec3Like;\n radius: number;\n thickness?: number;\n} | {\n type: \"cone\";\n center?: Vec3Like;\n radius: number; /** half-angle, radians */\n angle?: number; /** emit this far up the axis too */\n length?: number;\n thickness?: number;\n};\n/** Extra velocity over each particle's life — evaluated from the curves every frame and ADDED as a\n * displacement (not accumulated like `acceleration`): `radial` pushes outward along the particle's\n * birth direction (a burst that decays: `curve(4).to(0)`), `x`/`y`/`z` drift in the simulation\n * space (rising smoke: `y: curve(2).from(0).to(1)`). Unity's velocityOverLifetime. */\nexport type VelocityOverLife = {\n radial?: ParticleValue;\n x?: ParticleValue;\n y?: ParticleValue;\n z?: ParticleValue;\n};\ntype Noise = {\n strength?: number;\n frequency?: number;\n speed?: number;\n /** How much of the displacement a particle earns with AGE (default 0 = all of it from birth).\n * The field is sampled by position, so at 0 every particle born at the same spot is pushed the\n * same way and a plume's root wanders off its emitter by up to `strength` metres; at 1 a particle\n * is born exactly where the emitter put it and drifts into the field over its life — what you\n * want whenever the source is visible (an exhaust pipe, a contact patch, a muzzle). */\n ramp?: number;\n};\n/** Ground plane for bouncing particles (all render modes). `height` is in the simulation space:\n * world y with `space: 'world'`, emitter-local y otherwise. */\nexport type ParticleGround = {\n /** Plane height (default 0). */\n height?: number;\n /** Contact radius — particles stop `radius` above the plane (a mesh's half-extent; default 0). */\n radius?: number;\n /** Fraction of the vertical speed kept on impact, 0..1 (default 0.3). */\n bounce?: number;\n /** Tangential damping while in contact, per second — like `drag` (default 8). */\n friction?: number;\n};\nexport type ParticlesOptions = ParticlesMaterialOptions & {\n /** Draw every particle as this mesh — lit, tumbling 3D debris (shell casings, rubble, leaves,\n * shrapnel) in one draw call. The system switches to the mesh render mode; the default\n * material becomes `Material.lit()` (pass `material` for color/roughness/metallic — the\n * sprite look options are ignored). `size` scales the mesh (default 1); `rotation`/`opacity`/\n * `frame` don't apply. See `angularVelocity` and `ground`. */\n mesh?: Geometry;\n /** (mesh) Spin, radians per second about the particle's own axes — a vector, or a per-component\n * `{ min, max }` range randomized at spawn. Particles are born in the emitter's orientation. */\n angularVelocity?: Vec3Like | {\n min: Vec3Like;\n max: Vec3Like;\n };\n /** A ground plane the particles bounce on and come to rest on (any render mode); `null`\n * disables it. */\n ground?: ParticleGround | null;\n /** Custom draw material. Unset = the default point-sprite material, configured by the\n * `ParticlesMaterialOptions` sugar (map/sheet/emissive/blend/soft) — which is ignored\n * when an explicit material is passed. */\n material?: Material;\n /** Particle pool capacity (default 1000). */\n maxParticles?: number;\n /** Particles emitted per second. */\n rate?: number;\n /** Simulation space. `'local'` (default) — particles ride the node's transform; `'world'` —\n * each particle stays where it was born as the emitter moves on (trails: drift smoke, mud,\n * wake). Switching at runtime resets live particles. */\n space?: \"local\" | \"world\";\n /** Fraction (usually 0..1) of the emitter's own velocity added to each particle at spawn —\n * smoke \"thrown\" off a moving car. Takes effect with `space: 'world'`. */\n inheritVelocity?: number;\n /** Particles emitted per world unit the emitter MOVES, on top of `rate`, with spawn points\n * spread evenly along the path — trail density independent of speed, no per-frame clumps.\n * Meant for `space: 'world'`. */\n rateOverDistance?: number;\n /** Spread those spawn points along a CURVE through the emitter's recent path instead of the\n * straight line between where it was last frame and where it is now. A straight line cuts the\n * corner by however far the path bows inside one frame, which grows with the frame TIME — so a\n * fast curving emitter looks faceted, and looks worse the slower the machine. Default false\n * (the straight line); costs three stored positions and one curve evaluation per spawn.\n *\n * The curve needs a point one frame AHEAD, so each frame's spawns are placed provisionally and\n * nudged into place on the next frame, once it exists. Nothing else observes them in between. */\n smooth?: boolean;\n /** Draw order among blended systems at the same depth — higher draws later, i.e. on top (Unity's\n * sortingOrder). Systems are depth-sorted by their node, so the emitters of one effect tie and\n * without this the engine picks who covers whom per frame (smoke popping over a fireball).\n * Default 0; a fireball wants 2, its smoke 1, a smoke trail -1. */\n order?: number;\n /** Sprites take the light of the PLACE each one is in — the level's baked light grid (`env.lightmap.volume`).\n * A sprite is unlit: its colour is the picture, which is right for fire and wrong for dust — a puff kicked up\n * under an awning glows as if it stood in the sun. With `lit` every particle's colour is multiplied by the light\n * where it is, relative to the level's OPEN ground: exactly the authored colour out in the sun, the ambient's\n * share of it (tinted the way the shade is) under a roof — per particle, so a trail of puffs laid from the sun\n * into the shade is lit along its length. Author the colour for the open; nothing else to tune. Without a grid\n * — a level with no bake, a host that has none — the colours are drawn as authored. Points, quads, stretch and\n * `Trail`; mesh particles are lit by their material. Default false. */\n lit?: boolean;\n /** Coarse draw order among ALL blended draws, 0 (first) … 7 (last) — see `Mesh.renderPriority`.\n * Default 5: meshes sit at 4 and decals at 3, so smoke covers a car's glass and its skid marks\n * whatever the camera does (the engine's depth sort compares object centres, and an emitter's\n * centre says nothing about where its cloud is). `order` breaks ties inside one priority. */\n renderPriority?: number;\n shape?: Shape;\n /** Extra velocity over life (radial burst that decays, axis drift) — see `VelocityOverLife`. */\n velocityOverLife?: VelocityOverLife;\n startVelocity?: Vec3Like | VelocityValue;\n /** Downward acceleration, world units/s² — positive pulls particles DOWN (sugar for\n * `acceleration: [0, -g, 0]`). */\n gravity?: number;\n /** Constant acceleration vector (gravity, wind, …). Wins over `gravity` when both are set. */\n acceleration?: Vec3Like;\n drag?: number;\n lifetime?: Range<number>;\n color?: ParticleColor;\n /** World-unit diameter (alias of custom[0]). Default 1. */\n size?: ParticleValue;\n /** Radians (alias of custom[1]). */\n rotation?: ParticleValue;\n /** Per-particle opacity 0..1 (alias of custom[2]). Default 1. */\n opacity?: ParticleValue;\n /** Flipbook frame index (alias of custom[3]). With `sheet` set and no explicit frame, the\n * default is one full sheet cycle over each particle's lifetime, starting at `startFrame`. */\n frame?: ParticleValue;\n /** Where the default flipbook cycle begins: `'random'` (default — desynchronized loops like\n * fire/smoke) or a frame index (`0` plays the sheet in order — explosions, one-shot bursts).\n * Only shapes the default; an explicit `frame` wins. */\n startFrame?: number | \"random\";\n noise?: Noise | null;\n /** Fixed random seed for deterministic tests. */\n seed?: number;\n};\nexport declare class Particles extends Node {\n private _material;\n /** Custom curve-param slots (0..3); size/rotation/opacity/frame alias slots 0-3. */\n readonly custom: ParticleValue[];\n constructor(options?: ParticlesOptions);\n /** Emit `count` particles immediately (a burst). */\n spawn(count: number): this;\n private _send;\n set rate(val: number);\n /** `'world'` leaves particles behind where they were born (trails). Switching resets live ones. */\n set space(val: \"local\" | \"world\");\n set inheritVelocity(val: number);\n set rateOverDistance(val: number);\n /** Lay a frame's spawns along a curve through the emitter's path, not the straight chord. */\n set smooth(val: boolean);\n set order(val: number);\n /** Colours × the baked light where each particle is — see `ParticlesOptions.lit`. */\n set lit(val: boolean);\n /** Coarse draw order, 0 … 7 — see `Mesh.renderPriority`. Write-only. */\n set renderPriority(v: number);\n set velocityOverLife(v: VelocityOverLife);\n set shape(shape: Shape);\n /** (mesh mode) Replace the particle mesh; live particles keep flying as the new shape. */\n set mesh(g: Geometry);\n set angularVelocity(v: Vec3Like | {\n min: Vec3Like;\n max: Vec3Like;\n });\n set ground(g: ParticleGround | null);\n set startVelocity(val: Vec3Like | VelocityValue);\n /** Positive pulls particles down — sugar for `acceleration = [0, -g, 0]`. */\n set gravity(val: number);\n set acceleration(a: Vec3Like);\n set drag(val: number);\n set seed(val: number);\n set lifetime(val: Range<number>);\n set size(val: ParticleValue);\n set rotation(val: ParticleValue);\n set opacity(val: ParticleValue);\n set frame(val: ParticleValue);\n set color(value: ParticleColor);\n get material(): Material;\n set material(material: Material);\n set noise(noise: Noise | null);\n}\n/** `Trail` options. The look options (map/sheet/emissive/blend/soft) come from\n * `ParticlesMaterialOptions`, same as `Particles`. */\nexport type TrailOptions = Omit<ParticlesMaterialOptions, \"render\" | \"stretch\"> & {\n /** Seconds each trail point lives — the trail's length in time. Default 0.5. */\n time?: number;\n /** Strip width in world units; a curve tapers it over each point's life (head → tail).\n * Default 0.1. */\n width?: ParticleValue;\n /** Minimum emitter movement (world units) between recorded points. Default 0.05. */\n minDistance?: number;\n /** Point capacity (default 128). A spawn that does not fit is DROPPED, so a fast emitter at a\n * small `minDistance` wants headroom: a sword tip covers metres inside one `time` window. */\n maxPoints?: number;\n /** Follow a CURVE through the emitter's recent path instead of the straight line between frames.\n * A trail is where this shows most — the strip is the path — and it shows worse the lower the\n * frame rate, since a longer frame bows further off its own chord. Default false; see\n * `ParticlesOptions.smooth`. */\n smooth?: boolean;\n /** The strip takes the baked light of the place each of its points is at — `ParticlesOptions.lit`. Smoke and\n * dust trails; leave it off for a glowing one. Default false. */\n lit?: boolean;\n /** Which way the strip's WIDTH points.\n *\n * `'camera'` (default) rolls the strip about its own length to stay flat to the viewer — it can\n * never disappear, which is why it is the default, but it bears no relation to the thing that drew\n * it. An AXIS (`'x'`/`'y'`/`'z'`) uses that axis of the emitter's own transform, as it was when\n * each point was laid: on a node riding a sword's blade, `'z'` (the blade) makes the strip the\n * surface the blade actually swept, and `width` stops being a made-up number — it is the blade. */\n orient?: \"camera\" | \"x\" | \"y\" | \"z\";\n /** With `orient` on an axis: the floor under the strip's APPARENT width, 0..1 of its real width,\n * below which it rolls back toward the camera. An honestly oriented strip goes edge-on — and\n * vanishes — whenever the swing happens in the plane of view; this is the hybrid that keeps it\n * readable. 0 = never roll (honest, and it will vanish), 1 = always (the same as `'camera'`).\n * Default 0.4: a sweep still reads as a sweep, and a swing toward the camera still shows. */\n faceCamera?: number;\n color?: ParticleColor;\n /** Opacity along the trail. Defaults to fading the tail out (`curve().to(0)`). */\n opacity?: ParticleValue;\n};\n/** A ribbon strip that follows this node through the world — sword swings, skid marks, missile\n * trails. Attach it to (or under) the moving node and just move; points are laid down per\n * `minDistance` of movement, live for `time` seconds, and the strip stays glued to the node at\n * its head. Width/opacity/color accept the same curves as `Particles`, evaluated over each\n * point's life — i.e. along the trail from head (fresh) to tail (dying). */\nexport declare class Trail extends Node {\n private _material;\n private _rateDistance;\n private _orient;\n private _faceCamera;\n constructor(options?: TrailOptions);\n private _send;\n /** Trail length in seconds — how long each laid-down point lives. */\n set time(val: number);\n set width(val: ParticleValue);\n set opacity(val: ParticleValue);\n set color(value: ParticleColor);\n set minDistance(val: number);\n /** Follow a curve through the emitter's path instead of the straight chord between frames. */\n set smooth(val: boolean);\n set lit(val: boolean);\n /** Which way the strip's width points — see `TrailOptions.orient`. Keeps the current `faceCamera`. */\n set orient(val: \"camera\" | \"x\" | \"y\" | \"z\");\n /** The hybrid's floor — see `TrailOptions.faceCamera`. */\n set faceCamera(val: number);\n /** Pause/resume laying down points — existing ones still age out, so the trail fades naturally\n * after e.g. a sword swing ends. */\n set emitting(val: boolean);\n get material(): Material;\n}\nexport {};\n","types/gl/physics/CharacterController.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec2Like, type Vec3Like } from \"../../math/vec\";\nimport type { CompWriter } from \"../../core/compWrite\";\nimport type { Node } from \"../Node\";\n/** Where the character's feet are, as reported by the solver after the last step. */\nexport type GroundState = \"ground\" | \"slope\" | \"unsupported\" | \"air\";\nexport declare class CharacterController extends Aspect<\"controller\", Node> implements CompWriter {\n static readonly aspect = \"controller\";\n static fields: FieldMeta<CharacterController>;\n private _charId;\n private _gravityScale;\n private _maxSlope;\n onAttach(): void;\n onDetach(): void;\n /** Native character id (0 until attached / no physics support). */\n get id(): number;\n /**\n * This frame's movement command, in world units/s — NOT normalized, NOT a per-frame displacement\n * (that is what Unity's `Move` takes; passing `v * dt` here gives a character 60× too slow).\n *\n * Two components = horizontal `(x, z)`, the everyday call. Three = the whole velocity, for free mode\n * (`gravityScale = 0`); with gravity on, the vertical component fights the ballistic one and the\n * character barely falls, so that combination warns.\n *\n * Sticky only within the frame: the command expires once the engine consumes it. It also **takes the\n * axis back from a latched `velocity`** — commanding is claiming ownership, which is what keeps the\n * two horizontal sources from ever fighting.\n */\n move(x: number, z: number): void;\n move(v: Vec2Like | Vec3Like): void;\n /** Vertical velocity (world units/s) — LATCHED: gravity works on it, you seed it. `= 7` to jump,\n * `+= 3` to stack an explosion on top of the current motion. No ground check: guard it yourself\n * with `grounded` (or don't, for a double jump). Overridden every frame by a 3-component `move()`.\n * `velocity.y = 7` is the same channel — pick whichever reads better. */\n get velocityY(): number;\n set velocityY(v: number);\n /** Multiplier over the world gravity (`Physics.configure({ gravity })`); default 2, for the snappier\n * fall games want. **0 = free mode**: no gravity, no stick-to-floor, no stair stepping — a swimmer\n * or a drone, driven by the 3-component `move()`. */\n get gravityScale(): number;\n set gravityScale(v: number);\n /** Max ground slope (degrees) the character treats as walkable; default 45. Live. */\n get maxSlope(): number;\n set maxSlope(v: number);\n /**\n * True while a requested collider resize hasn't taken — you asked to stand up and there is something\n * overhead. Resizing goes through the `Shape` aspect itself:\n *\n * hero.aspect(Shape, { capsule: CROUCHED }) // always fits — you are shrinking\n * hero.aspect(Shape, { capsule: STANDING }) // may be refused under a low ceiling\n * if (hero.controller.resizing) … // still crouched; call it again next frame\n *\n * A refusal changes nothing, so the retry is just the same call again — and it is an exact headroom\n * test against the real capsule, unlike a hand-rolled raycast (a ray is a line; a capsule has girth).\n * The FEET stay planted across a resize, so the character neither hovers nor sinks.\n */\n get resizing(): boolean;\n /** True while standing on walkable ground. */\n get grounded(): boolean;\n /** Where the feet are after the last step: on walkable ground, on too-steep ground, touching\n * something that can't support it, or in the air. */\n get groundState(): GroundState;\n /**\n * READ — the velocity the solver ended up with after the most recent step (world units/s, fresh\n * Vec3): what HAPPENED, not what you asked for. Walking into a wall reads ~0, sliding along one\n * reads the tangent. Unlike Unity's synchronous `Move`, our step runs later in the frame, so a read\n * is up to one frame old — irrelevant for animation speed, fall damage or \"am I blocked\", which is\n * what it is for. (Exact wall contact would need a contact normal; the engine has none yet.)\n *\n * WRITE — LATCH the whole velocity: a knockback, a wall jump, a launch pad. Unlike `move()` it does\n * not expire, so the character keeps flying, and gravity still pulls the vertical down into a real\n * ballistic arc. It stays until `move()` takes the axis back — so a game simply doesn't call\n * `move()` while the throw lasts, and ends it on its own terms:\n *\n * hero.controller.velocity = [dir.x * 12, 6, dir.z * 12] // hit by the blast\n * // …in the loop:\n * if (thrown) { if (hero.controller.grounded) thrown = false } // landing ends it\n * else hero.controller.move(ix * SPEED, iz * SPEED) // …and this reclaims the axis\n *\n * Note nothing clears the latch by itself, landing included — so a thrown character that never gets\n * a `move()` keeps sliding along the ground (a kinematic controller has no friction).\n *\n * Reading is not the inverse of writing: `c.velocity = c.velocity` is NOT a no-op, because the read\n * reports the measured result (against a wall it is ~0 and would cancel the throw). In flight the\n * two agree closely, so read-modify-write mid-air behaves as expected.\n *\n * `c.velocity.y = 7` (the direct spelling) is a jump — the compiler routes it to the exact\n * `velocityY` channel via `_writeComp` below, no vector allocated — and `c.velocity.x = 3` latches\n * the whole vector with the measured velocity filling in the other two, i.e. the read-modify-write\n * above spelled naturally. A STORED copy is still a copy: `const v = c.velocity; v.y = 7` does nothing.\n */\n get velocity(): Vec3;\n set velocity(v: Vec3Like);\n /** Compile-time list (chisel reads it, then strips it): the getters whose `c.<getter>.<axis> = v`\n * spelling is routed to `_writeComp` below. See core/compWrite.ts. */\n static _comps: string[];\n}\n","types/gl/physics/Physics.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport type { CompAxis, CompWriter } from \"../../core/compWrite\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { type Node } from \"../Node\";\nexport type MotionType = \"static\" | \"dynamic\" | \"kinematic\";\nexport interface PhysicsConfig {\n /** Gravity in world units/s² (Y-up: down is negative). Default [0, -9.81, 0]. */\n gravity?: Vec3Like;\n /** Max simultaneous bodies (resizes the world; only before any body exists). Default 4096. */\n maxBodies?: number;\n}\n/** Closest raycast hit. */\nexport interface RayHit {\n node: Node | null;\n point: Vec3;\n normal: Vec3;\n fraction: number;\n}\n/**\n * What a body's friction already is the moment the host creates it. This is part of the ABI, not an\n * assumption: bridges.d.ts states it, so every host owes us this value. Knowing it lets attach skip\n * a bridge call per body whenever nobody named a surface.\n */\nexport declare const DEFAULT_FRICTION = 0.6;\nexport declare class Physics extends Aspect<\"physics\", Node> implements CompWriter {\n static readonly aspect = \"physics\";\n /** Render interpolation of body transforms between the fixed 60 Hz steps (global; default on). Turn\n * off to save per-frame transform writes when you have many moving bodies / don't need >60 Hz\n * smoothness — bodies then advance in discrete steps. */\n private static _interpolation;\n static get interpolation(): boolean;\n static set interpolation(on: boolean);\n /** Default \"dynamic\". */\n motion: MotionType;\n /** Mass in kg for dynamic bodies (default 1). Ignored for static/kinematic. */\n mass: number;\n /**\n * Surface friction: 0 = ice, ~1 = grippy asphalt, and values above 1 are allowed (rubber on\n * tarmac).\n *\n * The engine COMBINES the two touching bodies as `sqrt(a * b)`, so the LOWER value dominates and\n * the floor caps everything standing on it. The default **0.6** is a neutral solid surface (the\n * raw Jolt default of 0.2 is ice by game standards); dry tarmac a car should corner on wants a\n * `1`, ice `0.02`. A Vehicle's tires read the GROUND body's value, so this is the single number\n * that decides how well a car corners.\n *\n * Change it at runtime by re-configuring — `floor.aspect(Physics, { friction: 0.02 })` (an ice\n * patch) — or by assigning `floor.physics.friction = 0.02`; either way the setter pushes the new\n * surface to the live body at once. (chisel keeps an instance setter whose name appears as an\n * object-literal key anywhere in the bundle, so the config-object route survives tree-shaking\n * even when no code reads `.friction`.)\n */\n get friction(): number;\n set friction(v: number);\n private _friction;\n /** Scene-editor inspector: `motion` as a dropdown (a string default alone infers a text box). */\n static fields: FieldMeta<Physics>;\n private _bodyId;\n private static _refusedWarned;\n onAttach(): void;\n onDetach(): void;\n /** Native Jolt body id. 0 until attached, or if the build has no physics support. */\n get id(): number;\n /** Linear velocity in world units/second (fresh Vec3 on read; `velocity.y = 5` written directly on\n * the aspect is compiled to a component write — see `_writeComp`). */\n get velocity(): Vec3;\n set velocity(v: Vec3Like);\n /**\n * Angular velocity — **degrees/second about each world axis** (the SDK's angle unit everywhere;\n * the engine works in radians and converts here). Fresh Vec3 on read.\n *\n * This is the only handle on a body's spin, and placing an object usually needs it: a `position`\n * write is a pure teleport, so a crate that was tumbling keeps tumbling at its new home. Putting\n * something down is `body.velocity = [0,0,0]; body.angularVelocity = [0,0,0]; node.position = p`.\n */\n get angularVelocity(): Vec3;\n set angularVelocity(v: Vec3Like);\n _writeComp(prop: string, axis: CompAxis, v: number): void;\n /** Apply an instantaneous impulse (kg·m/s) and wake the body. */\n applyImpulse(v: Vec3Like): this;\n /** The same impulse applied at a WORLD-SPACE point instead of the centre of mass: the lever arm\n * becomes angular impulse, so the body spins as well as moves (a bullet hitting a crate off\n * centre, a blast lifting it by its base). Falls back to the central impulse on an older host. */\n applyImpulseAt(v: Vec3Like, point: Vec3Like): this;\n /** Configure gravity / limits. Call once before creating bodies. */\n static configure(config?: PhysicsConfig): void;\n /** Whether this build has physics support (CREATOR_GL_PHYSICS). */\n static get supported(): boolean;\n /** Closest pickable body hit by the ray from `origin` along `dir` (up to `maxDist`), or null. */\n static raycast(origin: Vec3Like, dir: Vec3Like, maxDist?: number): RayHit | null;\n}\n","types/gl/physics/physicsEvents.d.ts":"export declare const ensurePhysicsEvents: () => void;\n","types/gl/physics/Ragdoll.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport { Node } from \"../Node\";\nexport interface RagdollHinge {\n /** The hinge axis in the MODEL's space (its rest pose: +Z forward, +Y up, +X the model's left in\n * glTF). Perpendicular to the bone; the engine drops any component along it. */\n axis: Vec3Like;\n /** The bend range about `axis` in degrees, relative to the pose the ragdoll was built in — a knee\n * is `{ axis: [1, 0, 0], min: 0, max: 140 }`: it folds one way only. */\n min: number;\n max: number;\n}\nexport interface RagdollPart {\n /** The bone the body sits on — its origin is the joint. */\n bone: string;\n /** The bone the capsule points at (the next joint down). Omitted = a leaf: `length` along the line\n * from the parent part's origin (a head, a hand, a foot without toes). */\n to?: string;\n /** The bone of the part this one hangs from (default: the previous part in the list). The root\n * has none. */\n parent?: string;\n /** Capsule radius in metres (default 0.05). */\n radius?: number;\n /** Length in metres: a leaf's, or an override of the distance to `to`. */\n length?: number;\n /** This part's share of the ragdoll's `mass` (relative weight, default 1). */\n mass?: number;\n /** Cone half-angle in degrees the part may swing off its parent (default 30). Ignored with `hinge`. */\n swing?: number;\n /** Twist half-angle in degrees about its own axis (default 20). */\n twist?: number;\n /** A one-way joint instead of the cone. */\n hinge?: RagdollHinge;\n}\n/** How the body lies: on its back (the chest points up), prone (the chest points down), or on a side. */\nexport type RagdollFacing = \"up\" | \"down\" | \"side\";\nexport interface RagdollActivateOptions {\n /** A LAUNCH added to every part's own motion (world m/s) — an explosion, a throw. The bones' own\n * motion (the run, the swinging arms) is measured by the engine and needs no help. */\n velocity?: Vec3Like;\n /** The motors' strength from the first step (default: the current `strength`). */\n strength?: number;\n /** The root anchored to the animation from the first step (default: the current `anchored`). */\n anchored?: boolean;\n}\nexport interface RagdollDeactivateOptions {\n /** Seconds the animator takes to transition OUT of the fallen pose into whatever plays next (a\n * get-up take started right after, or the loop). 0 (default) = a cut. Move the model node under\n * the hips before this call: the bones are handed back against its new transform. */\n blend?: number;\n}\nexport interface RagdollHitOptions {\n /** How long the body stays powered before the bones go back to the animator (s, default 0.6). */\n duration?: number;\n /** The transition out of the reaction's last physical pose (s, default 0.25). */\n blend?: number;\n /** The motors' strength during the reaction (default 1). */\n strength?: number;\n}\nexport declare class Ragdoll extends Aspect<\"ragdoll\", Node> {\n static readonly aspect = \"ragdoll\";\n /** The parts: `'humanoid'` (default) finds the standard bones by name; a list places bodies on any\n * bones — parents before children. */\n parts: RagdollPart[] | \"humanoid\";\n /** Total mass in kg (default 70), split between the parts by their `mass` shares. */\n mass: number;\n /** Friction of every part (default 0.6 — the physics default). */\n friction: number;\n /** Linear / angular damping of every part; 0 = Jolt's own 0.05. More angular damping settles a\n * flailing body sooner. */\n linearDamping: number;\n angularDamping: number;\n /** What the parts collide with. `'static'` (default): the static geometry and other such ragdolls\n * only — dynamic bodies, character controllers and vehicles pass through a fallen body, which then\n * never shoves or blocks anything and costs nothing when they meet. `'all'`: a regular dynamic\n * body that bumps into everything (and gets kicked awake by everything). */\n collide: \"static\" | \"all\";\n /** Once every part of a LIMP body has come to rest the parts turn static where they lie (default\n * true): the pose holds, nothing can wake a settled body and it costs the solver nothing —\n * `deactivate()` / `activate()` still work (activate makes it dynamic again). A driven or anchored\n * body never freezes. */\n freeze: boolean;\n /** Seconds limp after which the body freezes whatever it is doing — a twitch on a slope or a pile\n * never sleeps on its own. 0 (default) = no cap. */\n freezeAfter: number;\n /** The joint motors: the position spring's frequency in Hz (default 6 — higher = a stiffer, quicker\n * return to the animated pose) and damping ratio (default 1 = critical, no overshoot). */\n driveFrequency: number;\n driveDamping: number;\n /** The motors' torque limit at strength 1, in N·m per kg of the part (default 12: ~180 N·m at the\n * hips of an 80 kg body, ~25 at a forearm). Lower = a hit displaces a limb more before the\n * animation wins it back. */\n driveTorque: number;\n /** Joint friction in N·m per kg of the part (default 0.3): a torque that resists any joint motion,\n * motor or not — a limp body folds instead of flopping like jelly. */\n jointFriction: number;\n /** Where the joint limits come from. `'clips'` (default): measured from the animation — at the first\n * activation that finds clips on the model's animator, every joint's swing and twist range over\n * every bound clip becomes its limit (plus `limitsMargin` on each side), so the motors never\n * target a pose the limits forbid and a limp body settles into poses the clips use; until clips\n * are bound the part table's cones apply. `'table'`: the part table's cones and hinges only. */\n limits: \"clips\" | \"table\";\n /** Degrees added on each side of a learned range (default 10). */\n limitsMargin: number;\n static fields: FieldMeta<Ragdoll>;\n private _id;\n private _active;\n private _bones;\n private _strength;\n private _anchored;\n private _hipsFwd;\n private _hipsUp;\n private _ramp;\n private _release;\n onAttach(): void;\n onDetach(): void;\n /** Hand the bones to physics from the pose they are in right now, each moving as it did over the\n * last two frames (the engine measures: a runner keeps travelling, a swinging arm keeps swinging). */\n activate(opts?: RagdollActivateOptions): boolean;\n /** Take the bones back: the animator's pose shows again from the next frame — through a `blend`\n * out of the fallen pose when asked (play the get-up take right after, with its own fade: it\n * starts from where the body lies). */\n deactivate(opts?: RagdollDeactivateOptions): void;\n /** Physics owns the bones right now. */\n get active(): boolean;\n /** Active and every part asleep (or frozen) — the body has come to rest. */\n get settled(): boolean;\n /** The joint motors' strength, 0..1: how hard every joint is pulled toward the pose the animator\n * shows (0 = off — a limp body). Kept across activations. */\n get strength(): number;\n set strength(v: number);\n /** The hips follow the animation kinematically (the body stands in its clip while physics moves the\n * limbs — hit reactions, a stagger). Off = the hips are a free body (a fall). */\n get anchored(): boolean;\n set anchored(v: boolean);\n /** The joints give way: the strength ramps to 0 over `seconds` and the anchor comes off — a body\n * shot mid-stride keeps its pose for a moment and then collapses, instead of switching off. */\n goLimp(seconds?: number): void;\n /** A flinch: the body powers up anchored to its animation (if it is not already active), the struck\n * part gets the impulse (N·s, at a world point), and after `duration` the bones go back to the\n * animator through `blend`. On a limp body (a corpse) it is just the impulse. */\n hit(bone: string, v: Vec3Like, at?: Vec3Like, opts?: RagdollHitOptions): boolean;\n /** The root part's bone (the hips): where the body is. */\n get root(): Node | null;\n /** How the body lies: `'up'` on its back (the chest points up), `'down'` prone, `'side'` otherwise.\n * Read while it is down, to pick the get-up take. */\n get facing(): RagdollFacing;\n /** Where the head points along the ground, as a yaw in degrees (the model node's `eulerAngles` y\n * that faces that way): where a get-up take that rises head-first ends up facing. A body still\n * upright answers with the way its chest faces. */\n get heading(): number;\n /** The bones that carry a part, in order. */\n get bones(): string[];\n /** The rigid-body id of a part (0 if none) — for the plain body calls. */\n bodyOf(bone: string): number;\n /** Push one part: an impulse in N·s, at a world point (a hit) or through its centre. Wakes the body. */\n impulse(bone: string, v: Vec3Like, at?: Vec3Like): boolean;\n /** The strength ramp (goLimp) and the hit reaction's hand-back. */\n update(dt: number): void;\n}\n","types/gl/physics/Shape.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\n/** Which geometry a Shape uses — the one-of the fields below encode (see `_build`'s order). */\nexport type ShapeKind = \"auto\" | \"box\" | \"sphere\" | \"cylinder\" | \"capsule\" | \"mesh\" | \"convex\" | \"heightfield\";\n/** A node-local AABB, in the node's OWN frame (its own transform excluded), before world scale. */\nexport type ShapeBounds = {\n min: [number, number, number];\n max: [number, number, number];\n};\n/** Dimensions measured from a node's rendered geometry — what `Shape.fit` writes, and the numbers\n * the scene editor's \"Fit to mesh\" button puts in the file. Exactly one dimension key is set (none\n * for a mesh/convex kind, whose geometry is the mesh itself); `origin` centres it on the art. */\nexport type ShapeFit = {\n box?: [number, number, number];\n sphere?: number;\n cylinder?: {\n halfHeight: number;\n radius: number;\n };\n capsule?: {\n halfHeight: number;\n radius: number;\n };\n origin: [number, number, number];\n};\nexport declare class Shape extends Aspect<\"shape\", Node> {\n static readonly aspect = \"shape\";\n /** Box half-extents [hx, hy, hz] (world units). */\n box?: Vec3Like;\n /** Sphere radius. */\n sphere?: number;\n /** Cylinder aligned on Y: half-height + radius. */\n cylinder?: {\n halfHeight: number;\n radius: number;\n };\n /** Capsule aligned on Y: half-height of the cylinder section + radius. */\n capsule?: {\n halfHeight: number;\n radius: number;\n };\n /** The node's own triangles (a Mesh's geometry or a Model's GLB, world scale applied).\n * `true` = exact triangle mesh — static/kinematic bodies, triggers, characters' ground and picking\n * only (a dynamic body can't be a triangle mesh; Physics throws). `'convex'` = convex hull of the\n * vertices, works for dynamic bodies too. A Model uses its bind pose (skinned parts skipped). */\n mesh?: boolean | \"convex\";\n /** The node's terrain (`Terrain.create(...).node`) as a Jolt height field — the exact drawn grid,\n * holes included (docs/terrain-plan.md). Static / kinematic / picking / character ground only,\n * like `mesh: true`. `terrain.commit()` pushes edits into the live shape. */\n heightfield?: boolean;\n /**\n * The shape's centre, relative to the node's origin — world units in the node's ROTATED frame\n * (the node's scale is ignored, exactly like the explicit dimensions above). Default [0, 0, 0].\n *\n * A model's pivot is rarely its centre of volume (a character stands ON its origin, a wheel hangs\n * off its axle), so a collider centred on the pivot is half sunk into the floor. `origin` lifts it\n * without moving the node: `{ capsule: { halfHeight: 0.6, radius: 0.3 }, origin: [0, 0.9, 0] }`.\n * `fit()` and the scene editor's \"Fit to mesh\" fill it in from the rendered bounds.\n *\n * On a DYNAMIC body the offset also moves the centre of mass, so a lopsided collider tips the way\n * you would expect. With no `origin` an auto shape (`{}`) still centres itself on the node's own\n * mesh bounds — only explicit dimensions sit on the pivot by default.\n */\n origin?: Vec3Like;\n /** Whether pointer rays can hit this shape (click / touchstart). Default true. */\n raycast: boolean;\n private _shapeId;\n private _bodyId;\n /** Centre the \"auto\" box measured for itself — used when `origin` isn't set explicitly. */\n private _autoOrigin;\n /** Geometry props as of the last build (see onReconfigure). */\n private _sig;\n onAttach(): void;\n onDetach(): void;\n /** Re-configuring (`node.aspect(Shape, { origin })`) rebuilds the geometry when a dimension, the\n * kind or the origin changed, and re-applies pickability. The body keeps its id and velocity. */\n onReconfigure(): void;\n /**\n * Measure the node's rendered geometry and size the collider to it — the code half of the scene\n * editor's \"Fit to mesh\". Keeps the current kind unless one is passed; `auto` becomes an explicit\n * box, and a mesh/convex shape only has its `origin` cleared (its geometry IS the mesh).\n *\n * crate.aspect(Shape, {}).shape.fit() // box around what the model actually draws\n * hero.aspect(Shape, {}).shape.fit('capsule') // capsule of the same height + girth\n *\n * A model loads asynchronously, so fit AFTER its `load()` resolves — an empty subtree measures as\n * nothing and the call is a no-op (it warns). Rebuilds the live shape, keeping the body.\n */\n fit(kind?: ShapeKind): this;\n /** Which geometry this shape currently uses (the `_build` dispatch, as a name). */\n get kind(): ShapeKind;\n /**\n * The node's subtree AABB in its OWN local frame (its own transform excluded), or null when there\n * is nothing to measure. Reads the engine's bounds — which cover a loaded GLB and every child —\n * and falls back to a Mesh node's own CPU geometry on hosts without them.\n */\n static boundsOf(node: Node): ShapeBounds | null;\n /**\n * Dimensions + origin that make `kind` hug what `node` renders — world units, so the node's world\n * scale is baked in exactly as the Shape fields expect. Null when the node has no geometry (a\n * model that hasn't loaded, an empty).\n */\n static fitTo(node: Node, kind?: ShapeKind): ShapeFit | null;\n /**\n * The measuring itself, over plain numbers: a node-local AABB + the node's world scale in, shape\n * dimensions out. Separate from `fitTo` so the scene-editor harness can measure a node from\n * ANOTHER bundle without touching accessors the bundler may have shaken out of it.\n *\n * A sphere takes the LARGEST half-extent and a cylinder/capsule the larger of X/Z, so the fit\n * reads as the object's silhouette rather than as an enclosing ball; adjust from there.\n */\n static fitBounds(bounds: ShapeBounds, scale: Vec3Like, kind?: ShapeKind): ShapeFit;\n private _createPickBody;\n private _rebuild;\n private _build;\n private _applyOrigin;\n private _signature;\n private _buildHeightField;\n private _buildMesh;\n private _buildAutoBox;\n}\n","types/gl/physics/Trigger.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { Node } from \"../Node\";\nexport declare class Trigger extends Aspect<\"trigger\", Node> {\n static readonly aspect = \"trigger\";\n private _bodyId;\n /** Native body id (0 if no physics support). */\n get id(): number;\n onAttach(): void;\n onDetach(): void;\n}\n","types/gl/Plane.d.ts":"import { Vec3, type Vec3Like } from \"../math/vec\";\nimport type { Ray } from \"./Ray\";\nexport declare class Plane {\n /** Unit normal. */\n readonly normal: Vec3;\n /** Scalar offset: dot(normal, point). */\n readonly d: number;\n constructor(normal: Vec3Like, point: Vec3Like);\n static fromPoints(a: Vec3Like, b: Vec3Like, c: Vec3Like): Plane;\n static fromCoefficients(a: number, b: number, c: number, d: number): Plane;\n /** Ray-plane parameter t (≥0), or null on a miss (parallel / behind origin). */\n intersectRay(ray: Ray): number | null;\n /** Like intersectRay but allows hits behind the origin (line-plane). */\n intersectLine(ray: Ray): number | null;\n /** Signed distance from a point (positive on the normal's side). */\n signedDistance(point: Vec3Like): number;\n /** Project a point onto the plane. */\n projectPoint(point: Vec3Like): Vec3;\n}\n","types/gl/Ray.d.ts":"import { Vec3, type Vec3Like } from \"../math/vec\";\nexport declare class Ray {\n readonly origin: Vec3;\n readonly dir: Vec3;\n constructor(origin: Vec3Like, dir: Vec3Like);\n /** The world-space point origin + t·dir. */\n getPoint(t: number): Vec3;\n}\n","types/gl/scenarios.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { FieldMeta } from \"../core/fields\";\nimport type { InspectorUI } from \"../core/InspectorUI\";\nimport { Node } from \"./Node\";\nimport { Model } from \"./Model\";\ntype LoopMode = \"once\" | \"loop\" | \"pingpong\";\n/** Travel from the node's starting position to a target node in `duration` seconds. */\nexport declare class MoveTo extends Aspect<\"moveTo\"> {\n /** Where to travel — place an Empty node and pick it. */\n target: Node | null;\n /** Seconds for the full trip. */\n duration: number;\n /** Seconds to wait before starting. */\n delay: number;\n /** once = stop at the target · loop = restart from the start point · pingpong = back and forth. */\n mode: LoopMode;\n /** Motion curve. */\n easing: \"smooth\" | \"linear\";\n static readonly aspect = \"moveTo\";\n static editor: {\n rebuild: boolean;\n };\n static fields: FieldMeta<MoveTo>;\n private _t;\n private _start;\n update(dt: number): void;\n /** Editor-only path line (edit mode; play mode never calls this). */\n rebuild(): void;\n}\n/** Travel through the children of a path node (add an Empty per waypoint) in `duration` seconds.\n * `loop` runs the circuit closed (last → first); `pingpong` goes back and forth along the open\n * path; `once` stops at the last waypoint. */\nexport declare class FollowPath extends Aspect<\"followPath\"> {\n /** A node whose CHILDREN are the waypoints, in file order. */\n path: Node | null;\n /** Seconds for one full pass of the path. */\n duration: number;\n /** Seconds to wait before starting. */\n delay: number;\n mode: LoopMode;\n /** Turn to face the direction of travel. */\n orient: boolean;\n /** Which local axis leads when orienting. */\n forward: \"-z\" | \"z\" | \"x\" | \"-x\";\n static readonly aspect = \"followPath\";\n static editor: {\n rebuild: boolean;\n };\n static fields: FieldMeta<FollowPath>;\n private _t;\n private _points;\n update(dt: number): void;\n /** Editor-only waypoint polyline (edit mode; play mode never calls this). */\n rebuild(): void;\n}\n/** Continuous rotation about one of the node's local axes, degrees per second. */\nexport declare class Spin extends Aspect<\"spin\"> {\n /** Degrees per second. */\n speed: number;\n /** Local axis to spin around. */\n axis: \"x\" | \"y\" | \"z\";\n static readonly aspect = \"spin\";\n static fields: FieldMeta<Spin>;\n update(dt: number): void;\n}\n/** Keep the node facing a target node (a turret tracking, a signpost, a camera aimed at a hero).\n * Accessor `node.facing` — NOT `lookAt`, which would shadow the `Node.lookAt()` method. */\nexport declare class LookAt extends Aspect<\"facing\"> {\n /** The node to face. */\n target: Node | null;\n /** Which local axis points at the target. */\n forward: \"-z\" | \"z\" | \"x\" | \"-x\";\n /** 0 = snap instantly; otherwise seconds of turn lag (bigger = slower, smoother). */\n smoothing: number;\n static readonly aspect = \"facing\";\n static editor: {\n rebuild: boolean;\n };\n static fields: FieldMeta<LookAt>;\n update(dt: number): void;\n /** Editor-only sight line (edit mode; play mode never calls this). */\n rebuild(): void;\n}\n/** Start a GLB animation clip when the scene runs. Attach to a `model:` node; the inspector card\n * lists the model's clips live and can preview them while editing. */\nexport declare class PlayAnimation extends Aspect<\"playAnimation\", Model> {\n /** Clip name; empty = the model's first clip. */\n clip: string;\n loop: boolean;\n /** Playback rate (1 = authored speed). */\n speed: number;\n static readonly aspect = \"playAnimation\";\n static fields: FieldMeta<PlayAnimation>;\n private _preview?;\n onAttach(): void;\n static inspector(ui: InspectorUI, a: PlayAnimation): void;\n}\nexport {};\n","types/gl/Scene.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Aspect, type AspectCtor, type FieldOf, type TargetOf } from \"../core/Aspect\";\nimport { Presentable, type DismissOptions, type PresentOptions } from \"../ui/presentable\";\nimport { type UIWidgetContent } from \"../ui/UILayer\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport type { FetchResponse } from \"../runtime/fetch\";\nimport { Camera } from \"./Camera\";\nimport { SceneAudio } from \"./audio/SceneAudio\";\nimport { type ControlsHandle, type ControlsOptions } from \"./controls\";\nimport { Material } from \"./Material\";\nimport { Node } from \"./Node\";\nexport type AmbientOcclusionOptions = {\n /** Strength of the darkening (default 1). */\n intensity?: number;\n /** How far the occlusion reaches, in metres (default 0.3). */\n radius?: number;\n /** Falloff contrast; >1 tightens it into the crease (default 1). */\n power?: number;\n /** Sample count + filtering (default 'medium'). Not the buffer resolution — that stays half. */\n quality?: \"low\" | \"medium\" | \"high\" | \"ultra\";\n};\n/** `SceneOptions.taa` / `scene.setAntialias(\"taa\", 4, taa)`: the temporal anti-aliasing knobs. */\nexport type TaaOptions = {\n /** Render the 3D at this fraction (0.5–1) and TAA-upscale it to the viewport; 1 = none. */\n upscale?: number;\n /** The history's share, 0 (max smoothing) … 1 (none); 0.12 default. */\n feedback?: number;\n /** Post-TAA sharpen 0–1; defaults to 0.5 with `upscale` below 1, else 0. */\n sharpness?: number;\n /** A first-person viewmodel: everything closer than this many metres to the camera is treated as\n * fixed on screen — its history is read at the same pixel, not reprojected by the camera's motion,\n * which would trail the weapon on every turn (TAA has no per-object motion vectors). 1 covers arms\n * and weapon at eye height; 0 (the default) = off. A wall walked into within the band smears a little. */\n viewmodel?: number;\n};\nexport type FogOptions = {\n /** A TINT on the in-scattered ambient, not an absolute colour: the engine multiplies it by the\n * environment luminance, so white (the default) means \"fog as bright as the ambient\" and the fog\n * brightens with `environmentIntensity`. Do NOT expect the same hex to look like it does in\n * `skybox` — that one IS an absolute radiance and reads roughly an order of magnitude brighter.\n * Tint towards the sky's hue; leave it white to sit at the ambient level. */\n color?: ColorInput;\n /** Metres from the camera before the fog starts (default 0). */\n start?: number;\n /** Extinction per metre at `height`; 0.01 ≈ clearly visible over ~100 m (default 0.01). */\n density?: number;\n /** The fog's \"sea level\" in world Y (default 0). */\n height?: number;\n /** How fast it thins with altitude, 1/m. 0 = uniform everywhere; higher = a ground-hugging layer\n * you can see over (default 0). */\n heightFalloff?: number;\n /** Cap on how opaque it can get, 0–1 — keeps far shapes readable (default 1). */\n maxOpacity?: number;\n /** Metres after which fog stops applying; 0 = everywhere (default 0). */\n cutoff?: number;\n /** Take the colour from the environment in the view direction, tinted by `color`, instead of a\n * flat `color`. Convincing when the IBL is a real sky (default false). */\n fromEnvironment?: boolean;\n};\nexport type SceneOptions = {\n /** Image-based ambient lighting (default on). `false` turns it off; a STRING is the scene's own\n * probe - `ibl: asset('../assets/ibl-interior.ktx')` - and is how two levels in one project get\n * different environments. Without it the host looks for a project-wide `ibl.ktx`, which is one\n * probe for every scene: swapping that file to suit an interior level silently relights the\n * outdoor one. A named probe also travels through `asset()`, so a build only carries the\n * environments its own entry point reaches. */\n ibl?: boolean | string;\n /** IBL intensity (default 20000). */\n environmentIntensity?: number;\n /** Camera exposure compensation in stops (default 0) - the same knob as\n * `scene.camera.exposureCompensation`, next to the rest of the scene's lighting so a LEVEL can\n * carry its own. The camera is a physical one at EV100 15 (f/16 - 1/125 - ISO 100), i.e. metered\n * for bright sun; an interior lit at real levels needs +7..+9 to read at all. Expose the camera\n * rather than inflating the lights: scaling lamps past what they physically emit gives bright\n * fixtures in a black room, because it changes the RATIO, not the level. */\n exposureCompensation?: number;\n /** Bloom post-processing. */\n bloom?: boolean;\n bloomIntensity?: number;\n /** Tone mapping operator. `'aces'` (default, filament's ACES legacy) desaturates bright colours\n * towards white — HDR fire reads pale; `'neutral'` (Khronos PBR Neutral) keeps hue and\n * saturation until very bright; `'linear'` clips each channel (what an engine without a\n * tonemapper shows — saturated, Unity-without-post-processing look); `'filmic'` (Uncharted). */\n toneMapping?: \"aces\" | \"neutral\" | \"linear\" | \"filmic\";\n /** The sky. Three forms:\n * - a colour — a flat clear colour;\n * - `{ texture }` — a KTX1 **cubemap**, the sharp `<name>_skybox.ktx` that filament's `cmgen`\n * produces from an equirectangular .hdr/.exr. This is the one to use for a real sky. Pass an\n * `asset('../assets/sky.ktx')` handle or a bare staged filename;\n * - `'environment'` — reuse the scene's IBL cubemap. Cheapest (no second texture) but that file\n * is prefiltered for roughness, so the sky comes out soft; fine as a fallback, not as the goal.\n *\n * Either texture form draws through filament's own skybox pass: a full-screen pass in device\n * space after the opaque queue. No geometry, no meridian seam, no pole distortion — do NOT build\n * a sky dome or a fullscreen equirect material by hand, both are strictly worse. */\n skybox?: ColorInput | \"environment\" | {\n texture: string;\n };\n /** Screen-space ambient occlusion — the contact darkening in creases and where props meet the\n * ground. Without it an IBL lights a crease exactly as brightly as an open face, so everything\n * reads as pasted onto the floor rather than standing on it. `true` takes defaults tuned for\n * human-scale props; `radius` is world-space metres and is the one knob that must follow the\n * scene's scale (~0.3 for objects on a table, ~0.6-1 for a yard of crates and containers). */\n ambientOcclusion?: boolean | AmbientOcclusionOptions;\n /** Distance fog / aerial perspective: distant geometry loses contrast so the eye reads depth, and\n * the hard edge where a finite level ends against the skybox goes away. By default the fog applies\n * at every distance — the skybox included — so the sky itself takes the fog colour and the horizon\n * blends on its own; `cutoff` opts geometry beyond a distance back out. */\n fog?: FogOptions;\n /** Anti-aliasing: `true` = 4× MSAA, `2`/`4` = that many samples, `false` = off (FXAA takes over),\n * `\"taa\"` = temporal anti-aliasing (Filament's TAA: one full-screen history blend instead of the\n * multisampled buffers — cheaper than MSAA on an integrated GPU and it also calms specular and\n * foliage shimmer; see `taa` for its knobs). Unset keeps the host default (desktop 4×, mobile/web\n * off). The biggest single fill-rate cost after resolution — turn it down on big screens first. */\n antialias?: boolean | 2 | 4 | \"taa\";\n /** The TAA's knobs (`antialias: \"taa\"`): `upscale` = render the 3D at this fraction (0.5–1) and let\n * TAA reconstruct the full resolution — the cheap way to a lower render cost with most of the\n * detail kept (`renderScale` shrinks the buffer and stretches it instead); `feedback` = the\n * history's share, 0.12 by default (raise it toward 0.3 if fast motion ghosts); `sharpness` =\n * a post-TAA sharpen 0–1, useful with `upscale`. */\n taa?: TaaOptions;\n /** Keep a stencil buffer for this scene (off by default: it costs memory and a clear per frame).\n * Needed before any material's `stencil` test or write does anything. */\n stencil?: boolean;\n /** Render the 3D at this fraction of the viewport (0.25–1) and upscale; the UI stays at native\n * resolution. A fixed, predictable cut of per-pixel GPU work — `0.75` is ~45 % cheaper and\n * barely visible in motion, `0.5` quarters it. Headless renders ignore it. */\n renderScale?: number;\n /** Let the engine shrink the 3D buffers under `renderScale` only when frames run over budget\n * (Filament dynamic resolution, sharpened upscale) down to `min` (default 0.5). Off by default:\n * it makes the output frame-time dependent, so flow tests / headless renders never enable it. */\n dynamicResolution?: boolean | {\n min?: number;\n };\n /** Anisotropic filtering, 1 (off) … 16. Default 2. What it buys is detail on surfaces seen at a\n * GRAZING angle — a first-person weapon, a floor, a wall — where the sample footprint is far\n * longer in one axis than the other and isotropic filtering has to pick a mip for the long one,\n * several levels coarser than the short axis deserves. Measured on a weapon seen from the side\n * (local contrast): 8.18 at 1× → 10.02 at 2× → 10.84 at 4× → 11.29 at 8×. The default is 2\n * because it is where the curve is steepest per unit of memory bandwidth; raise it if you have\n * the headroom.\n *\n * It is an ENGINE-WIDE default, not a property of this scene: a sampler is baked when its\n * texture is bound, so this reaches the models a scene loads AFTER it (which is every model in a\n * scene file — `env` is applied before the nodes build) and leaves already-loaded ones alone.\n * On the desktop host `CREATOR_TEXTURE_ANISOTROPY` overrides it, for tuning without a rebuild. */\n anisotropy?: number;\n /** Engine-wide cap on texture size, 0 / unset = none (see `Texture.maxSize`): a KTX2 above it\n * loses its top mip levels on load, a glTF image is downsampled. Applied before this scene's\n * assets load; like `anisotropy` it does not touch textures already loaded. */\n maxTextureSize?: number;\n /** The look on an HDR display (a screen with headroom above SDR white — Apple XDR panels, the\n * macOS host today); ignored on SDR. `strength` 0..1 is how much of the picture reaches for the\n * display's headroom (0 only what SDR clipped, 1 nearly everything; default 0.35). `paperWhite`\n * 1..8 is where white lands as a multiple of SDR white — the \"HDR brightness\" of a console\n * calibration screen, where 1.5–2 is the norm; default 1 keeps a white wall at the UI's white,\n * faithful but dim next to what \"HDR on\" is expected to look like. Engine-wide like `anisotropy`;\n * `device.hdr` is the runtime form and tells you whether the display has any headroom at all. */\n hdr?: {\n strength?: number;\n paperWhite?: number;\n };\n};\nexport declare class Scene implements Presentable {\n readonly camera: Camera;\n /** The listener + global 3D audio knobs (docs/audio-plan.md). */\n readonly audio: SceneAudio;\n readonly _touchStartListeners: Array<(ev: TouchStartEvent<Node | null>) => void>;\n private _material?;\n private static _active;\n static get active(): Scene | null;\n constructor(options?: SceneOptions);\n /** Runtime form of `renderScale` / `dynamicResolution` (a graphics-settings menu). `renderScale`\n * 0.25–1; older hosts without the method ignore it. */\n setRenderOptions(renderScale: number, dynamicResolution?: boolean | {\n min?: number;\n }): void;\n /** Scene occlusion material: an unlit instance in the occluder blue (the built-in `unlit`, which\n * every runtime carries) — one per scene, made on first use. */\n get occlusionMaterial(): Material;\n set skybox(sky: ColorInput | \"environment\" | {\n texture: string;\n });\n /** Runtime form of `ambientOcclusion` (a graphics-settings menu). `false` turns it off. */\n setAmbientOcclusion(options: boolean | AmbientOcclusionOptions): void;\n /** Runtime form of `fog` (weather, entering a building). `false` turns it off. */\n setFog(options: FogOptions | false): void;\n setMaterialGlobalParameter(i: number, x: number, y: number, z: number, w: number): void;\n setAntialias(mode: boolean | 2 | 4 | \"taa\", scale?: number, taa?: TaaOptions): void;\n /** Depth-reading effects on / off (a graphics-settings menu): soft particles and projected decals\n * read the scene depth, which costs a depth pre-pass of every opaque draw (~12 % of a fill-bound\n * frame). Off = hard-edged particles, no decals, no pre-pass. Engine-wide, live. */\n setDepthEffects(enabled: boolean): void;\n /** LOD distance (a graphics-settings menu): the engine's LOD thresholds × `bias`. 2 = every level\n * switches at half the distance (a model must look twice as big on screen to keep its detail),\n * 0.5 = full detail twice as far, 1 = the defaults. Engine-wide, live. Only GLBs that carry\n * `_LOD<n>` meshes (`lecodes assets doctor --lod`) have levels to switch. */\n setLodBias(bias: number): void;\n /** Runtime form of `bloom` / `bloomIntensity` (a graphics-settings menu). */\n setBloom(enabled: boolean, intensity?: number): void;\n /**\n * How bright the environment (IBL) lights the scene, in lux — `SceneOptions.environmentIntensity`\n * after the fact. Live: it changes the probe's intensity, not the probe, so it costs nothing and\n * can be dragged. (`setDefaultIbl`, the call that installs a probe, rebuilds the cubemap from the\n * ktx every time — never drive a slider through a scene option that has to re-open.)\n *\n * `lecodes lightmap bake` reads the same number off the live probe, so a scene dimmed here bakes\n * dimmed. Hosts without the call keep whatever the scene opened with, and the getter still\n * reports what was asked for.\n */\n get environmentIntensity(): number;\n set environmentIntensity(lux: number);\n private static _warnedEnvIntensity;\n /** The scene's stencil buffer on / off (see `SceneOptions.stencil`). */\n setStencil(enabled: boolean): void;\n add(...list: Node[]): this;\n remove(...list: Node[]): this;\n /** Attach (and configure) a system, or reconfigure it if already present. Returns the scene typed\n * as now-having it (`scene.system(Hud).hud`). A `System<'x', Scene2D>` is rejected here. */\n system<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;\n /** Safe access — undefined if the system isn't attached. */\n get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;\n /** Existence check AND type guard: inside `if (scene.has(Hud))`, `scene.hud` is present. */\n has<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this is this & FieldOf<A>;\n /** Detach a system (runs its onDetach). Chainable. */\n removeSystem<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this;\n /** Tear the scene down: every system detaches (last-attached first) and the scene closes. Nodes\n * are yours — destroy the ones you own; the native scene object itself is not released. */\n destroy(): void;\n createOverlay(options?: SceneOptions): Scene;\n warmRender(): Promise<void>;\n /** Precompile the scene's shader variants so nothing is compiled mid-game. Every material the host\n * knows is queued for the sun / shadow / fog / skinning variants and the dynamic-light key — the\n * first point light (a muzzle flash, an explosion) would otherwise rebuild every lit shader in view\n * on that frame. Call it once the sun and fog are set, typically under a loading screen; materials\n * loaded later are queued in the background as they are created. Resolves at once on a host\n * without the bridge. */\n precompileShaders(): Promise<void>;\n readonly cl: (() => void)[];\n _backButtonCallback?: () => void;\n private _vd?;\n /** Fires when the scene becomes the visible destination (incl. a pop revealing it). */\n onOpen(callback: () => void): this;\n /** Fires when the scene stops being visible (closed, replaced, or covered by a push). */\n onClose(callback: () => void): this;\n /** Hardware/system back while the scene is current. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n /** The UI over the scene — widgets (a HUD, a dialog), laid out over the scene while it is\n * presented; touches outside a widget's box reach the scene. `scene.setContent([hud])`. */\n setContent(content: UIWidgetContent): this;\n /** Make this the active scene — shows it as the current destination (replaces a screen /\n * another scene; only the active scene renders). The runtime activates the engine as part of\n * presenting the destination. */\n open(options?: PresentOptions): void | Promise<void>;\n close(options?: DismissOptions): void;\n addEventListener(channel: \"click\", callback: (ev: ClickEvent<Node | null>) => void): void;\n addEventListener(channel: \"touchstart\", callback: (ev: TouchStartEvent<Node | null>) => void): void;\n removeEventListener(channel: \"click\" | \"touchstart\", callback: (ev: any) => void): void;\n}\nexport type ARMode = \"default\" | \"markers\" | \"arcore\" | \"detached\";\nexport declare class ARScene<T extends ARMode = \"default\"> extends Scene {\n readonly mode: T;\n useWarmRender: boolean;\n private _root?;\n constructor(options?: SceneOptions & {\n mode?: T;\n });\n /** Root anchor node (not available in marker mode). */\n get root(): Node;\n /** Create an anchor from a tracking source (e.g. an image target). */\n createAnchor(source: FetchResponse, physicalWidth?: number): Node;\n /**\n * Let the user place & manipulate a node with touch gestures — the staple AR object-placement\n * interaction: ONE finger drags it across the floor (relative to where the camera looks), TWO fingers\n * pinch to scale and twist to rotate. Returns a handle; call `.remove()` to detach. Tunable via\n * options (min/max scale, and toggles for `pan` / `pinch` / `twist`).\n */\n addControls(target: Node, options?: ControlsOptions): ControlsHandle;\n open(options?: PresentOptions): Promise<void>;\n close(options?: DismissOptions): void;\n}\n/**\n * A 3D scene rendered in a VR headset (OpenXR — e.g. Meta Quest). The headset drives the camera:\n * every frame both eyes are rendered from the tracked head pose, so `scene.camera` position/lookAt\n * have no effect while the scene is open. The world origin is at floor level (stage space) —\n * author content with the ground at y = 0 and the user standing at the origin.\n *\n * `open()` rejects on hosts without a VR runtime (\"VR is not supported on this device\").\n */\nexport declare class VRScene extends Scene {\n open(options?: PresentOptions): Promise<void>;\n close(options?: DismissOptions): void;\n}\n","types/gl/state.d.ts":"import type { Scene } from \"./Scene\";\nexport declare const glState: {\n activeScene: Scene | null;\n};\n","types/gl/terrain/Terrain.d.ts":"import { Node } from \"../Node\";\nimport { Material } from \"../Material\";\nimport { Texture } from \"../Texture\";\nimport { Geometry } from \"../Geometry\";\nimport { type ColorInput } from \"../../core/color\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nexport type TerrainLayer = {\n /** Albedo texture (a URL / `asset()` handle, or a loaded Texture). Unset = white. Its ALPHA is the layer's roughness\n * map (`lecodes assets terrain-pack --roughness` puts it there): an opaque albedo reads 1. */\n albedo?: string | Texture;\n /** Metres per texture repeat. Default 8. */\n tiling?: number;\n /** Perceptual roughness of the layer — a factor on the albedo's alpha (its roughness map), the whole value when the\n * albedo is opaque. A terrain has no metallic: ground is a dielectric. Default 1. */\n roughness?: number;\n /** Normal-map strength (0 = the layer's slot of the pack is not read). Default 0 — set 1 when the\n * layer has a normal map in `normals`. */\n normalScale?: number;\n /** Sample this layer triplanar in world space (cliff rock): no stretching on steep slopes; its\n * normal map is then skipped. Default false. */\n triplanar?: boolean;\n};\nexport type TerrainOptions = {\n /** Samples per side (square). 257 / 513 / 1025 are the usual sizes. Default 129. */\n size?: number;\n sizeX?: number;\n sizeZ?: number;\n /** Metres between samples. Default 1. */\n cellSize?: number;\n /** Cells per chunk side (≤ 255). Default 64. */\n chunk?: number;\n /** Heights in metres: an array of sizeX × sizeZ (row-major, z rows), or a function of the sample's\n * LOCAL position in metres. Default flat 0. */\n heights?: Float32Array | ((x: number, z: number) => number);\n /** A byte per sample, 1 = hole (a triangle needs its three samples valid). */\n holes?: Uint8Array;\n /** RGBA layer weights per sample (normalised in the shader). Default: all layer 0. */\n control?: Uint8Array;\n layers?: TerrainLayer[];\n /** The two normal-map packs: `[layers 0+1, layers 2+3]` — XY of the even layer in RG, the odd in BA. */\n normals?: [string | Texture | undefined, (string | Texture)?];\n /** Multiplier on every layer's albedo. */\n tint?: ColorInput;\n name?: string;\n /** A material to use instead of `Material.terrain()` (a custom terrain shader with the same uniforms). */\n material?: Material;\n};\n/** A region of the terrain in LOCAL metres (XZ). `node` = the XZ footprint of a node's triangles. */\nexport type TerrainRegion = {\n circle: {\n x: number;\n z: number;\n r: number;\n };\n} | {\n rect: {\n x: number;\n z: number;\n w: number;\n h: number;\n };\n} | {\n polygon: readonly (readonly [number, number])[];\n} | {\n node: Node;\n};\nexport type ConformOptions = {\n /** How far below the target surface the ground sits (keeps bilinear terrain strictly under a\n * curved road between samples). Default 0.05. */\n offset?: number;\n /** Metres over which the surrounding ground blends back to its old height. Default 4; 0 = hard edge. */\n falloff?: number;\n /** `both` (default) cuts and fills; `lower` only cuts; `raise` only fills. */\n mode?: \"both\" | \"lower\" | \"raise\";\n};\nexport type RibbonOptions = {\n /** Width in metres. */\n width: number;\n /** Metres of ribbon per texture repeat along its length. Default = width. */\n uvScale?: number;\n};\n/** A brush dab for `sculpt` — LOCAL metres. */\nexport type SculptOptions = {\n x: number;\n z: number;\n /** Brush radius in metres. */\n radius: number;\n /** `raise` / `lower` by `amount` metres at full weight; `smooth` blends toward the 3×3 average\n * (`amount` 0…1 = how far); `flatten` pulls toward `target` (default: the height under the\n * centre) by `amount` 0…1. Default raise. */\n mode?: \"raise\" | \"lower\" | \"smooth\" | \"flatten\";\n amount?: number;\n /** 0…1 — the share of the radius at full weight; the rest feathers out (default 0.5). */\n hardness?: number;\n target?: number;\n};\n/** `snapshot()` — the three sample arrays, copied; `restore()` puts them back (undo, a level reset). */\nexport type TerrainSnapshot = {\n heights: Float32Array;\n holes: Uint8Array;\n control: Uint8Array;\n};\n/** A ray hit on the terrain (`raycast` local, `raycastWorld` world). */\nexport type TerrainHit = {\n point: Vec3;\n normal: Vec3;\n distance: number;\n};\nexport type AutoPaintRules = {\n /** The layer everything starts as. Default 0. */\n base?: number;\n /** Slope rule: the layer takes over between `from` and `to` degrees of slope. */\n slope?: {\n layer: number;\n from: number;\n to: number;\n };\n /** Height rule: the layer takes over between `from` and `to` metres (snow line). */\n height?: {\n layer: number;\n from: number;\n to: number;\n };\n /** Low rule: the layer takes over BELOW `to` metres, fading in from `from` (valley floors). */\n low?: {\n layer: number;\n from: number;\n to: number;\n };\n};\n/** What Shape { heightfield } reads off a terrain node (`node._terrain`). */\nexport type TerrainData = {\n sizeX: number;\n sizeZ: number;\n cellSize: number;\n heights: Float32Array;\n holes: Uint8Array | null;\n};\nexport declare class Terrain {\n /** The node the terrain hangs off: transform it to place the ground; add it to the scene. */\n readonly node: Node;\n readonly sizeX: number;\n readonly sizeZ: number;\n readonly cellSize: number;\n readonly chunk: number;\n /** sizeX × sizeZ heights in metres, row-major (z rows). Edit, then `commit()`. */\n readonly heights: Float32Array;\n /** A byte per sample, 1 = hole. */\n readonly holes: Uint8Array;\n /** RGBA layer weights per sample. */\n readonly control: Uint8Array;\n /** The splat material (`Material.terrain()` unless one was passed). */\n readonly material: Material;\n /** Resolves when every layer texture has loaded (the terrain renders white until then). */\n readonly ready: Promise<void>;\n layers: TerrainLayer[];\n private _native;\n private _chunkMeshes;\n private _controlTex;\n private _dirty;\n private _holesTouched;\n private _controlDirty;\n private _anyHole;\n private _cast;\n private _receive;\n private constructor();\n /** Build a terrain from data / a generator (synchronous; `ready` resolves once its textures loaded). */\n static create(opts?: TerrainOptions): Terrain;\n /** The terrain a node carries (the node `Terrain.create` returned), or null. */\n static of(node: Node | null | undefined): Terrain | null;\n /** Load a `.terrain` file (`Terrain.serialize` / the editor / `lecodes terrain import`); layer textures\n * are not in the file — pass them in `opts` (they are asset handles the file cannot hold). */\n static load(url: string, opts?: Omit<TerrainOptions, \"size\" | \"sizeX\" | \"sizeZ\" | \"heights\" | \"holes\" | \"control\">): Promise<Terrain>;\n private get _grid();\n /** Height at a local (x, z) on the drawn triangles; NaN in a hole or outside the grid. */\n heightAt(x: number, z: number): number;\n /** The drawn triangle's normal at a local (x, z) (unit Vec3, +Y up). */\n normalAt(x: number, z: number): Vec3;\n /** The LAYER WEIGHTS at a local (x, z) — what the splat shader blends there: the control map read bilinearly\n * between its samples and normalised to sum 1 (`[1, 0, 0, 0]` where the map is empty, as the shader has\n * it). Index = the layer's in `layers`. Outside the grid the edge answers. This is how a game asks WHAT the\n * ground is under a point — footprints in the sand and none on the cobble, a footstep sound per layer, dust\n * by surface — and the blend is already in the numbers, so a transition is a fade and not a line. */\n weightsAt(x: number, z: number): [number, number, number, number];\n /** The heaviest layer's index at a local (x, z) — `weightsAt` when only \"which one\" is asked. */\n layerAt(x: number, z: number): number;\n /** The smooth (vertex) normal at integer sample (ix, iz). */\n sampleNormal(ix: number, iz: number): Vec3;\n /** Extent in local metres: `[width, depth]`. */\n get extent(): [number, number];\n /** Min / max height over the grid. */\n get heightRange(): [number, number];\n /** A world-space point into the terrain's local frame. */\n toLocal(p: Vec3Like): Vec3;\n /** A local point into world space. */\n toWorld(p: Vec3Like): Vec3;\n /** The ground's WORLD height under a world (x, z): NaN off the grid / in a hole. */\n worldHeightAt(x: number, z: number): number;\n /** Nearest hit of a LOCAL ray on the drawn triangles (holes let it through), null on a miss.\n * Exact against what is rendered — the editor's brush and a host without physics pick with it. */\n raycast(origin: Vec3Like, dir: Vec3Like, maxDistance?: number): TerrainHit | null;\n /** `raycast` in WORLD space — through the node's transform (rotation + uniform scale). */\n raycastWorld(origin: Vec3Like, dir: Vec3Like, maxDistance?: number): TerrainHit | null;\n /** Write a rectangle of samples (`src` = w × h heights, row-major). */\n setHeights(x0: number, z0: number, w: number, h: number, src: ArrayLike<number>): this;\n /** Apply `fn(oldHeight, weight, x, z)` over a region; `weight` is 1 inside, fading to 0 over\n * `falloff` metres outside it. The building block of flatten / raise / hole. */\n shape(region: TerrainRegion, fn: (h: number, w: number, x: number, z: number) => number, falloff?: number): this;\n /** Flatten a region to `height` (a plateau / a building pad), blending over `falloff` metres. */\n flatten(region: TerrainRegion, height: number, opts?: {\n falloff?: number;\n }): this;\n /** Raise (or lower, negative) a region by `delta` metres, blending over `falloff` metres. */\n raise(region: TerrainRegion, delta: number, opts?: {\n falloff?: number;\n }): this;\n /** Copies of heights / holes / control — an undo point or a level reset. */\n snapshot(): TerrainSnapshot;\n /** Put a `snapshot()` back (same grid size) — everything marked dirty for the next `commit()`. */\n restore(s: TerrainSnapshot): this;\n /** One brush dab: raise / lower / smooth / flatten a disc of `radius` metres around (x, z), feathered\n * by `hardness` — the editor's sculpt tool and runtime deformation (craters, digging) share it. */\n sculpt(opts: SculptOptions): this;\n /** Cut a hole (no triangles, no collision, no navmesh) — or fill one back with `on = false`. */\n hole(region: TerrainRegion, on?: boolean): this;\n /**\n * Conform the ground to a mesh — the terrain takes the target's TOP surface minus `offset` under\n * its footprint (a road sits exactly on it, nothing pokes through), and blends back to the old\n * ground over `falloff` metres around it. `target` = a node (a Mesh, a Model, or a node holding\n * them — every triangle in the subtree counts), a Geometry in local coordinates, or a raw soup\n * (9 floats per triangle, local). Call again after the target moves.\n */\n conform(target: Node | Geometry | Float32Array, opts?: ConformOptions): this;\n /** `conform` to a ribbon along `points` (world/local metres, see `ribbon`) — the road stamp. */\n conformPath(points: readonly Vec3Like[], opts: ConformOptions & RibbonOptions): this;\n /**\n * A flat ribbon Geometry along a polyline (the road mesh AND the conform target): `width` metres,\n * vertices take the points' own Y, UV0 = (across 0…1, along / uvScale). Build it from heights you\n * sampled with `heightAt` and smoothed, then `Mesh.from(geometry, { material })` + `conform`.\n * It also carries a lightmap UV (uv1: along 0…1 × across 0…width/length — the strip's true aspect,\n * so `lecodes lightmap bake` gives it uniform texels), which makes the road a bake receiver.\n */\n static ribbon(points: readonly Vec3Like[], opts: RibbonOptions): Geometry;\n /** Write RGBA layer weights for a rectangle of samples (`rgba` = w × h × 4 bytes). */\n paint(x0: number, z0: number, w: number, h: number, rgba: ArrayLike<number>): this;\n /** Paint `layer` over a region with `strength` (0…1), feathered over `falloff` metres. */\n paintLayer(region: TerrainRegion, layer: number, strength?: number, falloff?: number): this;\n /** Paint the whole terrain from slope / height rules (grass on the flats, rock on cliffs, snow on\n * the peaks, dirt in the valleys) — the CPU pass a procedural level starts from. */\n paintAuto(rules?: AutoPaintRules): this;\n private _blendLayer;\n /** Push every pending edit to the engine: chunk renderables + the height-field collider for the\n * dirty rectangle, the control texture. Call once after a batch of edits. */\n commit(): this;\n set castShadows(v: boolean);\n get castShadows(): boolean;\n set receiveShadows(v: boolean);\n get receiveShadows(): boolean;\n /** The whole terrain as a `.terrain` file (LTER: heights quantised to 16 bits, holes, control). */\n serialize(): ArrayBuffer;\n /** Decode a `.terrain` file into create() options (heights back in metres). */\n static parse(buf: ArrayBuffer): {\n sizeX: number;\n sizeZ: number;\n cellSize: number;\n chunk: number;\n heights: Float32Array;\n holes: Uint8Array;\n control: Uint8Array;\n layers: TerrainLayer[];\n };\n private _build;\n private _buildFallbackChunk;\n private _rebuildFallbackChunks;\n private _applyShadows;\n private _uploadControl;\n private _applyLayers;\n /** Re-push layer scalars after editing `layers` (textures given as Texture apply too). */\n applyLayers(): Promise<void>;\n private _touch;\n private _touchControl;\n /** The sample rectangle a region (+ falloff) touches, or null when it misses the grid. */\n private _regionRect;\n /** Per-sample weights over `r`: 1 inside the region, smooth 1→0 across `falloff` metres outside. */\n private _regionWeights;\n /** World matrix of the node (column-major). */\n private _world;\n /** A target's triangles in the terrain's LOCAL frame, 9 floats per triangle. */\n private _triangles;\n}\n","types/gl/terrain/terrainMesh.d.ts":"import { Geometry } from \"../Geometry\";\nexport type TerrainGrid = {\n sizeX: number;\n sizeZ: number;\n cellSize: number;\n /** sizeX × sizeZ heights, row-major (z rows). */\n heights: Float32Array;\n /** One byte per sample, 1 = hole; null = no holes. */\n holes: Uint8Array | null;\n};\n/** The sample at integer (x, z), clamped to the grid. */\nexport declare const sampleAt: (g: TerrainGrid, x: number, z: number) => number;\nexport declare const isHole: (g: TerrainGrid, x: number, z: number) => boolean;\n/** Surface normal at a sample from central differences (one-sided at the borders). Writes `out` (xyz). */\nexport declare const normalAt: (g: TerrainGrid, x: number, z: number, out?: Float32Array | number[]) => typeof out;\n/**\n * Height at a LOCAL (x, z) in metres, interpolated on the drawn triangles (the i00–i11 diagonal), so a\n * character's feet and a raycast agree with what is rendered to the millimetre. NaN inside a hole\n * triangle or outside the grid.\n */\nexport declare const heightAt: (g: TerrainGrid, x: number, z: number) => number;\n/** The geometric normal at a LOCAL (x, z): the drawn triangle's normal (not the smoothed vertex one). */\nexport declare const faceNormalAt: (g: TerrainGrid, x: number, z: number, out?: Float32Array | number[]) => typeof out;\n/** Chunks along X and Z for a grid: a chunk covers `chunk` cells (chunk + 1 samples). */\nexport declare const chunkCounts: (g: TerrainGrid, chunk: number) => [number, number];\n/**\n * One chunk as a Geometry (positions, smooth normals, UV0 = local XZ metres, UV1 = the terrain's unit\n * square, u16 indices), or null when every cell of it is a hole.\n */\nexport declare const buildTerrainChunk: (g: TerrainGrid, cx: number, cz: number, chunk: number) => Geometry | null;\nexport type GridHit = {\n x: number;\n y: number;\n z: number;\n distance: number;\n nx: number;\n ny: number;\n nz: number;\n};\n/**\n * Nearest hit of a LOCAL ray (origin + direction, metres) on the drawn triangles — the same\n * i00–i11 split and hole rule as `heightAt`, so a pick lands on what is rendered. Walks the cells\n * the ray crosses (2D DDA on XZ), testing each cell's two triangles; holes let the ray through.\n * Null when it misses (or never enters the grid within `maxDistance`).\n */\nexport declare const gridRaycast: (g: TerrainGrid, ox: number, oy: number, oz: number, dx: number, dy: number, dz: number, maxDistance?: number) => GridHit | null;\n","types/gl/Texture.d.ts":"import { type FetchResponse, type File } from \"../runtime/fetch\";\n/** `Texture.load` options. */\nexport type TextureLoadOptions = {\n /** `true` (default): colour, stored sRGB. `false`: data (normal map, mask, heightmap) — kept linear. */\n srgb?: boolean;\n /** Ignore `Texture.maxSize` for this texture (a lightmap page, a lookup table). */\n fullSize?: boolean;\n};\nexport declare class Texture {\n static _maxSize: number;\n /** Engine-wide cap on texture size (a \"texture quality\" setting), 0 = none. A KTX2 wider or\n * taller than this loses its top mip levels on load (nothing resampled, less memory and\n * bandwidth), a glTF PNG/JPEG is downsampled. Reaches textures loaded AFTER it is set — a loaded\n * level keeps its textures — so set it up front (`SceneOptions.maxTextureSize`, or before the\n * level loads) and apply a menu change on the next level load. Lightmap pages are exempt\n * (`TextureLoadOptions.fullSize`). A host may pin it (desktop `CREATOR_TEXTURE_MAX_SIZE`). */\n static _anisotropy: number;\n /** Engine-wide anisotropic filtering, 1 (off) … 16 (default 2; `SceneOptions.anisotropy` sets it up\n * front). A sampler is baked when its texture is bound, so like `maxSize` this reaches textures\n * loaded AFTER it — set it before the level loads. Measured on a lightmapped interior at 720p:\n * 4× costs ~20 % of the frame over 1× on an integrated GPU. A host may pin it. */\n static get anisotropy(): number;\n static set anisotropy(level: number);\n static get maxSize(): number;\n static set maxSize(size: number);\n readonly width: number;\n readonly height: number;\n /** Horizontal wrap mode (U). */\n wrapS: number;\n /** Vertical wrap mode (V). */\n wrapT: number;\n constructor(width: number, height: number, id: Handle | number);\n static fromCanvas(canvas: {\n _bakeSurface(): number;\n width: number;\n height: number;\n pixelRatio: number;\n _tex3dId: number;\n }): Texture;\n /** A texture from raw pixels: `channels` (1–4, default 4) UBYTE per pixel, row-major, `width ×\n * height × channels` bytes; `srgb` (default true for colour) picks the sRGB internal format —\n * pass false for data (a heightmap, a mask). No mips. Throws on a host without the call. */\n static fromPixels(width: number, height: number, data: Uint8Array, opts?: {\n channels?: 1 | 2 | 3 | 4;\n srgb?: boolean;\n }): Texture;\n /** Re-upload a rectangle of a `fromPixels` texture (same channel count). */\n update(x: number, y: number, width: number, height: number, data: Uint8Array): void;\n /** Decode an image (PNG / JPG, or a KTX2 the core transcodes) into a texture. `srgb` (default\n * true) says the bytes are COLOUR, stored sRGB so the GPU linearises them on sample; pass\n * `false` for DATA — a normal map, a mask, a heightmap — which must come back as stored (a\n * flat normal read through sRGB bends by ~35°). A KTX2 decides by its own header. Image\n * textures get a mip chain (trilinear) on hosts that build one. */\n static load(source: string | FetchResponse | File, options?: TextureLoadOptions): Promise<Texture>;\n}\n","types/gl/touch.d.ts":"export declare const registerTouchStartEvent: () => void;\nexport declare const registerTouchEndEvent: () => void;\n","types/gl/vehicle/Vehicle.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { type QuatLike } from \"../../math/quat\";\nimport { Node } from \"../Node\";\nimport { Wheel, type Point } from \"./Wheel\";\n/** Which axle the engine drives — the default for every wheel's own `driven` share. */\nexport type DriveLayout = \"rear\" | \"front\" | \"all\" | \"none\";\n/**\n * How an axle's two wheels share torque.\n * - `lsd` — limited slip (Jolt's 1.4 ratio), the sane default.\n * - `open` — fully open: a lifted or spinning wheel takes ALL the torque.\n * - `locked` — both wheels forced to the same speed. Breaks traction predictably: the drift diff.\n * A number is the raw max/min wheel-speed ratio (> 1; smaller is more locked).\n */\nexport type DifferentialMode = \"lsd\" | \"open\" | \"locked\";\nexport interface EngineConfig {\n /** Peak torque in N·m (default 500). The single biggest \"how fast is it\" knob. */\n torque?: number;\n /** Redline in RPM (default 6000) — Jolt's own clamp; a rev limiter's stutter is the game's. */\n maxRpm?: number;\n /** Idle RPM (default 1000): the engine's floor. `0` = no floor — the engine can be dragged to a\n * standstill and stall, and holding idle (a governor), cranking it, are the game's to write. */\n idleRpm?: number;\n /**\n * The engine's CHARACTER: points `{ x, y }` in NORMALISED units — x a fraction of the redline, y a\n * fraction of `torque`, x ascending. Left out, Jolt's own broad curve is used.\n *\n * `[{ x: 0, y: 0.8 }, { x: 0.66, y: 1 }, { x: 1, y: 0.8 }]` is an ordinary petrol engine (peak two\n * thirds up, falling to the redline); `[{ x: 0, y: 1 }, { x: 1, y: 1 }]` is flat, an electric motor.\n */\n curve?: Point[];\n /** Moment of inertia in kg·m² (default 0.5) — how eagerly it revs when the clutch is out. */\n inertia?: number;\n /** Engine braking: angular damping of the engine itself (default 0.2). */\n braking?: number;\n}\n/**\n * The steering wheel as a BODY the tires push back on, simulated by the engine every sub-step. With\n * it, `steer` is where the driver's hands AIM the wheel and `steerForce` how firmly they hold it;\n * where the road wheels end up is physics:\n *\n * I·θ̈ = T_hand + T_align·(1 − powerSteering) + T_stop − (damping + endStop.damping·depth)·θ̇ − parkingFriction(v) − friction\n *\n * `T_align` is the tires' self-aligning torque (`steering.caster` / `trail` / `trailAtPeak` — the\n * same torque `steerTorque` reports without a feedback body, for a force-feedback wheel). `T_hand`\n * is the driver's arms, `steering.driver`. So: heavy at speed, light when the front lets go,\n * self-centring on release, and in a slide a let-go wheel swings into opposite lock by itself.\n * Without `feedback` there is no body: `steer` is the road wheels' angle as a fraction of `maxAngle`.\n */\nexport interface SteeringFeedback {\n /** Moment of inertia of wheel + column + rack about the axis, kg·m² (default 1). Heavier = slower\n * off the mark under the hands, but a wheel whipping into counter-steer carries further. */\n inertia?: number;\n /** Viscous damping, N·m·s/rad (default 25): what keeps a let-go wheel from ringing about centre. */\n damping?: number;\n /** The column's own dry friction, N·m, at any speed (default 8) — rack and bearings: the floor a\n * free wheel's spin decays against, and what keeps a let-go wheel from creeping under a small torque. */\n friction?: number;\n /** The contact patch's dry friction while (nearly) parked, N·m (default 40), fading out by 1.5 m/s\n * — why a parked car is hard to steer, and why a wheel left turned stays turned. */\n parkingFriction?: number;\n /** Power steering, 0..1 (default 0.5): the share of the tires' aligning torque the wheel never\n * sees. It is NOT a gain on the angle: 0 is a kart (heavy, full of feel, a held key gives up its\n * lock early at speed), 1 is a dead rim that neither centres nor counter-steers. */\n powerSteering?: number;\n /** The END STOP before the lock — rubber, not a wall (default `{ band: 16, torque: 120, damping: 150 }`):\n * over the last `band` degrees the rack pushes back toward centre with the SQUARE of the depth,\n * `torque` N·m at the lock, and damps by `damping` N·m·s/rad × depth. A wheel let go on the stop\n * eases back off it a few degrees; `band: 0` = the hard clamp only. */\n endStop?: {\n band?: number;\n torque?: number;\n damping?: number;\n };\n}\n/** The driver's ARMS on a `feedback` wheel — an actuator with numbers, because a stiff hand spring\n * has to be integrated with the column every sub-step. WHAT the hands do (aim, hold, let go) is\n * the game's, per frame, through `steer` and `steerForce`. */\nexport interface SteeringDriver {\n /** The most torque the hands can put on the wheel, N·m (default 130). The ceiling on how much lock\n * a held key keeps at speed against the tires' pull. */\n maxTorque?: number;\n /** How stiff the arms are, N·m/rad of the gap between where they aim and where the wheel is (default 500). */\n stiffness?: number;\n /** The fastest the hands turn the road wheels, deg/s (default 120): the hands cannot PUSH a wheel\n * that already outruns them, they can still hold and brake it; a let-go wheel is uncapped. */\n maxRate?: number;\n /** Seconds the hands' torque takes to build to `maxTorque` (default 0.1): muscles do not step. */\n rampTime?: number;\n}\nexport interface SteeringConfig {\n /** Steering lock in degrees (default 35): what `steer = ±1` means. */\n maxAngle?: number;\n /** The front axle's GEOMETRY, the source of the tires' self-aligning torque (`steerTorque`, and\n * what a `feedback` wheel is pushed by): the mechanical caster's trail, metres (default 0.03)… */\n caster?: number;\n /** …and the pneumatic trail, metres (default 0.025) — the patch's own lever, which collapses as the\n * tire reaches its peak slip angle (the steering going light when the front lets go)… */\n trail?: number;\n /** …to this fraction of itself at the peak (default 0.5). */\n trailAtPeak?: number;\n /** Simulate the steering wheel as a body the tires push back on (`SteeringFeedback`). `true` = the\n * defaults. Without it `steer` sets the road wheels' angle directly. */\n feedback?: boolean | SteeringFeedback;\n /** The driver's arms on a `feedback` wheel (`SteeringDriver`); the defaults without it. */\n driver?: SteeringDriver;\n}\n/**\n * Aerodynamics. Both numbers are quoted the same way — **a fraction of the car's own weight at\n * 30 m/s (108 km/h)** — and both grow with the SQUARE of speed from there, so `0.5` at 30 m/s is\n * `2.0` at 60 m/s. One mental model for both, and no drag coefficients or frontal areas to invent.\n */\nexport interface AeroConfig {\n /**\n * Downforce (default 0 — a car with no wing). The knob that decides whether a car corners better\n * or worse the faster it goes: tire grip is a constant, but the force a corner demands grows with\n * v², so with no downforce every car runs out of road at speed. `0.6` roughly doubles a car's\n * cornering at 150 km/h; a road car is nearer `0.1`, a race car well past `1`.\n *\n * It presses along the CHASSIS' own down axis (that is what keeps a car planted over a crest) and\n * only while a wheel is on the ground — a car on its roof is never launched by its own wing.\n */\n downforce?: number;\n /** Air resistance (default 0.03 — an ordinary car). What gives a car a top speed at all. */\n drag?: number;\n}\nexport declare class Vehicle extends Aspect<\"vehicle\", Node> {\n static readonly aspect = \"vehicle\";\n /** Chassis mass in kg (default 1200). Wheels are massless in this model. */\n mass: number;\n /** Centre of mass height in chassis space (metres, negative = lower). Left out, it drops to halfway\n * down the chassis shape — a car with its mass at the shape's centre tips over. */\n centerOfMass?: number;\n /** Which axle the engine drives (default \"rear\") — the default for every wheel's own `driven`\n * share: 1 on that axle, 0 elsewhere. `none` = no drive at all (a trailer, a pushed cart). */\n driveAxle: DriveLayout;\n /** Differential lock across each driven axle. `locked` is the drift setup — both wheels turn\n * together, so the pair lets go as a pair. Live: re-configure the aspect to switch it mid-drive. */\n differential: DifferentialMode | number;\n /**\n * Anti-roll bars between each axle's wheels — what stops a car rolling onto its inside wheels in a\n * fast corner. `true` (default) is a bar 0.01 as stiff as the wheel's own spring; a number is that\n * ratio directly, and `0` / `false` removes the bars.\n *\n * **The numbers are far smaller than they look and the gain is steep** — Jolt's bar feeds\n * `lengthDifference × stiffness × dt` as a bias into the suspension's own soft constraint, so 4%\n * of the spring already flattens the body. Measured on a 1250 kg car: `0` → 1.3° of roll at 0.86 g,\n * `0.01` → 0.6°, `0.15` → 0.2° (flat), `0.5` → the car HOPS.\n *\n * This is the knob for how much a car visibly LEANS, not for wheel lift: bars change how far the\n * body tips, not how much load transfers. For lift, lower `centerOfMass`.\n */\n antiRoll: boolean | number;\n /** Pitch/roll limit in degrees (default 60) before the constraint rights the car. 180 turns it off. */\n maxTilt: number;\n /** Friction of the CHASSIS body itself — how it slides when it lands on its roof or side. Nothing\n * to do with the tires; those are the `Wheel`'s `tire` × the ground's friction. */\n friction: number;\n /** Strength of the clutch when fully engaged (default 10). Small values slip; large ones weld the\n * engine to the wheels. `clutch` (the input) scales it 0..1. */\n clutchStrength: number;\n /** The clutch's torque CAPACITY, N·m (default 0 = none: Jolt's viscous clutch alone, torque =\n * `clutchStrength` × slip speed, no ceiling — rigid at any real slip). Set it and the clutch\n * SLIPS at this much torque × `clutch` — a dry clutch, emulated a physics step at a time: a\n * launch can be feathered, and a dumped clutch in too high a gear drags the engine down instead\n * of lurching. A road car's is ~1.5× the engine's peak torque. */\n clutchCapacity: number;\n engine: EngineConfig;\n steering: SteeringConfig;\n aero: AeroConfig;\n /** Scene-editor inspector: the flat, tunable half. The grouped objects are edited in code. */\n static fields: FieldMeta<Vehicle>;\n static editor: {\n rebuild: boolean;\n };\n /** Driver systems tick at the default 0, so their inputs land in the SAME early pass, before this flush. */\n protected updateOrder: number;\n private _id;\n private _bodyId;\n private _builtMass;\n private _wheels;\n private _state;\n private _stateFrame;\n private _throttle;\n private _steer;\n private _steerForce;\n private _ratio;\n private _clutch;\n private _input;\n private _sent;\n private _dirty;\n private _retunePending;\n onAttach(): void;\n onDetach(): void;\n /**\n * Re-configuring an attached vehicle retunes it in place — the way a drift button switches the\n * differential without the car so much as blinking:\n *\n * car.aspect(Vehicle, { differential: drift ? 'locked' : 'lsd' })\n *\n * Live: `differential`, `engine`, `steering`, `aero`, `maxTilt`, `friction`, `clutchStrength`,\n * `clutchCapacity`, `antiRoll` (its stiffness, on axles that have a bar), and every `Wheel`'s\n * `tire`. Everything else describes the car's STRUCTURE — `mass`, `centerOfMass`, which wheels\n * exist and where, their suspension, the driven shares — and is baked into the constraint at\n * attach; to change one of those, re-attach the aspect.\n */\n onReconfigure(): void;\n /** Native vehicle id (0 until attached / no physics support). */\n get id(): number;\n /** The chassis rigid body id (for `physicsApplyImpulse`-style calls). */\n get bodyId(): number;\n /** The wheels, front axle first, in the order the engine knows them. */\n get wheels(): readonly Wheel[];\n /** Throttle 0..1 — the engine's pedal. No sign: the direction is `ratio`'s. */\n get throttle(): number;\n set throttle(v: number);\n /** Steering −1..1. Without `steering.feedback`: the road wheels' angle as a fraction of `maxAngle`,\n * applied as is (a taper with speed, a rate limit, are the game's). With it: where the hands AIM\n * the wheel; the tires decide where the road wheels end up. */\n get steer(): number;\n set steer(v: number);\n /** How firmly the hands hold a `feedback` wheel, 0..1 (default 1): the hands' torque is capped at\n * `driver.maxTorque × steerForce`. 0 = let go — the tires alone have the wheel: back to centre in\n * a grip corner, into opposite lock in a slide. Ignored without a feedback wheel. */\n get steerForce(): number;\n set steerForce(v: number);\n /** The ONE gear ratio the engine runs (default 1): engine rpm = wheel rpm × ratio × the final\n * drive (3.42). The SIGN is the direction — negative is reverse — and 0 is neutral. */\n get ratio(): number;\n set ratio(v: number);\n /** Clutch engagement 0..1 (default 1 = home). 0 = out: the engine is free of the wheels. */\n get clutch(): number;\n set clutch(v: number);\n /**\n * EARLY phase: hand this frame's inputs to the engine, before the step. The vector is sent when\n * anything changed — and every frame while a throttle, steer or brake is non-zero, because that is\n * what keeps a driven car awake (an idle car with zero input sleeps). The pending re-tune (a\n * config or tire change) goes first, so the step runs on the new numbers.\n */\n protected updateBefore(): void;\n /** Teleport upright and clear all motion (velocity, engine rpm, wheel spin). Defaults to the\n * chassis node's current pose — `reset()` alone un-flips a car where it lies. The inputs are\n * kept and re-sent on the next early pass. */\n reset(position?: Vec3Like, rotation?: QuatLike): this;\n /** Push the chassis (a boost pad, an explosion) — an instantaneous impulse in kg·m/s. */\n applyImpulse(v: Vec3Like): this;\n private _read;\n /** Speed along the car's forward axis in m/s — negative when reversing (× 3.6 for km/h). */\n get speed(): number;\n /** Engine RPM. */\n get rpm(): number;\n /** How many wheels touch the ground this frame. */\n get wheelsOnGround(): number;\n /** At least one wheel on the ground. */\n get grounded(): boolean;\n /** Chassis velocity in world space, m/s. */\n get velocity(): Vec3;\n /** Chassis angular velocity in world space, rad/s. */\n get angularVelocity(): Vec3;\n /** How fast the car is turning about the vertical, in degrees per second — positive turning RIGHT\n * (the same sense as `steer`). The signal a counter-steer assist reads. */\n get yawRate(): number;\n /**\n * The car's slip angle in degrees: the angle between where the nose points and where the car is\n * actually travelling, positive when it is travelling to the RIGHT of the nose. 0 going straight,\n * ±180 backing up, and past ~10° the rear has stepped out — a drift.\n */\n get slipAngle(): number;\n /**\n * The angle of the SLIDE, degrees, signed like `slipAngle` (positive = travelling to the right of\n * the nose), −180..180: the angle between the car's axis and where its REAR AXLE travels — the\n * mean of the non-steering wheels (every wheel if all of them steer), its velocity from the\n * body's velocity and spin. Unlike `slipAngle` (the body's, at its centre) this is 0 on a clean\n * corner at ANY speed: at walking pace and full lock the body already travels ~20° off its nose\n * while the rear axle rolls straight along it. It is the rear stepping out — what a gyro comes in\n * on, and what a drift meter should show — and unlike the tires' own `Wheel.slipAngle` it does\n * not fold at 90°: a backward entry reads 110°, not 70°. The axis it is measured from is the one\n * the DRIVETRAIN pushes along — the nose for a positive `ratio`, the tail for a negative one — so\n * honest reversing reads 0, and a car spun round in a forward gear reads past 90°. 0 at a\n * standstill: with no speed a direction is noise, so it fades in over walking pace,\n * `DRIFT_SPEED_FROM`..`DRIFT_SPEED_FULL` of the axle's ground speed.\n */\n get driftAngle(): number;\n /** Where the steered wheels actually are, in degrees, right-positive: the angle `steer` set, or\n * with `steering.feedback` where the column has come to. */\n get steerAngle(): number;\n /** The tires' self-aligning torque on the steering, N·m, positive = it pulls the wheel to the\n * RIGHT — what the driver feels: heavy at speed, light when the front lets go, and the\n * counter-steer in a slide. Reported with or without a `feedback` wheel: the signal a\n * force-feedback steering wheel is driven by. */\n get steerTorque(): number;\n /** Every Wheel under the chassis, ordered front axle first, with its axle group resolved. */\n private _collectWheels;\n /** Pack the whole configuration into the one blob the host ABI takes (see bridges.d.ts). */\n private _buildSettings;\n /** Edit mode: which way the chassis faces. Each wheel draws its own circle and travel range — see\n * `Wheel.rebuild()`. Play mode never calls this. */\n rebuild(): void;\n}\n","types/gl/vehicle/Wheel.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3 } from \"../../math/vec\";\nimport { Node } from \"../Node\";\n/** Floats `vehicleGetState` writes before the per-wheel block: speed, rpm, contacts, vx, vy, vz, wx, wy, wz,\n * steerDeg, steerTorque. */\nexport declare const STATE_HEADER = 11;\n/** Floats per wheel: contact, slip, slipAngle, suspensionLength, steerDeg, spin, fLat, fLong, vLat, vSlip, load. */\nexport declare const WHEEL_STATE = 11;\n/** Fully compressed = this fraction of `travel` (the engine's one suspension constant, mirrored here\n * so `compression` and the resting-height maths read the same number). */\nexport declare const SUSPENSION_MIN_FRACTION = 0.4;\n/** A point on a curve — a tire's friction over slip, an engine's torque over rpm. */\nexport type Point = {\n x: number;\n y: number;\n};\nexport interface WheelSuspension {\n /** Total travel in metres, full droop to fully compressed (default 0.4). */\n travel?: number;\n /** Spring frequency in Hz — bigger is stiffer (default 1.4; a race car ~2.5, a truck ~1). It also\n * sets the ride-height sag, and the sag is how far the wheel can still extend DOWN. */\n stiffness?: number;\n /** Damping ratio 0..1 (default 0.5). Low values pogo. */\n damping?: number;\n}\n/**\n * A tire, as the engine takes it: two friction curves and two numbers. `Tire.road()` and the other\n * presets are starting points — copy one and edit, or `Tire.scale()` it.\n */\nexport interface Tire {\n /** Lateral friction over slip ANGLE: `{ x: degrees, y: friction }`, x ascending. Friction is the\n * coefficient the tire's load is multiplied by; the last value holds to 90°. The grip a wheel\n * actually gets is combined with the ground it stands on as `sqrt(tire × groundFriction)`, and a\n * body's friction defaults to 0.6 — a road a car should really corner on wants `Physics { friction: 1 }`. */\n side: Point[];\n /** Longitudinal friction over slip RATIO: `{ x: ratio, y: friction }` (0 = rolling in sync, 1 =\n * locked or spinning freely). */\n forward: Point[];\n /** The longitudinal impulse clamp as a multiple of `friction × load` — for DRIVE only; a braking\n * wheel is always clamped at the physical limit (or a locked rear would stop the car at a full g\n * and kill every handbrake turn). `1` is the physical tire; `road`'s 10 is Jolt's own sample\n * value (it keeps a driven wheel from ever spinning up). Anything a friction circle should bite\n * on wants this near 1. */\n traction?: number;\n /** Friction circle, 0..1: how much of the lateral capacity the longitudinal impulse in use takes\n * away. `0` = the two axes independent (a spinning wheel corners as well as a rolling one);\n * `1` = the full circle — wheelspin or a locked wheel lets go sideways. */\n circle?: number;\n}\n/**\n * Tire presets — fresh point lists every call (editing one never touches another), and `scale`.\n *\n * - `road` — Jolt's stock tire: lateral peak 1.2 at 3° falling to 1.0 by 20° and flat after, the\n * two axes independent, and the longitudinal clamp ×10 (Jolt's own sample runs this; it means a\n * driven wheel practically never spins up). Grippy, glued, hard to unsettle.\n * - `arcade` — the peak held all the way out on both axes: the car does not let go at all.\n * - `drift` — a tire that can be held sideways: lateral grip falls to 0.7 past 25°, the longitudinal\n * clamp is near the physical one (`traction: 2` — a launch at exactly 1 is a 0.4 g crawl; 2 keeps\n * it punchy) so the rear can be spun up, and a friction circle (`circle: 0.85` — most of it, so a\n * spinning rear loses most but not all of its lateral grip and the slide stays progressive):\n * power oversteer, and a slide the throttle keeps alive. A 600 N·m car lights its tires off the\n * line on it; that is the tire, and a traction control is the game's.\n */\nexport declare const Tire: {\n road: () => Tire;\n arcade: () => Tire;\n drift: () => Tire;\n /** Both curves multiplied by `k` — a grip slider, a cold tire, a wet road. A new tire; `t` is untouched. */\n scale: (t: Tire, k: number) => Tire;\n};\nexport declare function resolveTire(tire: Tire): ResolvedTire;\nexport declare class Wheel extends Aspect<\"wheel\", Node> {\n static readonly aspect = \"wheel\";\n /** Wheel radius in metres. Default: measured from the node's rendered bounds, else 0.35. Too small\n * and the car scrapes, too large and it floats. */\n radius?: number;\n /** Wheel width in metres. Default: measured, else 0.25. */\n width?: number;\n /** Axle group, front to back. Default: derived from Z. Set it for a car whose wheels are not in neat\n * left/right pairs — an axle's wheels are paired for the differential and the anti-roll bar. */\n axle?: number;\n /** Does this wheel steer? Default: the wheels on the front axle. */\n steer?: boolean;\n /** This wheel's SHARE of the engine's torque, 0 = not driven. Default: from the vehicle's\n * `driveAxle` (1 on that axle). An axle's share is the sum of its two wheels', the left/right\n * split their ratio, so `0.6` / `0.4` front-to-rear is `driven: 0.3` on each front wheel and\n * `0.2` on each rear. Structural: baked at attach. */\n driven?: number;\n suspension: WheelSuspension;\n /** The tire (default `Tire.road()`). Live: re-assign it or re-configure the aspect and the car\n * retunes in place — a grip slider, a tire that heats up. */\n tire: Tire;\n /** INPUT: brake torque on this wheel THIS frame, N·m (default 0). Sticky, like `Vehicle.throttle`:\n * write it every frame from a driver system's `updateBefore` — the foot brake's share, the\n * handbrake's 4500 on a rear wheel, an ABS's pulses — and the same physics step applies it. A\n * braking wheel is clamped at the physical tire limit (the `traction` boost is for drive only). */\n brake: number;\n /** Scene-editor inspector. `steer` / `driven` are deliberately absent: they are tri-state\n * (undefined = derive it from the axle), which a slider cannot express. */\n static fields: FieldMeta<Wheel>;\n static editor: {\n rebuild: boolean;\n };\n onDetach(): void;\n /** Re-configuring a wheel on a live car retunes the car: the tire is live; size, suspension, the\n * driven share and the axle are structural (re-attach the Vehicle). */\n onReconfigure(): void;\n private _state;\n /** Touching the ground this step. */\n get contact(): boolean;\n /** Longitudinal slip RATIO, signed: 0 = rolling in sync with the ground, towards +1 = spinning up\n * (wheelspin), towards −1 = locking under braking — whichever way the car travels. Smoke, tire\n * marks, wheelspin sound and traction control key off this. */\n get slip(): number;\n /** Slip ANGLE in degrees, signed: how far the tire's travel direction is off from where it points,\n * positive when the contact patch slides to the tire's RIGHT. Past the curve's peak (~3°) the tire\n * is letting go sideways. */\n get slipAngle(): number;\n /** This wheel's steer angle in degrees, right-positive. */\n get steerAngle(): number;\n /** Wheel spin in rad/s (× radius ≈ the speed the tire is laying down). Forward-positive; a model\n * turns about the right-hand axle by MINUS the integrated angle. */\n get spin(): number;\n /** The tire's lateral force this step, N, positive toward the tire's right — the road pushing the\n * patch back against its slide. */\n get sideForce(): number;\n /** The tire's longitudinal force this step, N, positive pushing the car forward. */\n get forwardForce(): number;\n /** How fast the contact patch slides sideways, m/s, positive to the tire's right. */\n get sideSlipSpeed(): number;\n /** How fast the tread runs over the road, m/s, positive spinning up, negative locking. Force ×\n * sliding speed (`|sideForce × sideSlipSpeed| + |forwardForce × slipSpeed|`) is the friction's\n * heat into the tread, W — a tire-temperature model integrates it. */\n get slipSpeed(): number;\n /** The suspension's force on the wheel this step, N — the tire's LOAD (0 in the air). What a\n * friction budget divides by: `hypot(sideForce, forwardForce) / (load × μ)`. */\n get load(): number;\n /** Suspension compression, 0 = fully extended (drooping) … 1 = fully compressed. */\n get compression(): number;\n /** Where the wheel's centre is right now, in CHASSIS space: the suspension's attachment point,\n * down by however far it hangs this step. Put a wheel model here (see the file header). */\n get position(): Vec3;\n /** Edit mode: this wheel's own circle at its resting height, its travel range, and a mark when the\n * engine drives it — enough to place a wheel without running the game. */\n rebuild(): void;\n}\n","types/inject.d.ts":"export { Mathf } from \"./math/Mathf\";\nexport { Vec2, Vec3 } from \"./math/vec\";\nexport { Quat } from \"./math/quat\";\nexport { Mat4 } from \"./math/mat4\";\nexport { Color } from \"./core/color\";\nexport { Aspect, System, type With, type SystemHost } from \"./core/Aspect\";\nexport { type EventMap } from \"./core/events\";\nexport { Time } from \"./core/time\";\nexport { StateMachine, defineStates, type StateDef, type StatesDef, type StateGuard, type StateHandler, type StateMachineEvents } from \"./core/StateMachine\";\nexport { InspectorUI } from \"./core/InspectorUI\";\nexport { signal, computed, effect, type Signal, type Computed } from \"./core/signals\";\nexport { __compWrite, __compOp, type CompAxis, type CompWriter } from \"./core/compWrite\";\nexport { Canvas, Bitmap } from \"./canvas/Canvas\";\nexport { toast, openURL, SvgSource } from \"./runtime/misc\";\nexport { app, type AppState, type OrientationLock } from \"./runtime/app\";\nexport { clipboard } from \"./runtime/clipboard\";\nexport { date, type DateValue, type DateInput, type Unit, type Locale } from \"./runtime/datetime\";\nexport { fetch, fetchLocal, FormData, File, type FetchResponse } from \"./runtime/fetch\";\nexport { localStorage } from \"./runtime/storage\";\nexport { device, type HapticStyle, type MotionOptions } from \"./runtime/device\";\nexport { Input, InputChannel, type InputKeyEvent, type InputGamepadEvent, type InputEventName, type GamepadState, type GamepadAxisName } from \"./runtime/input\";\nexport { WebSocket } from \"./runtime/net\";\nexport { Net, NetPlayer, Replicated, NetEntity, type NetMessage, type NetRole, type NetStatus, type NetEvents, type NetLaunch, type NetInput, type NetKind, type NetTransform, type NetCorrection } from \"./net\";\nexport { __rpc, __channel, __serverOnly, RpcError } from \"./runtime/rpc\";\nexport type { ChannelSubscription } from \"./server/channel\";\nexport type { StoredFile, StoredImage } from \"./server/files/models\";\nexport { AudioPlayer, VideoPlayer } from \"./runtime/media\";\nexport { Sound, type SoundOptions } from \"./audio/Sound\";\nexport { Voice, type VoiceEvents } from \"./audio/Voice\";\nexport { Bus, REVERB_PRESETS, type ReverbPreset, type ReverbParams, type EchoParams } from \"./audio/Bus\";\nexport { audio, type PlaySoundOptions, type SpatialOptions, type Rolloff, type AudioStats } from \"./audio/audio\";\nexport { openFilePicker, files, type FileData } from \"./runtime/files\";\nexport { share } from \"./runtime/share\";\nexport { ClickEvent, TouchStartEvent, LongPressEvent, MouseEnterEvent } from \"./runtime/touch\";\nexport { Scene2D } from \"./g2/Scene2D\";\nexport { Node2D } from \"./g2/Node2D\";\nexport { Camera2D } from \"./g2/Camera2D\";\nexport { Sprite } from \"./g2/Sprite\";\nexport { SpriteAnimation } from \"./g2/SpriteAnimation\";\nexport { Shape2D } from \"./g2/Shape2D\";\nexport { Physics2D } from \"./g2/Physics2D\";\nexport { Trigger2D } from \"./g2/Trigger2D\";\nexport { CharacterController2D } from \"./g2/CharacterController2D\";\nexport { OneWay2D } from \"./g2/OneWay2D\";\nexport { PhysicsGroup2D } from \"./g2/groups2d\";\nexport { Tilemap } from \"./g2/Tilemap\";\nexport { Texture2D } from \"./g2/Texture2D\";\nexport { SpriteSheet, defineSpriteSheet } from \"./g2/SpriteSheet\";\nexport type { SpriteSheetDef, SheetSprite, SpriteMakeOptions } from \"./g2/SpriteSheet\";\nexport { Tileset, defineTileset, Autotile2D } from \"./g2/Tileset\";\nexport { rawCell, isRawCell, rawIndex } from \"./g2/autotile\";\nexport { rot90, rot180, rot270, flipX, packTile, tileIndex, tileTurns, tileFlip, tileOriented } from \"./g2/autotile\";\nexport type { TilesetDef, TileMaterial, PatchMaterial, PathMaterial, PatchSlots, EdgeSlot, FillBlock, BlockEntry, TileBlock, TilePart, } from \"./g2/autotile\";\nexport { defineScene2d, Scene2dHandle } from \"./g2/defineScene2d\";\nexport type { Scene2dDef, Scene2dNodeDef, Scene2dEnv, SpriteSourceDef, TilemapSourceDef, Camera2dNodeDef, LoadedScene2d } from \"./g2/defineScene2d\";\nexport { cells, encodeCells, type CellsData } from \"./g2/cells\";\nexport { CameraFollow } from \"./g2/scenarios2d\";\nexport { UIScreen, type UIScreenStyle, UIRow, UIColumn, UIBox, type UIContainerStyle, UIText, type UITextStyle, UIButton, type UIButtonStyle, UIImage, type UIImageStyle, UIVideo, type UIVideoStyle, UIInput, UITextArea, type UIInputStyle, UIScrollable, type UIScrollableStyle, UIPager, type UIPagerStyle, UITabs, type UITabDef, defineTabs, type TabDef, type TabsHandle, UIWidget, type UIWidgetStyle, UIOverlay, type UIWidgetContent, UIModal, type UIModalStyle, UIBottomSheet, type UIBottomSheetStyle, UIPopover, type UIPopoverStyle, UISpacer, type UISpacerStyle, UIVirtualizedList, Router, NativeView, type UINativeViewStyle, registerFont, __uiMap, __UIColumn, __UIRow, __UIBox, __UIButton, __UIScreen, __UIScrollable, __UIWidget, } from \"./ui/UI\";\nexport { Presentable } from \"./ui/UI\";\nexport type { DismissOptions, PresentOptions, Transition, TransitionName, TransitionPose, TransitionSpec } from \"./ui/UI\";\nexport type { UINode, UINodeChild } from \"./ui/UINode\";\nexport { theme, type ThemeValues, type ThemeAccessors, type ThemeRoles } from \"./ui/theme\";\nexport { animate, type AnimateOptions, type AnimateValue, type AnimateOut } from \"./animate/tween/animateValue\";\nexport { cubicBezier } from \"./animate/bezier\";\nexport { Timeline, type TimelineOptions, type TimelineAddOptions, type TimelinePosition } from \"./animate/tween/Timeline\";\nexport { type Animation } from \"./animate/tween/Animation\";\nexport { type TweenMeta } from \"./animate/tween/spec\";\nexport { type EasingInput } from \"./animate/tween/easing\";\nexport { easeIn, easeOut, easeInOut } from \"./animate/easings\";\nexport { QRScanner } from \"./plugins/gen/qr-scanner/sdk/qr-scanner\";\nexport { CameraView, type CameraFacing } from \"./plugins/gen/camera/sdk/camera\";\nexport { Geolocation, type GeoPosition, type GeoOptions, type GeoWatch } from \"./plugins/gen/geolocation/sdk/geolocation\";\nexport { MapView, type MapOptions, type MapStyle, type MapStyleName, type MapCamera, type MapTap, type LngLat, type CameraMove, type FitOptions, type MapPaddingValues, type MarkerItem, type MarkerTap, type MarkerLayer, type MarkerLayerOptions, type LineLayer, type LineLayerOptions, type UserLocationOptions, } from \"./plugins/gen/map/sdk/map\";\nexport { Push, type PushPayload, type PushStatus, type PushRegisterOptions, type PushEvent } from \"./plugins/gen/push/sdk/push\";\nexport { Service } from \"./plugins/service\";\nexport { defineScene, use, ref, make, SceneHandle } from \"./scene/defineScene\";\nexport { defineMaterial, MaterialHandle } from \"./scene/material\";\nexport type { MaterialData, MaterialParamValue, ShaderMaterialDef, LitMaterialDef, UnlitMaterialDef } from \"./scene/material\";\nexport type { SceneDef, SceneNodeDef, MeshDef, LightDef, MaterialDef, CameraNodeDef, AspectEntry, MakeEntry, LoadedScene, SceneInstance } from \"./scene/defineScene\";\nexport { CameraPlace } from \"./gl/CameraPlace\";\nexport { Level } from \"./scene/level\";\nexport type { LevelSpot, LevelBuild, LevelCollider, LevelLineOptions, LevelGridOptions, LevelRingOptions, LevelScatterOptions, LevelPlaceOptions } from \"./scene/level\";\nexport type { FieldMeta } from \"./core/fields\";\nexport { Gizmos } from \"./scene/gizmos\";\nexport type { GizmoStyle, GizmoAnchor } from \"./scene/gizmos\";\nexport { MoveTo, FollowPath, Spin, LookAt, PlayAnimation } from \"./gl/scenarios\";\nexport { registerEditorWindow, registerEditorTool } from \"./scene/editorPlugins\";\nexport type { EditorApi, EditorRayHit, EditorToolHooks, EditorWindowFn } from \"./scene/editorPlugins\";\nexport { Scene, ARScene, VRScene } from \"./gl/Scene\";\nexport { Node } from \"./gl/Node\";\nexport { Mesh } from \"./gl/Mesh\";\nexport { Model } from \"./gl/Model\";\nexport { Shape } from \"./gl/physics/Shape\";\nexport { Physics } from \"./gl/physics/Physics\";\nexport { Trigger } from \"./gl/physics/Trigger\";\nexport { AudioSource, type AudioCone } from \"./gl/audio/AudioSource\";\nexport { AudioZone } from \"./gl/audio/AudioZone\";\nexport { SceneAudio } from \"./gl/audio/SceneAudio\";\nexport { CharacterController } from \"./gl/physics/CharacterController\";\nexport { Vehicle } from \"./gl/vehicle/Vehicle\";\nexport type { DriveLayout, DifferentialMode, EngineConfig, SteeringConfig, SteeringFeedback, SteeringDriver, AeroConfig } from \"./gl/vehicle/Vehicle\";\nexport { Wheel, Tire, resolveTire } from \"./gl/vehicle/Wheel\";\nexport { Ragdoll } from \"./gl/physics/Ragdoll\";\nexport type { RagdollPart, RagdollHinge, RagdollFacing, RagdollActivateOptions, RagdollDeactivateOptions, RagdollHitOptions } from \"./gl/physics/Ragdoll\";\nexport type { Point, WheelSuspension } from \"./gl/vehicle/Wheel\";\nexport { AnimationClip } from \"./gl/animation/AnimationClip\";\nexport type { ClipDef, ClipTrackDef, ClipKey } from \"./gl/animation/AnimationClip\";\nexport { Animator } from \"./gl/animation/Animator\";\nexport type { LodMode } from \"./gl/animation/Animator\";\nexport type { TrianglePick } from \"./gl/Model\";\nexport { Feet } from \"./gl/animation/Feet\";\nexport type { FeetOptions, FootState } from \"./gl/animation/Feet\";\nexport { Warp } from \"./gl/animation/Warp\";\nexport type { WarpOptions, StepWarpOptions } from \"./gl/animation/Warp\";\nexport { Playback } from \"./gl/animation/Playback\";\nexport { Loop } from \"./gl/animation/Loop\";\nexport { Layer } from \"./gl/animation/Layer\";\nexport type { PlayOptions, StopOptions, LayerOptions, LoopOptions, LoopDef, BlendPosition, BlendMember, ActiveClip, ClipInfo, ClipCycle, ClipAlign, KneeAxisReport, StepHandler, ClipEventHandler } from \"./gl/animation/core\";\nexport { IK } from \"./gl/animation/IK\";\nexport { DynamicBone, DynamicBoneCollider } from \"./gl/animation/DynamicBone\";\nexport type { DynamicBoneCurve, DynamicBoneFloor, DynamicBoneColliders } from \"./gl/animation/DynamicBone\";\nexport type { IKTwoBone, IKLookAt } from \"./gl/animation/IK\";\nexport { Light } from \"./gl/Light\";\nexport { Lightmap } from \"./gl/Lightmap\";\nexport { Foliage } from \"./gl/Foliage\";\nexport type { FoliageOptions, FoliageWind } from \"./gl/Foliage\";\nexport { Terrain } from \"./gl/terrain/Terrain\";\nexport type { TerrainOptions, TerrainLayer, TerrainRegion, ConformOptions, RibbonOptions, AutoPaintRules, SculptOptions, TerrainHit, TerrainSnapshot } from \"./gl/terrain/Terrain\";\nexport { NavMesh, NavCrowd } from \"./gl/nav/NavMesh\";\nexport type { NavMeshLoadOptions, NavMeshInfo, NavPath, NavQueryOptions, NavRaycastHit, NavAgentSize } from \"./gl/nav/NavMesh\";\nexport { NavAgent } from \"./gl/nav/NavAgent\";\nexport type { NavAgentState, NavAgentAvoidance, NavAgentDrive, NavAgentEvents } from \"./gl/nav/NavAgent\";\nexport { Locomotion } from \"./gl/animation/Locomotion\";\nexport type { LocomotionSet, LocomotionClip, LocomotionTuning, LocomotionState, LocomotionEvents, Displacement, Gait } from \"./gl/animation/Locomotion\";\nexport { Material } from \"./gl/Material\";\nexport { Geometry } from \"./gl/Geometry\";\nexport { InstancedMesh } from \"./gl/InstancedMesh\";\nexport type { InstanceTransform } from \"./gl/InstancedMesh\";\nexport { Texture } from \"./gl/Texture\";\nexport type { TextureLoadOptions } from \"./gl/Texture\";\nexport { Camera } from \"./gl/Camera\";\nexport { Ray } from \"./gl/Ray\";\nexport { Plane } from \"./gl/Plane\";\nexport { Noise } from \"./gl/Noise\";\nexport { Particles, Trail, curve, colorCurve } from \"./gl/Particles\";\nexport { DecalSet, DecalTrail } from \"./gl/DecalSet\";\nexport type { DecalOptions, DecalSetOptions, DecalSpawnOptions, DecalPlacement, DecalTrailOptions } from \"./gl/DecalSet\";\n","types/inject.editor.d.ts":"export { sceneEditor as __sceneEditor, type SceneEditorApi } from \"./scene/editor\";\n","types/math/mat4.d.ts":"import { Vec3, type Vec3Like } from \"./vec\";\nimport { Quat, type QuatLike, type EulerOrder } from \"./quat\";\nexport type Mat4Like = Mat4 | number[] | Float32Array | readonly number[];\nexport declare class Mat4 {\n /** The raw column-major elements (length 16). Public on purpose — read/write directly when you want\n * the metal: `mat.m[12] += vx * dt`. The fluent methods never mutate it (they return a new Mat4). */\n m: number[];\n constructor(src?: Mat4Like);\n set(values: ArrayLike<number>): this;\n copy(src: Mat4Like): this;\n /** `this · b` (apply `b` first in local space, then `this`). */\n mul(b: Mat4Like): Mat4;\n /** `b · this` — multiply on the other side (apply `this` first, then `b`). */\n premul(b: Mat4Like): Mat4;\n invert(): Mat4;\n transpose(): Mat4;\n determinant(): number;\n /** `this · translate(v)`. */\n translate(v: Vec3Like): Mat4;\n /** `this · scale(v)`. Accepts a vector or a uniform scalar. */\n scale(v: Vec3Like | number): Mat4;\n /** `this · rotate(axis, rad)`. */\n rotate(rad: number, axis: Vec3Like): Mat4;\n rotateX(rad: number): Mat4;\n rotateY(rad: number): Mat4;\n rotateZ(rad: number): Mat4;\n /** Transform a point (applies translation + perspective divide). */\n transformPoint(v: Vec3Like): Vec3;\n /** Transform a direction (rotation/scale only — no translation, no divide). */\n transformDirection(v: Vec3Like): Vec3;\n get position(): Vec3;\n get scaling(): Vec3;\n get rotation(): Quat;\n get eulerAngles(): Vec3;\n toEuler(order?: EulerOrder): Vec3;\n /** `{ position, rotation, scale }` in one shot. */\n decompose(): {\n position: Vec3;\n rotation: Quat;\n scale: Vec3;\n };\n /** Column basis vectors (the local X / Y / Z axes in world space). */\n get basisX(): Vec3;\n get basisY(): Vec3;\n get basisZ(): Vec3;\n clone(): Mat4;\n toArray(): number[];\n toFloat32Array(): Float32Array;\n equals(b: Mat4Like, eps?: number): boolean;\n static identity(): Mat4;\n static from(src: Mat4Like): Mat4;\n /** Translation · Rotation · Scale into one matrix. `scale` defaults to 1 and accepts a scalar. */\n static compose(position: Vec3Like, rotation: QuatLike, scale?: Vec3Like | number): Mat4;\n static fromQuat(q: QuatLike): Mat4;\n static fromTranslation(v: Vec3Like): Mat4;\n static fromScale(v: Vec3Like | number): Mat4;\n static fromEuler(x: number, y: number, z: number, order?: EulerOrder): Mat4;\n /** A view matrix that looks from `eye` toward `center` with `up`. */\n static lookAt(eye: Vec3Like, center: Vec3Like, up?: Vec3Like): Mat4;\n /** A world matrix that places something at `eye` oriented to look at `target`. */\n static targetTo(eye: Vec3Like, target: Vec3Like, up?: Vec3Like): Mat4;\n /** Perspective projection (WebGL/OpenGL clip, NDC z ∈ [−1, 1]). `fovy` is in RADIANS. */\n static perspective(fovy: number, aspect: number, near: number, far: number): Mat4;\n /** Orthographic projection (WebGL/OpenGL clip, NDC z ∈ [−1, 1]). */\n static ortho(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4;\n}\n","types/math/Mathf.d.ts":"export type Damper<T extends number | number[]> = ((target: T, dt: number) => T) & {\n /** Snap the damper's internal current value (e.g. on teleport). */\n setValue(value: T): void;\n};\ndeclare function smoothDamp(initial: number, smoothTime: number, maxSpeed?: number): Damper<number>;\ndeclare function smoothDamp(initial: number[], smoothTime: number, maxSpeed?: number): Damper<number[]>;\nexport declare const Mathf: {\n PI: number;\n TAU: number;\n EPSILON: number;\n DEG2RAD: number;\n RAD2DEG: number;\n deg2rad: (deg: number) => number;\n rad2deg: (rad: number) => number;\n clamp: (v: number, min: number, max: number) => number;\n clamp01: (v: number) => number;\n lerp: (a: number, b: number, t: number) => number;\n inverseLerp: (a: number, b: number, v: number) => number;\n remap: (v: number, inMin: number, inMax: number, outMin: number, outMax: number) => number;\n /** Move `a` toward `b` by at most `maxDelta`. */\n moveTowards: (a: number, b: number, maxDelta: number) => number;\n /** Frame-rate-independent exponential approach (good default: lambda 5..15). */\n damp: (a: number, b: number, lambda: number, dt: number) => number;\n sign: (x: number) => number;\n /** Loop a value into [0, length). */\n repeat: (t: number, length: number) => number;\n /** Ping-pong a value in [0, length]. */\n pingPong: (t: number, length: number) => number;\n random: (min?: number, max?: number) => number;\n randomInt: (min: number, max: number) => number;\n /**\n * Critically-damped follow (Unity SmoothDamp). Returns a stateful damper you call every frame:\n * const d = Mathf.smoothDamp([x, y], 0.15)\n * pos = d(targetPos, dt)\n * Works on a number or a numeric array (vec2 / vec3).\n */\n smoothDamp: typeof smoothDamp;\n};\nexport {};\n","types/math/quat.d.ts":"import { Vec3, type Vec3Like } from \"./vec\";\nexport type QuatLike = Quat | readonly [number, number, number, number] | number[] | Float32Array;\nexport type EulerOrder = \"XYZ\" | \"YXZ\" | \"ZXY\" | \"ZYX\" | \"YZX\" | \"XZY\";\n/** Read the w / 4th component of any quaternion-like (wrapper `.w`, or array-like `[3]`). */\nexport declare const cw: (q: {\n w?: number;\n} | ArrayLike<number>) => number;\nexport declare class Quat {\n x: number;\n y: number;\n z: number;\n w: number;\n constructor(x?: number | QuatLike, y?: number, z?: number, w?: number);\n set(x: number, y: number, z: number, w: number): this;\n copy(q: QuatLike): this;\n /** Hamilton product `this ⊗ b` (apply `b` first, then `this`). */\n mul(b: QuatLike): Quat;\n normalize(): Quat;\n conjugate(): Quat;\n /** Inverse rotation. For a unit quaternion this equals `conjugate()`. */\n invert(): Quat;\n dot(b: QuatLike): number;\n /** Spherical interpolation toward `b` by `t ∈ [0, 1]`. */\n slerp(b: QuatLike, t: number): Quat;\n /** Angular distance (radians) between two unit quaternions. */\n angle(b: QuatLike): number;\n /** Rotate a vector by this quaternion → a new `Vec3`. */\n rotateVec3(v: Vec3Like): Vec3;\n /** Extract euler angles (DEGREES) in the given order. */\n toEuler(order?: EulerOrder): Vec3;\n equals(b: QuatLike, eps?: number): boolean;\n /** True if the two unit quaternions represent the same rotation (±q are equal). */\n sameRotation(b: QuatLike, eps?: number): boolean;\n clone(): Quat;\n toArray(): [number, number, number, number];\n [Symbol.iterator](): Iterator<number>;\n static from(q: QuatLike): Quat;\n static get identity(): Quat;\n /** From euler angles in DEGREES (default order \"YXZ\"). Inverts `toEuler`. */\n static fromEuler(x: number, y: number, z: number, order?: EulerOrder): Quat;\n /** From a rotation `axis` and an angle in RADIANS. The axis is normalized for you. */\n static fromAxisAngle(axis: Vec3Like, rad: number): Quat;\n /** The shortest rotation that takes direction `a` onto direction `b`. */\n static fromTo(a: Vec3Like, b: Vec3Like): Quat;\n /** A rotation whose forward (−Z) points along `forward`, with `up` as the reference up axis. */\n static lookRotation(forward: Vec3Like, up?: Vec3Like): Quat;\n}\n/** Quaternion from a column-major rotation matrix (≥3×3, indices 0,1,2,4,5,6,8,9,10). gl-matrix's\n * `getRotation` algorithm — the exact inverse of building a matrix from a quaternion. */\nexport declare const quatFromColMajor: (m: ArrayLike<number>) => Quat;\n/** Euler angles (DEGREES) from a column-major rotation matrix, standard three.js extraction.\n * Element naming follows the column-major layout: mRC = m[(C-1)*4 + (R-1)]. */\nexport declare const eulerFromColMajor: (m: ArrayLike<number>, order?: EulerOrder) => Vec3;\n","types/math/vec.d.ts":"export type Vec2Like = Vec2 | readonly [number, number] | number[] | Float32Array;\nexport type Vec3Like = Vec3 | readonly [number, number, number] | number[] | Float32Array;\n/** Read the x / first component of any vector-like (wrapper, tuple, or typed array). `?? ` is safe on\n * 0 and NaN — it only falls through on `undefined` (i.e. a non-wrapper that has no `.x`). */\nexport declare const cx: (v: {\n x?: number;\n} | ArrayLike<number>) => number;\nexport declare const cy: (v: {\n y?: number;\n} | ArrayLike<number>) => number;\nexport declare const cz: (v: {\n z?: number;\n} | ArrayLike<number>) => number;\nexport declare class Vec2 {\n x: number;\n y: number;\n constructor(x?: number | Vec2Like, y?: number);\n /** Mutate the components in place. Returns `this`. */\n set(x: number, y: number): this;\n /** Copy another vector's components into this one. Returns `this`. */\n copy(v: Vec2Like): this;\n add(v: Vec2Like): Vec2;\n sub(v: Vec2Like): Vec2;\n mul(v: Vec2Like): Vec2;\n div(v: Vec2Like): Vec2;\n scale(s: number): Vec2;\n /** `this + v * s` (fused multiply-add). */\n scaleAndAdd(v: Vec2Like, s: number): Vec2;\n negate(): Vec2;\n dot(v: Vec2Like): number;\n /** 2D cross product → the scalar z of the 3D cross (signed parallelogram area). */\n cross(v: Vec2Like): number;\n length(): number;\n lengthSq(): number;\n distanceTo(v: Vec2Like): number;\n distanceSqTo(v: Vec2Like): number;\n normalize(): Vec2;\n lerp(v: Vec2Like, t: number): Vec2;\n clamp(min: Vec2Like, max: Vec2Like): Vec2;\n min(v: Vec2Like): Vec2;\n max(v: Vec2Like): Vec2;\n /** Left-hand perpendicular: (-y, x), a 90° CCW turn. */\n perp(): Vec2;\n /** Rotate by `rad` (CCW) around `origin` (default 0). */\n rotate(rad: number, origin?: Vec2Like): Vec2;\n /** The vector's heading in radians: `atan2(y, x)`. */\n heading(): number;\n /** Angle (radians) between this and `v`. */\n angle(v: Vec2Like): number;\n withX(x: number): Vec2;\n withY(y: number): Vec2;\n equals(v: Vec2Like, eps?: number): boolean;\n clone(): Vec2;\n toArray(): [number, number];\n [Symbol.iterator](): Iterator<number>;\n static from(v: Vec2Like): Vec2;\n static get zero(): Vec2;\n static get one(): Vec2;\n static get up(): Vec2;\n static get down(): Vec2;\n static get left(): Vec2;\n static get right(): Vec2;\n}\nexport declare class Vec3 {\n x: number;\n y: number;\n z: number;\n constructor(x?: number | Vec3Like, y?: number, z?: number);\n set(x: number, y: number, z: number): this;\n copy(v: Vec3Like): this;\n add(v: Vec3Like): Vec3;\n sub(v: Vec3Like): Vec3;\n mul(v: Vec3Like): Vec3;\n div(v: Vec3Like): Vec3;\n scale(s: number): Vec3;\n /** `this + v * s` (fused multiply-add). */\n scaleAndAdd(v: Vec3Like, s: number): Vec3;\n negate(): Vec3;\n dot(v: Vec3Like): number;\n cross(v: Vec3Like): Vec3;\n length(): number;\n lengthSq(): number;\n distanceTo(v: Vec3Like): number;\n distanceSqTo(v: Vec3Like): number;\n normalize(): Vec3;\n lerp(v: Vec3Like, t: number): Vec3;\n clamp(min: Vec3Like, max: Vec3Like): Vec3;\n min(v: Vec3Like): Vec3;\n max(v: Vec3Like): Vec3;\n /** Reflect this vector about a (unit) `normal`: `v - 2·(v·n)·n`. */\n reflect(normal: Vec3Like): Vec3;\n /** Vector projection of this onto `onto`. */\n project(onto: Vec3Like): Vec3;\n /** Angle (radians) between this and `v`. */\n angle(v: Vec3Like): number;\n /** Rotate this point around the X axis through `origin` (default 0) by `rad`. */\n rotateX(rad: number, origin?: Vec3Like): Vec3;\n rotateY(rad: number, origin?: Vec3Like): Vec3;\n rotateZ(rad: number, origin?: Vec3Like): Vec3;\n /** Rotate this vector by a quaternion (x, y, z, w). Accepts a `Quat` or a raw `[x,y,z,w]`. */\n rotate(q: ArrayLike<number> | {\n x: number;\n y: number;\n z: number;\n w: number;\n }): Vec3;\n /** Transform this point by a column-major mat4 (a `Mat4`, its `.m`, or a raw length-16 array),\n * applying translation and the perspective divide. */\n transform(m: ArrayLike<number> | {\n m: ArrayLike<number>;\n }): Vec3;\n withX(x: number): Vec3;\n withY(y: number): Vec3;\n withZ(z: number): Vec3;\n equals(v: Vec3Like, eps?: number): boolean;\n clone(): Vec3;\n toArray(): [number, number, number];\n [Symbol.iterator](): Iterator<number>;\n static from(v: Vec3Like): Vec3;\n static get zero(): Vec3;\n static get one(): Vec3;\n static get up(): Vec3;\n static get down(): Vec3;\n static get left(): Vec3;\n static get right(): Vec3;\n /** Forward is −Z (the engine's cameras look down −Z; `node.forward` is −Z at identity). */\n static get forward(): Vec3;\n static get back(): Vec3;\n}\n","types/net/codec.d.ts":"export type FieldKind = 0 | 1 | 2;\nexport type Field = {\n key: string;\n kind: FieldKind;\n len: number;\n step: boolean;\n};\nexport type Layout = {\n fields: Field[];\n floats: number;\n bools: number;\n bytes: number;\n sig: string;\n};\nexport declare const makeLayout: (defaults: Record<string, unknown>, what: string, discrete?: readonly string[]) => Layout;\n/** A fresh state object shaped like the defaults (arrays copied, never shared). */\nexport declare const cloneDefaults: <T extends object>(defaults: T) => T;\n/** Copy the layout's fields from `from` into `into` (array elements copied in place; unknown keys\n * ignored — a JSON spawn state or a partial `setInput`). */\nexport declare const assignState: (layout: Layout, into: any, from: any) => void;\nexport declare const packInto: (view: DataView, offset: number, layout: Layout, s: any) => number;\nexport declare const unpackFrom: (view: DataView, offset: number, layout: Layout, into: any) => number;\n/** `out = a + (b − a) · t` for the numeric fields; booleans and the discrete ones take `b`'s. */\nexport declare const lerpState: (layout: Layout, a: any, b: any, t: number, out: any) => void;\n/** FNV-1a over a string → 8 hex chars. Enough to tell two bundles' schemas apart. */\nexport declare const hashString: (s: string) => string;\n","types/net/core.d.ts":"export type Listener = (...args: any[]) => void;\nexport type NetRole = \"offline\" | \"host\" | \"client\" | \"server\";\nexport type NetStatus = \"idle\" | \"connecting\" | \"online\" | \"error\";\n/** A typed message key: `const Fire = Net.message<{ dir: number[] }>(\"fire\")`. The type lives in\n * TypeScript only; the payload is JSON. */\nexport type NetMessage<T = unknown> = {\n readonly name: string;\n readonly unreliable: boolean;\n readonly __t?: T;\n};\nexport type NetEvents = {\n /** Client: welcomed by the server. Host/server: listening. */\n connect: () => void;\n /** The connection ended (`reason` from the transport, e.g. \"timed out\", \"kicked\"). */\n disconnect: (reason: string) => void;\n /** The server refused us (`reason`: \"full\" | \"version\" | \"schema\" | a kick reason). */\n reject: (reason: string) => void;\n join: (player: NetPlayer) => void;\n leave: (player: NetPlayer, reason: string) => void;\n error: (message: string) => void;\n};\nexport type NetLaunch = {\n role: \"server\" | \"client\";\n address: string;\n port: number;\n maxClients: number;\n};\n/** Link statistics (`player.rtt` / `player.loss` read them): the bridge's `NetStats`. */\nexport type NetStats = {\n rtt: number;\n loss: number;\n sentKbps: number;\n receivedKbps: number;\n};\nexport declare const CH_RELIABLE = 0;\nexport declare const CH_UNRELIABLE = 1;\nexport declare const PROTO = 3;\nexport declare const LOCAL_SLOT = -1;\nexport declare const bridge: () => typeof _creatorNet | null;\nexport declare class NetPlayer {\n /** Session-unique id assigned by the server (1 = the host's own player when hosting). */\n readonly id: number;\n name: string;\n readonly connectedAt: number;\n /** A local bag for game facts (score, team, ready). NOT replicated — anything a client must see\n * goes through a message or replicated state. */\n data: any;\n /** Server: what this player's `Net.connect(…, { hello })` carried (the game's own: a build, a\n * token) — the value `Net.listen({ accept })` was asked about. Undefined everywhere else. */\n hello: unknown;\n private _leave;\n constructor(id: number, name: string, slot: number);\n get isMe(): boolean;\n /** Round trip to this player in ms (server side) or to the server (our own player on a client). */\n get rtt(): number;\n get loss(): number;\n /** Server → this player. */\n send<T>(msg: NetMessage<T>, data: T): void;\n kick(reason?: string): void;\n on(event: \"leave\", cb: (player: NetPlayer, reason: string) => void): this;\n off(event: \"leave\", cb: (player: NetPlayer, reason: string) => void): this;\n}\nexport declare const state: {\n role: NetRole;\n status: NetStatus;\n isServer: boolean;\n isClient: boolean;\n me: NetPlayer | null;\n players: NetPlayer[];\n nextId: number;\n /** a session is up: the phase hooks are installed and pump every frame */\n active: boolean;\n events: Map<string, Listener[]>;\n handlers: Map<string, Listener[]>;\n connectResolve: null | (() => void);\n connectReject: null | ((e: Error) => void);\n myName: string;\n /** client: the game's own part of the `$hello` (`Net.connect(…, { hello })`), opaque to the SDK */\n hello: unknown;\n /** server: the game's say in the handshake (`Net.listen({ accept })`) — a reason refuses */\n accept: null | ((hello: unknown, who: {\n name: string;\n }) => string | null | void);\n};\nexport declare const hooks: {\n frameEarly: null | ((dt: number) => void);\n frameFixed: null | ((dt: number) => void);\n frameLate: null | ((dt: number) => void);\n /** client: extra `$hello` fields (schema hash) */\n helloExtra: null | (() => Record<string, unknown>);\n /** server: a reject reason for this `$hello`, or null to accept */\n helloCheck: null | ((data: any) => string | null);\n /** server: extra `$welcome` fields (tick, kind table) */\n welcomeExtra: null | (() => Record<string, unknown>);\n /** server: right after `$welcome` + `$join` went out — send the live entities to the newcomer */\n afterWelcome: null | ((p: NetPlayer) => void);\n /** client: the `$welcome` arrived (before the connect event) */\n onWelcome: null | ((data: any) => void);\n /** client: a reserved `$` message the roster does not know (spawn / despawn) */\n clientReserved: null | ((name: string, data: any) => void);\n /** binary payloads (channel 1): inputs on the server, snapshots on the client */\n serverBinary: null | ((p: NetPlayer, channel: number, data: ArrayBuffer) => void);\n clientBinary: null | ((channel: number, data: ArrayBuffer) => void);\n /** server: a player is gone (after the leave event) */\n playerLeft: null | ((p: NetPlayer) => void);\n /** the session ends (before the state resets); `role` = the role we are leaving */\n reset: null | ((role: NetRole) => void);\n};\nexport declare const emit: (event: keyof NetEvents, ...args: any[]) => void;\nexport declare const playerBySlot: (slot: number) => NetPlayer | undefined;\nexport declare const addPlayer: (id: number, name: string, slot: number) => NetPlayer;\nexport declare const removePlayer: (p: NetPlayer, reason: string) => void;\nexport declare const ensureMe: () => NetPlayer;\nexport declare const sendRaw: (slot: number, channel: number, payload: string | ArrayBuffer) => boolean;\nexport declare const queueLocal: (fn: () => void) => void;\nexport declare const dispatchMessage: (name: string, data: unknown, from: NetPlayer | null) => void;\nexport declare const deliverTo: (p: NetPlayer, msg: NetMessage<any>, data: unknown) => void;\nexport declare const broadcastRaw: (payload: string | ArrayBuffer, except: NetPlayer | null, channel?: number) => void;\nexport declare const startPhases: () => void;\nexport declare const stopPhases: () => void;\nexport declare const resetToOffline: () => void;\nexport declare const pump: () => void;\n","types/net/index.d.ts":"import { NetPlayer, type NetEvents, type NetLaunch, type NetMessage, type NetRole, type NetStatus } from \"./core\";\nimport { NetEntity, Replicated, stats, type NetCorrection, type NetInput, type NetKind, type NetTransform } from \"./replication\";\nexport { NetPlayer, NetEntity, Replicated };\nexport type { NetEvents, NetLaunch, NetMessage, NetRole, NetStatus, NetInput, NetKind, NetTransform, NetCorrection };\ndeclare class NetImpl {\n get role(): NetRole;\n get status(): NetStatus;\n get isServer(): boolean;\n get isClient(): boolean;\n /** True on hosts that ship the transport (desktop, the 3d/full Android variants, iOS). Web: false. */\n get supported(): boolean;\n /** What the exe was launched as (`--server --port N` / `--connect ADDR`), or null. */\n get launch(): NetLaunch | null;\n get me(): NetPlayer;\n get players(): readonly NetPlayer[];\n player(id: number): NetPlayer | undefined;\n /** Our round trip to the server (client), 0 otherwise. */\n get rtt(): number;\n /** The simulation tick — one per fixed step (`updateFixed`). The server's is THE tick; a client\n * runs a few ticks ahead so its inputs arrive in time. */\n get tick(): number;\n /** The server tick this machine is SHOWING the others at: on a client, its estimate of the server's\n * clock less the interpolation delay (fractional); `tick` everywhere else, where nothing is\n * interpolated. What a client names when it tells the server \"as I saw it\". */\n get viewTick(): number;\n /** Live counters: snapshots, input lead / `ahead`, corrections, missed inputs, bytes out. */\n get stats(): typeof stats;\n /** Start serving on `port`. From offline this makes us the host (a player who is also the\n * server); on the dedicated exe (`Net.launch.role === \"server\"`) there is no local player.\n * `accept` is the game's say in the handshake: it is given what the client's `connect` passed as\n * `hello` and returns a reason to refuse (the client's `reject` event carries it), nothing to accept. */\n listen(opts?: {\n port?: number;\n maxClients?: number;\n name?: string;\n dedicated?: boolean;\n accept?: (hello: unknown, who: {\n name: string;\n }) => string | null | void;\n }): boolean;\n /** Connect to a host/server (`address` = \"ip:port\"). Resolves once the server welcomed us.\n * `hello` = anything JSON the game wants the server to see before it lets us in (its\n * `Net.listen({ accept })`, then `player.hello`); the SDK only carries it. */\n connect(target: {\n address: string;\n }, opts?: {\n name?: string;\n hello?: unknown;\n }): Promise<void>;\n /** Client → offline. Host/server → everyone is dropped, back to offline. */\n disconnect(): void;\n /** Declare a message type once; the name is the wire id. `unreliable` = channel 1 (fire-and-forget). */\n message<T = void>(name: string, opts?: {\n unreliable?: boolean;\n }): NetMessage<T>;\n /** Client → server (offline / host: delivered in-process, `from` = our own player). */\n send<T>(msg: NetMessage<T>, data: T): void;\n /** Server → every player (incl. the host's own), minus `except`. */\n broadcast<T>(msg: NetMessage<T>, data: T, opts?: {\n except?: NetPlayer | null;\n }): void;\n /** Subscribe to a built-in event or to a message (`from` = the sending player on the server,\n * null on a client — the server sent it). Returns `Net` for chaining. */\n on<K extends keyof NetEvents>(event: K, cb: NetEvents[K]): this;\n on<T>(msg: NetMessage<T>, cb: (data: T, from: NetPlayer | null) => void): this;\n off<K extends keyof NetEvents>(event: K, cb: NetEvents[K]): this;\n off<T>(msg: NetMessage<T>, cb: (data: T, from: NetPlayer | null) => void): this;\n /** The per-tick input layout (one per game): `const PlayerInput = Net.input({ moveX: 0, moveY: 0, jump: false })`.\n * Fields: number → f32, boolean → 1 bit, number[] → f32 × length. */\n input<T extends object>(defaults: T): NetInput<T>;\n /** Set this tick's input — from `updateFixed`, once per tick, on the machine that owns the player\n * (client / host / offline). The owner's sim reads it back through `rep.input(PlayerInput)`; a\n * client also ships it to the server for the same tick. */\n setInput<T extends object>(inp: NetInput<T>, values: Partial<T>): void;\n /** A replicated entity type: the defaults are the snapshot layout (same field rules as `input`),\n * `transform` tells the SDK which fields mirror the node's pose, `client` births the proxy on a\n * client when the server spawns one (`new Node().aspect(Replicated, { kind, owner })`) — it may\n * be set later, `Kind.client = …`, where the client's code lives. `discrete` names the numeric\n * fields that are never interpolated (an index, a count); `correction` tunes how the owner's\n * prediction is brought back to the server's state (all in the game's own units). */\n kind<S extends object>(name: string, defaults: S, opts?: {\n transform?: NetTransform;\n client?: (rep: NetEntity<S>, scene: any) => any;\n discrete?: readonly (keyof S & string)[];\n correction?: Partial<NetCorrection>;\n }): NetKind<S>;\n /** Every replicated entity this machine knows. */\n get entities(): readonly NetEntity[];\n entity(netId: number): NetEntity | undefined;\n /** Dev only: yojimbo's network simulator on our side of the wire (latency/jitter in ms, loss in %). */\n simulate(opts: {\n latency?: number;\n jitter?: number;\n loss?: number;\n }): void;\n}\nexport declare const Net: NetImpl;\n","types/net/replication.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { Vec3 } from \"../math/vec\";\nimport type { Node } from \"../gl/Node\";\nimport { Scene } from \"../gl/Scene\";\nimport { type Layout } from \"./codec\";\nimport { NetPlayer } from \"./core\";\nexport type NetTransform = \"pos\" | \"pos+rot\" | \"none\";\n/** How an owner's prediction is brought back to the server's state. The SDK knows nothing of what\n * the entity is, so the defaults are neutral: every disagreement counts, none is a teleport. */\nexport type NetCorrection = {\n /** A vertical disagreement below this is ignored (world units). 0 = none ignored. A body that\n * snaps to a floor differs by a little between two machines, and lifting it by that feeds itself. */\n deadbandY: number;\n /** A disagreement of this much or more is a teleport: the body jumps and `correction` stays zero\n * (world units). Infinity = always smoothed. */\n snap: number;\n /** The decay time constant of the visual offset `correction` (seconds). 0 = no smoothing. */\n tau: number;\n};\n/** The per-tick input layout: `const PlayerInput = Net.input({ moveX: 0, moveY: 0, jump: false })`. */\nexport type NetInput<T extends object = any> = {\n readonly layout: Layout;\n readonly defaults: T;\n readonly __t?: T;\n};\n/** A replicated entity type: `const PlayerKind = Net.kind('player', { pos: [0,0,0], hp: 100 }, { transform: 'pos', client })`. */\nexport type NetKind<S extends object = any> = {\n readonly name: string;\n readonly layout: Layout;\n readonly defaults: S;\n /** Which state fields the SDK samples on the server and applies to a client proxy: `pos` (a\n * `pos: [x,y,z]` field), `pos+rot` (+ a `rot: [x,y,z,w]` quaternion field), or `none`. */\n readonly transform: NetTransform;\n readonly correction: NetCorrection;\n /** Births the client-side proxy on spawn; the SDK attaches `Replicated` to what it returns.\n * Assignable: a declaration both ends share may leave it to the client's own module. */\n client?: (rep: NetEntity<S>, scene: Scene | null) => Node | void;\n readonly __t?: S;\n};\n/** Live counters (`Net.stats`): how the clocks and the prediction are doing. */\nexport declare const stats: {\n /** client: snapshots received */ snapshots: number;\n /** client: how far ahead of the server's simulation our newest input was at the last snapshot */ ahead: number;\n /** client: our tick minus the estimated server tick */ lead: number;\n /** client: tick nudges (+1 / −1) by the lead control */ nudges: number;\n /** owner: corrections applied, the largest one and their sum (metres) — `sum / corrections` = the typical one */ corrections: number;\n maxCorrection: number;\n sumCorrection: number;\n /** server: inputs that arrived late (the last one was repeated), all clients */ missed: number;\n /** bytes sent on the unreliable channel (snapshots / inputs) */ bytesOut: number;\n};\nexport declare class NetEntity<S extends object = any> {\n /** Session-unique id, assigned by the server. */\n readonly netId: number;\n readonly kind: NetKind<S>;\n /** The owning player's id; 0 = the server's own (props, the game state). */\n readonly ownerId: number;\n /** Server: the authoritative state you write (`pos` is sampled from the node). Client remote:\n * interpolated. Client owner: the newest authoritative state. */\n readonly state: S;\n /** The node carrying this entity (server: yours; client: what the kind's factory returned). */\n node: Node | null;\n /** Owner on a client: the visual offset left by the last correction, decaying to zero — add it to\n * what you DRAW (a child mesh, the camera), never to physics. */\n readonly correction: Vec3;\n constructor(netId: number, kind: NetKind<S>, ownerId: number, s: S);\n get owner(): NetPlayer | null;\n /** Our own player owns it (offline: everything owned by `Net.me`). */\n get isMine(): boolean;\n /** This machine runs the simulation for it: the server always, a client for what it owns\n * (prediction). A remote proxy on a client is interpolation only. */\n get simulated(): boolean;\n /** The owner's input for the tick being simulated — the ring entry on the server (the last one\n * repeated when it is late), the local input on the owner / host / offline. */\n input<T extends object>(inp: NetInput<T>): T;\n /** `input()` is an input the owner gave — false until the first one exists (the server before\n * the owner's first packet, the owner before its first `Net.setInput`), when it is the defaults. */\n get hasInput(): boolean;\n /** Client: `state` was refreshed (a snapshot landed / the interpolation moved). */\n on(event: \"state\", cb: (s: S) => void): this;\n off(event: \"state\", cb: (s: S) => void): this;\n}\nexport declare const declareKind: <S extends object>(name: string, defaults: S, opts?: {\n transform?: NetTransform;\n client?: NetKind<S>[\"client\"];\n discrete?: readonly string[];\n correction?: Partial<NetCorrection>;\n}) => NetKind<S>;\nexport declare const declareInput: <T extends object>(defaults: T) => NetInput<T>;\nexport declare const setInput: <T extends object>(inp: NetInput<T>, values: Partial<T>) => void;\nexport declare const currentTick: () => number;\nexport declare const viewTick: () => number;\nexport declare const allEntities: () => NetEntity[];\nexport declare const entityById: (netId: number) => NetEntity | undefined;\n/**\n * The server's handle on a replicated entity — attach it to the node that IS the entity:\n * `new Node().aspect(Replicated, { kind: PlayerKind, owner: player })`. From then on the entity exists\n * on every client (the kind's `client` factory births the proxy there, and the SDK attaches this same\n * aspect to it), its state is packed into every snapshot, and `node.destroy()` despawns it everywhere.\n * `node.replicated.state` / `.isMine` / `.simulated` / `.input()` are the same on both sides.\n */\nexport declare class Replicated extends Aspect<\"replicated\", Node> {\n static readonly aspect = \"replicated\";\n /** Server: the entity type (required). */\n kind: NetKind<any>;\n /** Server: the owning player, or null for the server's own. */\n owner: NetPlayer | null;\n protected onAttach(): void;\n protected onDetach(): void;\n /** The entity itself (what the client factory received). */\n get entity(): NetEntity;\n get netId(): number;\n get state(): any;\n get isMine(): boolean;\n get simulated(): boolean;\n get ownerPlayer(): NetPlayer | null;\n get correction(): Vec3;\n /** The owner's input for the tick being simulated (see `NetEntity.input`). */\n input<T extends object>(inp: NetInput<T>): T;\n get hasInput(): boolean;\n}\nexport declare const installReplication: () => void;\n","types/plugin.d.ts":"import { File as HostFile } from \"./runtime/fetch\";\nimport { ServiceClient } from \"./runtime/service\";\nimport { NativeViewElement } from \"./ui/NativeView\";\nexport type { PresentOptions } from \"./ui/presentable\";\nexport type { NativeView } from \"./ui/NativeView\";\nexport type { FetchResponse } from \"./runtime/fetch\";\n/** Signed 32-bit integer on the wire. */\nexport type i32 = number;\n/** Double on the wire — also every integer that can leave 32 bits (a millisecond time stamp). */\nexport type f64 = number;\n/** Bytes that STAY in the host's buffer table: the native half hands over its bytes + a name, the\n * app gets the SDK's `File` handle (a texture source, a `FormData` value, a share) and the bytes\n * never enter the JS heap. For bytes the app must read itself, a contract says `Uint8Array`. */\nexport type File = HostFile;\n/** Any JSON value, opaque to the generator (GeoJSON, a developer's own payload): it crosses as is\n * and the native half receives the platform's untyped value. */\nexport type Json = null | boolean | number | string | Json[] | {\n [key: string]: Json;\n};\ndeclare const channel: unique symbol;\n/** Marks a contract interface as a NativeView channel. `Name` is what the halves register under\n * (`registerView(name)`); `Params` is what a factory receives; `Events` maps an event's name to\n * its payload (`void` = no payload). */\nexport interface View<Name extends string, Params extends object = {}, Events extends object = {}> {\n readonly [channel]?: {\n kind: \"view\";\n name: Name;\n params: Params;\n events: Events;\n };\n}\n/** Marks a contract interface as a headless Service channel — see {@link View}. */\nexport interface Service<Name extends string, Params extends object = {}, Events extends object = {}> {\n readonly [channel]?: {\n kind: \"service\";\n name: Name;\n params: Params;\n events: Events;\n };\n}\n/** A listener of the event `K`: no argument for a `void` payload. */\nexport type Listener<Events, K extends keyof Events> = Events[K] extends void ? () => void : (payload: Events[K]) => void;\n/** What an event's payload is read with when it is not on the wire what it is for the app (it\n * holds a File): by the event's name. */\nexport type EventReaders = {\n [event: string]: (wire: any) => any;\n};\n/** The element of a view plugin: a `NativeView` whose events are the contract's. Generated wrappers\n * extend it (`<Name>Base`); a hand-written one extends that, or this when its API is not the wire's. */\nexport declare class ViewChannel<Events extends object = {}> extends NativeViewElement {\n private readonly _readers;\n constructor(iface: string, name: string, params: object, readers?: EventReaders);\n /** Whether this host registered a view under `name` — at contract version `since` or later, when\n * one is given (a method's `@since`). */\n static supports(name: string, since?: number): boolean;\n on<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n off<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n}\n/** The client of a service plugin: a session that opens on the first call, with the contract's\n * events. The service twin of {@link ViewChannel}. */\nexport declare class ServiceChannel<Events extends object = {}> extends ServiceClient {\n private readonly _readers;\n constructor(iface: string, name: string, params?: object, readers?: EventReaders);\n /** Whether this host registered a service under `name` — at contract version `since` or later,\n * when one is given (a method's `@since`). */\n static supports(name: string, since?: number): boolean;\n on<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n off<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n}\n/** The text of a host buffer — what a bundled `asset()` is in a shell compile (`\"id:N\"`): the host\n * already holds the bytes. Empty when there is no such buffer. */\nexport declare const bufferText: (systemId: number) => string;\n/** Prepare-then-present for a view that needs the camera: fail before any prompt on a host without\n * the view, ask for the permission while the current destination stays visible, give up when\n * another navigation superseded this one. Resolves when the view may open. */\nexport declare const prepareCamera: (view: ViewChannel<any>) => Promise<void>;\n","types/plugins/gen/camera/sdk/camera.d.ts":"import { type File, type NativeView, type PresentOptions } from \"../../../../plugin\";\nimport type { Facing } from \"../contract\";\nexport type CameraFacing = Facing;\nexport interface CameraView extends NativeView {\n /** Request the camera permission, then present the preview. The current destination stays\n * visible until the camera is ready; rejects if the permission is denied, the host has no\n * camera, or another navigation superseded this one. */\n open(options?: PresentOptions): Promise<void>;\n /** Capture a still frame as an image `File` (host-encoded). */\n takePhoto(): Promise<File>;\n /** Switch between the front and the back camera while the preview is live. */\n setFacingMode(facingMode: CameraFacing): Promise<void>;\n}\n/**\n * Create a camera view (default: the back camera). `CameraView.isSupported` reports whether this\n * host has the capability — check it before offering the feature.\n */\nexport declare const CameraView: {\n (options?: {\n facingMode?: CameraFacing;\n }): CameraView;\n /** Whether this host registered a \"camera\" view. */\n readonly isSupported: boolean;\n};\n","types/plugins/gen/camera/sdk/camera.gen.d.ts":"import { ViewChannel, type File } from \"../../../../plugin\";\nimport type { CameraEvents, CameraParams, Facing } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"camera\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** Capture a still frame as a JPEG.\n * Rejects with \"failed\". */\nexport declare const takePhoto: (view: ViewChannel<CameraEvents>) => Promise<File>;\n/** Switch the camera while the preview is live. */\nexport declare const setFacingMode: (view: ViewChannel<CameraEvents>, mode: Facing) => Promise<void>;\n/** A method of the contract. */\nexport type Method = \"takePhoto\" | \"setFacingMode\";\n/** Whether this host has the view \"camera\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The view \"camera\" with the wire's methods as its own. */\nexport declare class CameraViewBase extends ViewChannel<CameraEvents> {\n constructor(params?: CameraParams);\n /** Capture a still frame as a JPEG.\n * Rejects with \"failed\". */\n takePhoto(): Promise<File>;\n /** Switch the camera while the preview is live. */\n setFacingMode(mode: Facing): Promise<void>;\n}\n","types/plugins/gen/geolocation/sdk/geolocation.d.ts":"import type { GeoOptions, GeoPosition } from \"../contract\";\nexport type { GeoOptions, GeoPosition };\n/** A live `Geolocation.watch()` subscription — `stop()` it when the screen goes away. */\nexport interface GeoWatch {\n stop(): void;\n}\n/**\n * The device position. `Geolocation.isSupported` reports whether this host registered the\n * service — check it before offering location features.\n */\nexport declare const Geolocation: {\n /** Whether this host registered a \"geolocation\" service. */\n readonly isSupported: boolean;\n /** One position fix. Prompts for permission on first use; rejects on denial (\"denied\"), no\n * provider (\"unavailable\"), or `options.timeout` elapsing (\"timeout\"). */\n getCurrent(options?: GeoOptions): Promise<GeoPosition>;\n /** Continuous updates. Resolves once watching (permission granted + provider started) — so a\n * denial is a rejection, never a silently dead callback. One host watch serves every\n * subscriber; the options of the watch that starts it win. Always `stop()` when done. */\n watch(callback: (position: GeoPosition) => void, options?: GeoOptions): Promise<GeoWatch>;\n};\n","types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts":"import { ServiceChannel } from \"../../../../plugin\";\nimport type { GeoOptions, GeoPosition, GeolocationEvents, GeolocationParams } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"geolocation\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** One fix.\n * Rejects with \"denied\" / \"unavailable\" / \"timeout\". */\nexport declare const getCurrent: (service: ServiceChannel<GeolocationEvents>, options?: GeoOptions) => Promise<GeoPosition>;\n/** Start the session's watch; resolves once it is live (permission granted, provider started).\n * A second call while watching resolves at once and keeps the first call's options.\n * Rejects with \"denied\" / \"unavailable\". */\nexport declare const startWatch: (service: ServiceChannel<GeolocationEvents>, options?: GeoOptions) => Promise<void>;\nexport declare const stopWatch: (service: ServiceChannel<GeolocationEvents>) => Promise<void>;\n/** A method of the contract. */\nexport type Method = \"getCurrent\" | \"startWatch\" | \"stopWatch\";\n/** Whether this host has the service \"geolocation\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The service \"geolocation\" with the wire's methods as its own. */\nexport declare class GeolocationBase extends ServiceChannel<GeolocationEvents> {\n constructor(params?: GeolocationParams);\n /** One fix.\n * Rejects with \"denied\" / \"unavailable\" / \"timeout\". */\n getCurrent(options?: GeoOptions): Promise<GeoPosition>;\n /** Start the session's watch; resolves once it is live (permission granted, provider started).\n * A second call while watching resolves at once and keeps the first call's options.\n * Rejects with \"denied\" / \"unavailable\". */\n startWatch(options?: GeoOptions): Promise<void>;\n stopWatch(): Promise<void>;\n}\n","types/plugins/gen/map/sdk/map.d.ts":"import { type FetchResponse, type NativeView } from \"../../../../plugin\";\nimport type { LngLat, MapCamera, MapCameraMove, MapFitOptions, MapPadding, MapParams, MapUserLocationOptions } from \"../contract\";\nexport type { LngLat, MapCamera };\nexport type CameraMove = MapCameraMove;\nexport type FitOptions = MapFitOptions;\nexport type MapPaddingValues = MapPadding;\nexport type UserLocationOptions = MapUserLocationOptions;\n/** The ready-made styles a map falls back on — [OpenFreeMap](https://openfreemap.org): OSM data,\n * no key, no registration, no request limits, commercial use allowed, and the whole stack is\n * open-source if you'd rather self-host. `liberty` is the default. Credit them (and OSM) in your\n * app: \"© OpenFreeMap © OpenMapTiles, data from OpenStreetMap\". A public free instance is a\n * donation-funded service with no SLA — for a product with real traffic, run your own tiles and\n * pass that style's URL instead. */\nexport type MapStyleName = \"liberty\" | \"bright\" | \"positron\" | \"dark\" | \"fiord\";\n/**\n * Where the map's style comes from:\n *\n * - a **name** — `\"liberty\"` (the default), `\"positron\"`, … see {@link MapStyleName}: a ready-made\n * style on a free public tile server, so `MapView()` alone already draws a world map;\n * - a **URL** — `\"https://tiles.example.com/styles/city/style.json\"`, the map fetches it;\n * - a **bundled style** — `asset(\"./map/style.json\")`: the file ships inside the app and the\n * wrapper hands its text to the map, so the style itself needs no server (tiles, sprites and\n * glyphs are still fetched from whatever urls it names);\n * - an **already-read file** — a `FetchResponse` from `fetchLocal(\"style.json\")` or\n * `await fetch(url)` (a style downloaded once and cached in `files`);\n * - the **style object** itself — the natural way to substitute a tile-server address at runtime:\n * `{ ...style, sources: { openmaptiles: { type: \"vector\", url: `${server}/data/v3.json` } } }`.\n *\n * Whichever form: **every url INSIDE the style (`sources[].url`, `sprite`, `glyphs`) must be\n * absolute.** maplibre-native, unlike maplibre-gl-js, resolves no relative ones — a style with\n * them loads to an empty basemap (your layers still draw). A tileserver-gl instance emits\n * relative urls until its `publicUrl` is configured.\n */\nexport type MapStyle = MapStyleName | (string & {}) | FetchResponse | object;\nexport interface MapOptions extends Omit<MapParams, \"style\" | \"styleJson\"> {\n /** The MapLibre style: a ready-made name (`\"liberty\"` — the default, `\"positron\"`, …), a URL,\n * a style bundled with the app (`asset(\"./style.json\")`), an already-read file\n * (`fetchLocal(\"style.json\")`, `await fetch(url)`) or the style object itself — see\n * {@link MapStyle}. */\n style?: MapStyle;\n}\n/** A tap on the map itself — not on a feature of a managed layer. */\nexport interface MapTap {\n lngLat: LngLat;\n /** View-space point, px. */\n point: [number, number];\n}\n/** One marker. `id` comes back in `onTap`; `icon` names an image of the style's sprite; `color` /\n * `title` feed the default layers; extra keys become feature properties. */\nexport interface MarkerItem {\n id: string | number;\n lngLat: LngLat;\n icon?: string;\n color?: string;\n title?: string;\n [property: string]: any;\n}\nexport interface MarkerTap {\n id: string | number;\n lngLat: LngLat;\n /** Every property of the tapped feature (the item's keys, `id` and `lngLat` excluded). */\n properties: Record<string, any>;\n}\nexport interface MarkerLayerOptions {\n /** Group nearby markers into clusters (a cluster tap zooms in). Default false. */\n cluster?: boolean;\n /** Cluster radius, px (default 50). */\n clusterRadius?: number;\n /** Zoom at which clusters stop forming (default: maxZoom − 1). */\n clusterMaxZoom?: number;\n}\nexport interface LineLayerOptions {\n color?: string;\n /** Px (default 4). */\n width?: number;\n /** 0–1 (default 1). */\n opacity?: number;\n}\nexport interface MarkerLayer {\n readonly name: string;\n /** Replace the layer's markers. */\n set(items: MarkerItem[]): this;\n clear(): this;\n /** A marker (or any feature of this layer's source) was tapped. */\n onTap(callback: (marker: MarkerTap) => void): this;\n}\nexport interface LineLayer {\n readonly name: string;\n /** Replace the line with these vertices. */\n set(coordinates: LngLat[]): this;\n clear(): this;\n}\nexport interface MapView extends NativeView {\n /** The style loaded and the map is interactive (queued calls have been replayed). */\n onReady(callback: () => void): this;\n /** A tap that hit no feature of a managed layer. */\n onTap(callback: (tap: MapTap) => void): this;\n /** The camera settled after a gesture or an animation. */\n onMove(callback: (camera: MapCamera) => void): this;\n /** The map reported a problem — a style that wouldn't load, a source it couldn't reach. Never\n * fatal; with no handler the message goes to `console.error`, so it is never silent. */\n onError(callback: (error: {\n message: string;\n }) => void): this;\n /** A named marker layer (one GeoJSON source). If the style already declares a source with this\n * name, its layers are used as-is and only the data is pushed; otherwise the plugin creates the\n * source and default marker layers (colored dot, `icon`, `title` label; clusters on request). */\n markers(name: string, options?: MarkerLayerOptions): MarkerLayer;\n /** A named line layer (one GeoJSON source) — same style-first rule as `markers`. */\n line(name: string, options?: LineLayerOptions): LineLayer;\n /** Raw escape hatch: replace the data of any GeoJSON source in the style. */\n setData(source: string, geojson: object): this;\n flyTo(center: LngLat, options?: CameraMove): this;\n jumpTo(center: LngLat, options?: CameraMove): this;\n /** Fit the camera to these points (padding + the view padding respected). */\n fitPoints(points: LngLat[], options?: FitOptions): this;\n /** Content inset: the part of the view covered by your UI (`\"40%\"` = of the view's size).\n * Camera operations center inside the remaining area. */\n setPadding(padding: MapPaddingValues): this;\n getCamera(): Promise<MapCamera>;\n /** Move the user puck (the map draws it; the position comes from you — `Geolocation.watch`).\n * `null` hides it. */\n setUserLocation(lngLat: LngLat | null, options?: UserLocationOptions): this;\n}\n/**\n * Create a map view. `MapView.isSupported` reports whether this host registered a \"map\" view —\n * check it before offering the feature.\n */\nexport declare const MapView: {\n (options?: MapOptions): MapView;\n /** Whether this host registered a \"map\" view. */\n readonly isSupported: boolean;\n};\n","types/plugins/gen/map/sdk/map.gen.d.ts":"import { ViewChannel, type Json } from \"../../../../plugin\";\nimport type { LngLat, MapCamera, MapCameraMove, MapEvents, MapFitOptions, MapLayerKind, MapLayerOptions, MapPadding, MapParams, MapUserLocationOptions } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"map\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** Make sure the GeoJSON source `source` exists. A source the style declares is used as is (its\n * layers draw, only data flows); otherwise the half creates it with the default layers of `kind`.\n * Rejects with \"notReady\". */\nexport declare const ensureLayer: (view: ViewChannel<MapEvents>, source: string, kind: MapLayerKind, options?: MapLayerOptions) => Promise<void>;\nexport declare const removeLayer: (view: ViewChannel<MapEvents>, source: string) => Promise<void>;\n/** Replace the data of a GeoJSON source: a Feature or a FeatureCollection.\n * Rejects with \"notReady\". */\nexport declare const setData: (view: ViewChannel<MapEvents>, source: string, geojson: Json) => Promise<void>;\nexport declare const flyTo: (view: ViewChannel<MapEvents>, center: LngLat, options?: MapCameraMove) => Promise<void>;\nexport declare const jumpTo: (view: ViewChannel<MapEvents>, center: LngLat, options?: MapCameraMove) => Promise<void>;\n/** Fit the camera to the points.\n * Rejects with \"noPoints\". */\nexport declare const fitPoints: (view: ViewChannel<MapEvents>, points: LngLat[], options?: MapFitOptions) => Promise<void>;\n/** The part of the view covered by the app's UI; camera moves center inside the rest. */\nexport declare const setPadding: (view: ViewChannel<MapEvents>, padding: MapPadding) => Promise<void>;\n/** Rejects with \"notReady\". */\nexport declare const getCamera: (view: ViewChannel<MapEvents>) => Promise<MapCamera>;\n/** Move the user puck; null hides it. */\nexport declare const setUserLocation: (view: ViewChannel<MapEvents>, lngLat: LngLat | null, options?: MapUserLocationOptions) => Promise<void>;\n/** A method of the contract. */\nexport type Method = \"ensureLayer\" | \"removeLayer\" | \"setData\" | \"flyTo\" | \"jumpTo\" | \"fitPoints\" | \"setPadding\" | \"getCamera\" | \"setUserLocation\";\n/** Whether this host has the view \"map\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The view \"map\" with the wire's methods as its own. */\nexport declare class MapViewBase extends ViewChannel<MapEvents> {\n constructor(params?: MapParams);\n /** Make sure the GeoJSON source `source` exists. A source the style declares is used as is (its\n * layers draw, only data flows); otherwise the half creates it with the default layers of `kind`.\n * Rejects with \"notReady\". */\n ensureLayer(source: string, kind: MapLayerKind, options?: MapLayerOptions): Promise<void>;\n removeLayer(source: string): Promise<void>;\n /** Replace the data of a GeoJSON source: a Feature or a FeatureCollection.\n * Rejects with \"notReady\". */\n setData(source: string, geojson: Json): Promise<void>;\n flyTo(center: LngLat, options?: MapCameraMove): Promise<void>;\n jumpTo(center: LngLat, options?: MapCameraMove): Promise<void>;\n /** Fit the camera to the points.\n * Rejects with \"noPoints\". */\n fitPoints(points: LngLat[], options?: MapFitOptions): Promise<void>;\n /** The part of the view covered by the app's UI; camera moves center inside the rest. */\n setPadding(padding: MapPadding): Promise<void>;\n /** Rejects with \"notReady\". */\n getCamera(): Promise<MapCamera>;\n /** Move the user puck; null hides it. */\n setUserLocation(lngLat: LngLat | null, options?: MapUserLocationOptions): Promise<void>;\n}\n","types/plugins/gen/push/sdk/push.d.ts":"import type { PushEvents, PushPayload, PushRegisterOptions, PushRegistration, PushStatus } from \"../contract\";\nexport type { PushPayload, PushRegisterOptions, PushStatus };\nexport type PushEvent = keyof PushEvents;\n/**\n * Remote push notifications. `Push.isSupported` reports whether this host registered the\n * service — check it before offering notification features.\n */\nexport declare const Push: {\n /** Whether this host registered a \"push\" service. */\n readonly isSupported: boolean;\n /** Permission + registration state. Never prompts. */\n getStatus(): Promise<PushStatus>;\n /** Ask for permission (first time) and register this device → the opaque address your server\n * targets. Idempotent — safe to call every launch; rejects \"denied\" / \"unavailable\". */\n register(options?: PushRegisterOptions): Promise<PushRegistration>;\n /** Remove this device's registration (the address stops receiving). */\n unregister(): Promise<void>;\n /** The notification that cold-started this app run, or null. Stable across calls. */\n getLaunch(): Promise<PushPayload | null>;\n /** \"message\" = received while the app is open; \"tap\" = the user tapped one while it ran. */\n addEventListener(event: PushEvent, callback: (payload: PushPayload) => void): void;\n removeEventListener(event: PushEvent, callback: (payload: PushPayload) => void): void;\n};\n","types/plugins/gen/push/sdk/push.gen.d.ts":"import { ServiceChannel } from \"../../../../plugin\";\nimport type { PushEvents, PushParams, PushPayload, PushRegisterOptions, PushRegistration, PushStatus } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"push\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** Permission + registration state. Never prompts. */\nexport declare const getStatus: (service: ServiceChannel<PushEvents>) => Promise<PushStatus>;\n/** Ask for the permission (the first time) and register this device. Idempotent.\n * Rejects with \"denied\" / \"unavailable\". */\nexport declare const register: (service: ServiceChannel<PushEvents>, options?: PushRegisterOptions) => Promise<PushRegistration>;\n/** Remove this device's registration.\n * Rejects with \"unavailable\". */\nexport declare const unregister: (service: ServiceChannel<PushEvents>) => Promise<void>;\n/** The notification that cold-started this world, or null. Stable across calls. */\nexport declare const getLaunch: (service: ServiceChannel<PushEvents>) => Promise<PushPayload | null>;\n/** A method of the contract. */\nexport type Method = \"getStatus\" | \"register\" | \"unregister\" | \"getLaunch\";\n/** Whether this host has the service \"push\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The service \"push\" with the wire's methods as its own. */\nexport declare class PushBase extends ServiceChannel<PushEvents> {\n constructor(params?: PushParams);\n /** Permission + registration state. Never prompts. */\n getStatus(): Promise<PushStatus>;\n /** Ask for the permission (the first time) and register this device. Idempotent.\n * Rejects with \"denied\" / \"unavailable\". */\n register(options?: PushRegisterOptions): Promise<PushRegistration>;\n /** Remove this device's registration.\n * Rejects with \"unavailable\". */\n unregister(): Promise<void>;\n /** The notification that cold-started this world, or null. Stable across calls. */\n getLaunch(): Promise<PushPayload | null>;\n}\n","types/plugins/gen/qr-scanner/sdk/qr-scanner.d.ts":"import { type NativeView, type PresentOptions } from \"../../../../plugin\";\nexport interface QRScanner extends NativeView {\n /** Fires per decoded camera frame: the decoded string, or `null` for a frame with no readable\n * code (expect those repeatedly while the user aims). The same code can be reported more than\n * once — `close()` or debounce once you have what you need. */\n onScan(callback: (data: string | null) => void): this;\n /** Request the camera permission, then present the scanner. The current destination (and its\n * loading state) stays visible until the scanner is ready; rejects if the camera is denied,\n * the host can't scan, or another navigation superseded this one. */\n open(options?: PresentOptions): Promise<void>;\n}\n/**\n * Create a QR scanner view. `QRScanner.isSupported` reports whether this host can scan at all —\n * check it before offering the feature.\n */\nexport declare const QRScanner: {\n (): QRScanner;\n /** Whether this host registered a \"qrScanner\" view. */\n readonly isSupported: boolean;\n};\n","types/plugins/gen/qr-scanner/sdk/qr-scanner.gen.d.ts":"import { ViewChannel } from \"../../../../plugin\";\nimport type { QRScannerEvents, QRScannerParams } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"qrScanner\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** A method of the contract. */\nexport type Method = never;\n/** Whether this host has the view \"qrScanner\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The view \"qrScanner\" with the wire's methods as its own. */\nexport declare class QRScannerBase extends ViewChannel<QRScannerEvents> {\n constructor(params?: QRScannerParams);\n}\n","types/plugins/permission.d.ts":"export declare const _requestCameraPermission: () => Promise<void>;\n","types/plugins/service.d.ts":"export interface Service {\n /** Invoke a method on the service (`battery.call(\"level\")`). Arguments and the result are\n * JSON-serialized; rejects when the host has no such service or the method reports an\n * error. The host session opens lazily on the first call. */\n call(method: string, ...args: any[]): Promise<any>;\n /** Subscribe to an event the service emits while a session is open\n * (`battery.on(\"change\", data => …)`). Payloads are JSON-decoded. */\n on(event: string, callback: (data?: any) => void): this;\n /** Remove a previously added listener. */\n off(event: string, callback: (data?: any) => void): this;\n /** Close the host session (stops whatever the service was doing). Listeners stay\n * registered — a later `call()` opens a fresh session that delivers to them again. */\n close(): void;\n}\n/**\n * A host-registered headless service — the UI-less sibling of `NativeView`. Use it for\n * services without a typed wrapper: native code registered in your app shell\n * (`engine.registerService(\"app.battery\") { … }`) or a third-party plugin's channel.\n * **Host-optional** — gate on `Service.isSupported` (the web editor registers none of them).\n *\n * ```ts\n * if (Service.isSupported(\"app.battery\")) {\n * const battery = Service(\"app.battery\")\n * battery.on(\"change\", data => { level.text = data.level + \"%\" })\n * const { level } = await battery.call(\"level\")\n * }\n * ```\n */\nexport declare const Service: {\n (name: string, params?: any): Service;\n /** Whether this host registered a service under `name`. */\n isSupported(name: string): boolean;\n};\n","types/runtime/app.d.ts":"export type AppState = \"active\" | \"background\";\n/** `\"landscape\"` — either landscape direction (sensor landscape), `\"portrait\"` — upright only,\n * `\"auto\"` — released: the device's own rotation rules apply. */\nexport type OrientationLock = \"auto\" | \"portrait\" | \"landscape\";\ntype AppEventMap = {\n /** The app left the foreground (home button, tab hidden, another app on top). Delivered before\n * the host halts the frame loop — the last chance to persist state / pause work. */\n pause: () => void;\n /** The app returned to the foreground; frames are running again. */\n resume: () => void;\n /** A link arrived while the app was running (warm deep link). `app.launchUrl` is already\n * updated to the same value when this fires. */\n url: (url: string) => void;\n /** The on-screen keyboard changed. `height` mirrors `app.keyboardHeight` (the raw overlap, see\n * there); `duration` is the platform's keyboard animation duration in ms (0 where none) — pass\n * it to `animateTo` to move a composer in sync with the keyboard. */\n keyboard: (height: number, duration: number) => void;\n};\nexport declare const app: {\n /** The SDK this app was compiled with (semver, e.g. `\"2.0.0\"`). Its major is the bundle ↔ runtime\n * contract: a host runs only bundles of its own major, and the launchers send it as `?sdk=` when\n * they fetch a published bundle — the platform keeps one bundle per major. */\n sdkVersion: string;\n /** Current lifecycle state. `\"background\"` while the app is not the foreground app / the tab is\n * hidden. `\"active\"` on hosts that don't track it. */\n readonly state: AppState;\n /** The URL the app was (most recently) opened with — the deep link — or `null` for a plain\n * launch. Warm links update it and fire the `\"url\"` event. */\n readonly launchUrl: string | null;\n /** On-screen keyboard height in logical px currently overlapping the app viewport, `0` when\n * hidden. This is the RAW overlap, independent of the focused input's `keyboardShrink` policy —\n * with the default shrink the layout already avoids the keyboard; the main consumer is overlay\n * mode (`keyboardShrink: false`), e.g. a chat composer's `pb`. `0` on hosts without an\n * on-screen keyboard. */\n readonly keyboardHeight: number;\n /** Lock the screen orientation — `\"landscape\"` for a horizontal game (the device rotates to\n * landscape right away and stays there whichever way it is held), `\"portrait\"` for upright\n * only, `\"auto\"` to release. Call it once at startup; the lock is per app run (it resets\n * when the app quits or restarts), so there is nothing to undo. The rotation arrives as an\n * ordinary resize — layouts reflow, a scene's viewport follows. Silent no-op on hosts\n * without a rotatable screen (desktop, headless, web). */\n setOrientation(mode: OrientationLock): void;\n /** Re-run this app's bundle in a fresh world — the platform's `location.reload()`. Pass `url`\n * to reboot with different launch arguments (the new run reads them via `app.launchUrl`),\n * `null` to reboot with a cleared one, or omit it to replay the current one. No-op on hosts\n * without world control (headless). */\n restart(url?: string | null): void;\n /** Leave this app. Inside the LeCodes viewer that returns to the launcher (the LeCodes home\n * screen); a standalone-built app leaves to the platform instead — Android backgrounds it,\n * iOS ignores the call (the platform forbids programmatic exit). */\n quit(): void;\n /** Global back-press fallback (Android back button/gesture — iOS has no system back). Fires\n * only when nothing else consumed the press: no open widget/modal claimed it, the current\n * screen has no `onBack`, every pager is at its tab root and the router is at its\n * stack root. The place for app-wide policy — e.g. double-press-to-quit:\n *\n * ```ts\n * let armedAt = 0\n * app.onBack(() => {\n * if (Date.now() - armedAt < 2000) { app.quit(); return }\n * armedAt = Date.now()\n * toast(\"Press back again to exit\")\n * })\n * ```\n *\n * Replaces the previous handler; pass `null` to remove. */\n onBack(callback: (() => void) | null): void;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: (() => void) | null): void;\n addEventListener<E extends keyof AppEventMap>(event: E, callback: AppEventMap[E]): void;\n removeEventListener<E extends keyof AppEventMap>(event: E, callback: AppEventMap[E]): void;\n};\nexport {};\n","types/runtime/appEvents.d.ts":"type AppEventCallback = (data?: string) => void;\nexport declare const appEventsOn: (event: string, cb: AppEventCallback) => void;\nexport declare const appEventsOff: (event: string, cb: AppEventCallback) => void;\ntype KeyboardCallback = (height: number, duration: number) => void;\nexport declare const keyboardEventsOn: (cb: KeyboardCallback) => void;\nexport declare const keyboardEventsOff: (cb: KeyboardCallback) => void;\nexport {};\n","types/runtime/channel.d.ts":"export {};\n","types/runtime/clipboard.d.ts":"export declare const clipboard: {\n /** Put `text` on the system clipboard. Silent no-op on hosts without clipboard access. */\n write(text: string): void;\n /** Read text from the system clipboard. Rejects when the platform has no clipboard access, the\n * user denied it, or there is nothing readable. */\n read(): Promise<string>;\n};\n","types/runtime/datetime.d.ts":"export type Locale = \"en\" | \"ru\";\nexport type DateInput = Date | number | string | DateValue;\nexport type Unit = \"ms\" | \"second\" | \"minute\" | \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\n/**\n * An immutable moment in time — the value returned by [`date()`]. Wraps a single epoch-millisecond\n * scalar (`t`); every method returns a new `DateValue` or a plain scalar, never mutating. Construct\n * it with `date(...)`, not `new`.\n */\nexport declare class DateValue {\n /** Epoch milliseconds — the one canonical scalar. Prefer `valueOf()`; this is public so `date(a)`\n * can read it back cheaply and so tooling can treat it as the value's single component. */\n readonly t: number;\n constructor(ms: number);\n /**\n * Format against a `day.js`-style token pattern (default `\"D MMMM YYYY\"`). Locale defaults to the\n * current device language.\n *\n * Tokens: `YYYY`/`YY` year · `MMMM`/`MMM`/`MM`/`M` month · `DD`/`D` day · `dddd`/`ddd` weekday ·\n * `HH`/`H` 24-hour · `hh`/`h` 12-hour · `mm`/`m` minute · `ss`/`s` second · `A`/`a` AM/PM.\n *\n * ```ts\n * date().format() // \"10 July 2026\" / \"10 июля 2026\"\n * date(ts).format(\"DD.MM.YYYY HH:mm\") // \"10.07.2026 14:05\"\n * date(ts).format(\"MMMM YYYY\", \"ru\") // \"Июль 2026\" (nominative — no day token)\n * ```\n */\n format(pattern?: string, locale?: Locale): string;\n /**\n * Human relative time vs `now` (default: the current time) — \"5 minutes ago\", \"in 2 days\",\n * \"5 минут назад\", \"через 2 дня\". Reads as \"just now\" under ~45 seconds; handles Russian number\n * agreement (`1 минуту` / `2 минуты` / `5 минут`). Locale defaults to the device language.\n */\n timeAgo(locale?: Locale, now?: DateInput): string;\n /** Add `n` of a unit, returning a new value. Linear units (`ms`…`week`) are scalar ms math;\n * `month`/`year` are calendar-aware (clamp on short months, like day.js). */\n add(n: number, unit: Unit): DateValue;\n /** Subtract `n` of a unit. Equivalent to `add(-n, unit)`. */\n subtract(n: number, unit: Unit): DateValue;\n /** Snap down to the start of a unit (local time): start of day/hour/month/year, etc. */\n startOf(unit: Unit): DateValue;\n /** Snap up to the end of a unit (local time): the last millisecond of the day/hour/month/… */\n endOf(unit: Unit): DateValue;\n /** Epoch milliseconds. Enables `+date(x)`, `date(a) < date(b)`, `date(a) - date(b)` via coercion. */\n valueOf(): number;\n /** Whole seconds since the epoch (Unix time). */\n unix(): number;\n /** Signed difference to `other`, in whole `unit`s (default `ms`), truncated toward zero. */\n diff(other: DateInput, unit?: Unit): number;\n isBefore(other: DateInput): boolean;\n isAfter(other: DateInput): boolean;\n isSame(other: DateInput): boolean;\n year(): number;\n /** 0-based month (0 = January), matching `Date.getMonth`. */\n month(): number;\n /** Day of the month, 1–31. */\n day(): number;\n /** Day of the week, 0 (Sunday)–6 (Saturday), matching `Date.getDay`. */\n weekday(): number;\n hour(): number;\n minute(): number;\n second(): number;\n /** A native `Date` snapshot of this value. */\n toDate(): Date;\n}\n/**\n * Create a `DateValue` — a locale-aware, immutable moment, dayjs-style. Accepts a `Date`, a\n * millisecond timestamp (`Date.now()`), a parseable string, or another `DateValue`; with no argument\n * it's the current time. Chain arithmetic and finish with `format` / `timeAgo`, both of which\n * understand **English** and **Russian** and default to the current device language\n * ([`device.language`](../runtime/device.ts)).\n *\n * ```ts\n * date().format(\"dddd, D MMMM\") // \"Friday, 10 July\" / \"пятница, 10 июля\"\n * date(ts).timeAgo() // \"5 minutes ago\" / \"5 минут назад\"\n * date().add(3, \"day\").startOf(\"day\").format(\"D MMMM\")\n * date(a).diff(b, \"hour\") // signed whole hours\n * date(a).isBefore(b) // boolean\n * ```\n */\nexport declare const date: (value?: DateInput) => DateValue;\n","types/runtime/device.d.ts":"import { Quat } from \"../math/quat\";\nimport { Vec3 } from \"../math/vec\";\ntype ResizeCallback = (width: number, height: number) => void;\ntype HdrChangeCallback = (headroom: number) => void;\ntype DeviceEventMap = {\n resize: ResizeCallback;\n /** Connectivity came back (best-effort, navigator.onLine semantics). */\n online: () => void;\n /** Connectivity was lost. */\n offline: () => void;\n /** The headroom the 3D engine renders to moved (`device.hdr.headroom`): the display ramped up to\n * its peak after launch, brightness changed, the window went to another screen. */\n hdrchange: HdrChangeCallback;\n};\n/** Semantic haptic styles for `device.vibrate`. Impact styles (`light`/`medium`/`heavy`/`soft`/\n * `rigid`) are a physical \"tap\" of varying weight; notification styles (`success`/`warning`/`error`)\n * cue an outcome; `selection` is a light tick for a value change. Chosen to map 1:1 onto iOS\n * `UIFeedbackGenerator` and, on Android, `HapticFeedbackConstants` / `VibrationEffect` — so the same\n * call feels native everywhere, rather than a duration that only web/Android can honor. */\nexport type HapticStyle = \"light\" | \"medium\" | \"heavy\" | \"soft\" | \"rigid\" | \"success\" | \"warning\" | \"error\" | \"selection\";\n/** Options for `device.motion.start`. */\nexport interface MotionOptions {\n /** Sensor update interval in seconds (default 1/60). The sensor fuses at ≥ this rate in the\n * background; you poll the freshest sample each frame, so this is a floor, not a sync. */\n interval?: number;\n /** Frame the readables are delivered in. \"world\" (default): engine Y-up, screen-oriented — drops\n * straight into `camera.quaternion` / any node. \"device\": the raw sensor frame, no conversion. */\n frame?: \"world\" | \"device\";\n}\nexport declare const device: {\n /** Which INPUT MODEL the app is running under — the thing to branch on when a build needs\n * mouse-look instead of on-screen sticks. It is not the OS name: a Mac reports `\"desktop\"`,\n * like Windows and Linux do (the OS/version detail is host-side, not here). */\n readonly platform: \"web\" | \"android\" | \"ios\" | \"desktop\" | string;\n readonly language: string;\n /** Display device-pixel ratio (physical px per logical/CSS px): 1 on standard displays, 2–3 on\n * retina / iOS. Bake a Canvas at this ratio for crisp output without hardcoding, e.g.\n * `new Canvas(w, h, { pixelRatio: device.pixelRatio })`. NOTE: the web 2D/GL surface currently\n * renders at logical resolution, so on web this only helps UI canvases / is forward-looking for\n * 2D; on iOS (physical surface) it makes 2D canvases crisp. Falls back to 1 if the host omits it. */\n readonly pixelRatio: number;\n /** Current display width in logical px — the same value the \"resize\" event delivers, but readable at\n * any time (not only inside the listener). 0 until the host has reported a size. */\n readonly width: number;\n /** Current display height in logical px — the same value the \"resize\" event delivers, readable at any\n * time. 0 until the host has reported a size. */\n readonly height: number;\n /** Opt into the precise-touch system where the platform supports it. OFF by default. When on, fast\n * strokes are sampled at the touch digitizer's full rate (iOS coalesced touches, ≈120–240 Hz) instead\n * of once per display frame (~60 Hz), so a pointer-heavy app (drawing, handwriting, dragging) gets more\n * points and smoother lines. Leave it off for tap/button UIs. No-op on hosts without a coalesced-input\n * concept (web already coalesces pointermove; headless). */\n setPreciseTouch(enabled: boolean): void;\n /** Fire a one-shot haptic of the given semantic `style` (default `\"medium\"`) — a physical tap on\n * supported hardware (iOS Taptic Engine, Android vibrator). Chosen by meaning, not duration, so it\n * feels native on each platform; see {@link HapticStyle}. Host-gated: a silent no-op where there's\n * no haptic hardware (iPad, older iPhones, web, headless). */\n vibrate(style?: HapticStyle): void;\n /** The host's performance overlay: one line over everything with the frames per second the\n * display actually got, how evenly they came (`66 fps · 73% even` is judder, `60 fps · 100% even`\n * is smooth), and the GPU's and the main thread's milliseconds per frame. The host measures and\n * draws it itself about once a second — nothing of it runs in the app's JS, so it does not change\n * what it measures. It belongs to the host, not to the project: it stays on when another project\n * is opened. Reads `false`, and writing does nothing, on hosts without one (web, headless). */\n statsOverlay: boolean;\n /** Device-orientation sensor (gyro + accelerometer, fused) for tilt/steering and magic-window /\n * 360° panoramas. Poll `attitude` / `gravity` inside setLoop; they return the freshest fused\n * sample, so the sensor rate need not match your frame rate. Host-gated: a no-op with no sensor. */\n motion: {\n /** Whether this device has the motion sensors at all (no gyro → false; iPad/older, web, headless). */\n readonly available: boolean;\n /** Whether updates are currently running (start succeeded and stop hasn't been called). */\n readonly enabled: boolean;\n /** Begin sensor updates. Resolves to whether it actually started (false = no sensor / denied).\n * Async so a web host can await its permission prompt; native resolves immediately. */\n start(options?: MotionOptions): Promise<boolean>;\n /** Stop sensor updates and release the sensor (battery). */\n stop(): void;\n /** Capture the current heading as \"forward\" — a yaw-only recenter (pitch/roll stay gravity-\n * referenced, so the horizon stays level). No-op in the \"device\" frame. */\n recenter(): void;\n /** The device's current orientation as a `Quat`. In the \"world\" frame (default) it's engine Y-up\n * and screen-oriented, so `camera.quaternion = device.motion.attitude` is a complete magic-window\n * / panorama camera. `Quat.identity` until the first sample arrives / when not running. */\n readonly attitude: Quat;\n /** Gravity direction for tilt controls. In the \"world\" frame it's SCREEN space (x → right, y →\n * down, matching clientX/clientY), orientation-aware — a 2D game reads `gravity.x / gravity.y`.\n * `(0,0,0)` when not running. */\n readonly gravity: Vec3;\n };\n /** The display's extended dynamic range — HDR. On a screen with headroom above SDR white (Apple's\n * XDR panels; the macOS host today) the 3D surface is float and the engine renders past 1.0:\n * 1.0 is the white of the UI and of a diffuse white surface, and the sun, emissives and speculars\n * climb up to `headroom` times that. Everywhere else it is SDR: `available` false, `headroom` 1,\n * the look setters remembered but invisible.\n *\n * Branch content on `available`, not on `headroom` — the live value ramps up from 1 over the\n * first seconds after launch and follows the brightness keys. Particle `emissive` is the thing\n * to raise: it is in post-exposure units (1 = white on screen) and everything above that clips on\n * SDR, so an HDR display is the only place a fireball peaking at 8 reads as one. */\n hdr: {\n /** Whether the surface can show anything above SDR white at all (`maxHeadroom > 1`). */\n readonly available: boolean;\n /** The peak the display can reach, as a multiple of SDR white (a 1600-nit XDR panel reports up\n * to 16). Constant for the surface; 1 on SDR. */\n readonly maxHeadroom: number;\n /** The headroom the engine renders to right now — the screen's current peak as a multiple of SDR\n * white, quantised to half-stops. Moves with brightness and the screen under the window\n * (`hdrchange` event); never below 1. */\n readonly headroom: number;\n /** How much of the picture reaches for the headroom, 0..1 (default 0.35). 0 touches only what\n * SDR clipped — faithful to the SDR grade, but a mostly-mid-tone frame then looks flat next to\n * the one bright spot; 1 lifts nearly everything above black toward the peak. A sunlit exterior\n * takes 1, a dim interior wants less. A host may pin it (`LECODES_HDR_STRENGTH`). */\n strength: number;\n /** Where white lands, as a multiple of SDR white, 1..8 (default 1) — the \"HDR brightness\" of a\n * console game's calibration screen, where paper white sits at ~200 nits against SDR's ~100.\n * It scales the WHOLE picture: at 1 a white wall is as bright as the UI's white, at 2 it is\n * twice that, and highlights still climb above it (the engine keeps `headroom / paperWhite` for\n * them, clamped at the peak). `strength` decides how much of the picture reaches for the\n * peak; this decides where the picture starts. 1.5–2 is the console norm; a game that wants to\n * read as \"HDR on\" rather than \"SDR with a brighter sun\" wants this over `strength`. A host may\n * pin it (`LECODES_HDR_PAPER_WHITE`). */\n paperWhite: number;\n };\n /** Current connectivity — best-effort navigator.onLine semantics: `false` only when the platform\n * is sure there's no network. `true` on hosts that don't track it. Change events: `\"online\"` /\n * `\"offline\"`. */\n readonly online: boolean;\n addEventListener<E extends keyof DeviceEventMap>(channel: E, callback: DeviceEventMap[E]): void;\n removeEventListener<E extends keyof DeviceEventMap>(channel: E, callback: DeviceEventMap[E]): void;\n};\nexport {};\n","types/runtime/fetch.d.ts":"export type FetchOptions = {\n body?: any;\n method?: string;\n headers?: Record<string, string>;\n useOnce?: boolean;\n onProgress?: (progress: {\n loaded: number;\n total?: number;\n }) => void;\n};\nexport interface FetchResponse {\n readonly status: number;\n json<T = any>(): T;\n text(): string;\n /** @deprecated A no-op: the body is freed with the response's handle (owned handles). Apps written\n * against the pre-owned SDK still call it after `text()` / `json()`; remove the call. */\n dispose(): void;\n}\nexport declare const fetch: (url: string, options?: FetchOptions) => Promise<FetchResponse>;\nexport declare const fetchLocal: (path: string) => FetchResponse;\n/** A handle to a picked / fetched file (see openFilePicker). */\nexport declare class File {\n readonly name: string;\n readonly size: number;\n constructor(systemId: number, name: string, size: number);\n}\ntype FormDataValue = string | number | boolean | File | FetchResponse;\nexport declare class FormData {\n private _entries;\n append(name: string, value: FormDataValue, filename?: string): void;\n delete(name: string): void;\n}\nexport {};\n","types/runtime/files.d.ts":"import { File, type FetchResponse } from \"./fetch\";\ntype OpenFilePickerOptions = {\n accept?: string;\n};\nexport declare function openFilePicker(options?: OpenFilePickerOptions & {\n multiple?: false;\n}): Promise<File | null>;\nexport declare function openFilePicker(options: OpenFilePickerOptions & {\n multiple: true;\n}): Promise<File[]>;\n/** Anything writable as-is: text, raw bytes, or a buffer the host already holds\n * (a picked `File`, a `FetchResponse`, a `Canvas.toFile()` snapshot). */\nexport type FileData = string | Uint8Array | ArrayBuffer | File | FetchResponse;\n/** One directory entry, as `files.ls` / `files.stat` report it. */\nexport type FileEntry = {\n /** The last path segment. */\n name: string;\n /** Relative to the listed directory, `/`-separated — equal to `name` unless the listing was\n * recursive. Join it onto the directory you listed to read the file. */\n path: string;\n kind: \"file\" | \"dir\";\n /** Bytes; 0 for a directory. */\n size: number;\n /** Last modification, ms since the epoch (a `Date` value). */\n modified: number;\n};\nexport declare const files: {\n /** Is there a filesystem here (desktop)? False on web/mobile, where every other call rejects. */\n readonly supported: boolean;\n /** Replace the file's contents, creating the parent folders on the way. */\n write(path: string, data: FileData): Promise<void>;\n /** Add to the end of the file, creating it (and the parent folders) when it isn't there yet. */\n append(path: string, data: FileData): Promise<void>;\n /** The whole file as UTF-8 text — null when there is no such file. */\n readText(path: string): Promise<string | null>;\n /** The whole file as bytes — null when there is no such file. */\n readBytes(path: string): Promise<Uint8Array | null>;\n /** Delete a file, or a directory (empty, or any directory with `{ recursive: true }`). Deleting\n * something already gone is success — what's promised is that the path is free afterwards. */\n rm(path: string, options?: {\n recursive?: boolean;\n }): Promise<void>;\n /** Create a directory and any missing parents. An existing directory is fine. */\n mkdir(path: string): Promise<void>;\n /** The entries of a directory, sorted by path — null when there is no such directory (an empty\n * one is `[]`, so `(await files.ls(\"saves\")) ?? []` covers both). `{ recursive: true }` walks\n * the subfolders too; each entry's `path` is then relative to the directory listed. A path that\n * is a file, not a directory, rejects. Filter in JS — `entries.filter(e => e.name.endsWith(\".json\"))`. */\n ls(path: string, options?: {\n recursive?: boolean;\n }): Promise<FileEntry[] | null>;\n /** What is at `path`: a file or a directory entry (`path` equal to `name`), or null when nothing\n * is there — `(await files.stat(p)) !== null` is the exists check. */\n stat(path: string): Promise<FileEntry | null>;\n};\nexport {};\n","types/runtime/input.d.ts":"/** Continuous channel ids — the `_creatorInput.read` contract (sdk/src/bridges/input.d.ts). */\nexport declare const InputChannel: {\n readonly MouseX: 0;\n readonly MouseY: 1;\n readonly MouseDX: 2;\n readonly MouseDY: 3;\n readonly WheelX: 4;\n readonly WheelY: 5;\n readonly PointerLocked: 6;\n readonly GamepadCount: 7;\n readonly PointerOnUI: 8;\n readonly GamepadBase: 16;\n readonly GamepadStride: 16;\n readonly PadConnected: 0;\n readonly PadLeftX: 1;\n readonly PadLeftY: 2;\n readonly PadRightX: 3;\n readonly PadRightY: 4;\n readonly PadLeftTrigger: 5;\n readonly PadRightTrigger: 6;\n};\nexport type InputEventName = \"keydown\" | \"keyup\" | \"gamepadconnected\" | \"gamepaddisconnected\";\n/** `keydown` / `keyup` payload. `code` is the same string `Input.key()` takes. */\nexport interface InputKeyEvent {\n readonly type: \"keydown\" | \"keyup\";\n /** Button code: KeyboardEvent.code ('KeyW', 'Space'), 'MouseLeft|Right|Middle|Back|Forward', or\n * 'GamepadSouth|East|West|North|L1|R1|L2|R2|Select|Start|L3|R3|Up|Down|Left|Right'. */\n readonly code: string;\n /** Which device: 'keyboard' | 'mouse' | 'gamepad'. */\n readonly source: \"keyboard\" | \"mouse\" | \"gamepad\";\n /** Pad index (0..3) for gamepad buttons, undefined otherwise. */\n readonly gamepad?: number;\n /** OS auto-repeat keydown (key still held) — ignore for one-shot actions. */\n readonly repeat: boolean;\n}\nexport interface InputGamepadEvent {\n readonly type: \"gamepadconnected\" | \"gamepaddisconnected\";\n readonly gamepad: number;\n}\ntype Listener<E> = (e: E) => void;\ntype InputEventMap = {\n keydown: InputKeyEvent;\n keyup: InputKeyEvent;\n gamepadconnected: InputGamepadEvent;\n gamepaddisconnected: InputGamepadEvent;\n};\n/** Mouse state — polled. Position is the cursor inside the viewport in logical px; `delta` is the\n * motion during the previous frame (raw where the OS offers it) and keeps counting while locked —\n * that's FPS look. Hosts without a mouse report zeros. */\nexport declare const mouse: {\n readonly position: {\n x: number;\n y: number;\n };\n readonly delta: {\n x: number;\n y: number;\n };\n /** Wheel notches during the previous frame (+y = wheel toward you / scroll down). */\n readonly wheel: {\n x: number;\n y: number;\n };\n /** Pointer lock: cursor hidden + confined, `delta` keeps flowing. Web grants it only from a user\n * gesture (call it in a 'keydown' handler for MouseLeft); hosts drop it on focus loss and\n * re-acquire on focus. Escape does NOT unlock by itself on native hosts — call `unlock()`. */\n readonly locked: boolean;\n /** The primary button went down on a UI element (a button, a scrollable, an input, a modal\n * backdrop) and is still held. Stays true wherever the cursor drifts until the release, so\n * `if (!Input.mouse.onUI) look(Input.mouse.delta)` never turns a HUD drag into camera look.\n * Always false while `locked`. A press that fell through to the scene reads false. */\n readonly onUI: boolean;\n lock(): boolean;\n unlock(): void;\n};\nexport type GamepadAxisName = \"leftX\" | \"leftY\" | \"rightX\" | \"rightY\" | \"leftTrigger\" | \"rightTrigger\";\nexport interface GamepadState {\n readonly index: number;\n readonly connected: boolean;\n /** Stick axes −1..1 (+Y = down, like the web Gamepad API), triggers 0..1. `deadzone` (default\n * 0.15) zeroes small stick drift — pass 0 for the raw value. */\n axis(name: GamepadAxisName, deadzone?: number): number;\n /** Held? Same as `Input.key(code, index)`. */\n button(code: string): boolean;\n /** Rumble: `strong` = the heavy low-frequency motor, `weak` = the light high-frequency one, both\n * 0..1, for `durationMs` (default 200, hosts cap at 5000). A new call replaces the running\n * effect. The host stops the motors by itself — after the duration, on focus loss and when the\n * project is swapped — so there is nothing to clean up. False when the pad or host has no motors. */\n rumble(strong: number, weak?: number, durationMs?: number): boolean;\n /** Stop the running rumble now. */\n stopRumble(): void;\n}\nexport declare const Input: {\n /**\n * Is a button held? `code` is the physical key (`KeyboardEvent.code`: 'ArrowRight', 'KeyW',\n * 'Space'), a mouse button ('MouseLeft', 'MouseRight', 'MouseMiddle') or a gamepad button\n * ('GamepadSouth' = A/Cross, 'GamepadR2' = right trigger as a button …). Poll inside setLoop for\n * frame-independent movement. `gamepad` scopes a Gamepad* code to one pad; omitted = any pad.\n */\n key(code: string, gamepad?: number): boolean;\n /** Listen for a discrete input moment. `keydown`/`keyup` cover EVERY button — keyboard, mouse,\n * gamepad — filter on `e.code`. Use these for one-shot actions (jump, shoot, charge-release);\n * `Input.key` for continuous ones (walk). */\n on<K extends InputEventName>(name: K, listener: Listener<InputEventMap[K]>): void;\n off<K extends InputEventName>(name: K, listener: Listener<InputEventMap[K]>): void;\n mouse: {\n readonly position: {\n x: number;\n y: number;\n };\n readonly delta: {\n x: number;\n y: number;\n };\n /** Wheel notches during the previous frame (+y = wheel toward you / scroll down). */\n readonly wheel: {\n x: number;\n y: number;\n };\n /** Pointer lock: cursor hidden + confined, `delta` keeps flowing. Web grants it only from a user\n * gesture (call it in a 'keydown' handler for MouseLeft); hosts drop it on focus loss and\n * re-acquire on focus. Escape does NOT unlock by itself on native hosts — call `unlock()`. */\n readonly locked: boolean;\n /** The primary button went down on a UI element (a button, a scrollable, an input, a modal\n * backdrop) and is still held. Stays true wherever the cursor drifts until the release, so\n * `if (!Input.mouse.onUI) look(Input.mouse.delta)` never turns a HUD drag into camera look.\n * Always false while `locked`. A press that fell through to the scene reads false. */\n readonly onUI: boolean;\n lock(): boolean;\n unlock(): void;\n };\n /** Gamepad `index` (0..3). Always returns an object — check `.connected`. */\n gamepad(index?: number): GamepadState;\n /** Indices of the currently connected gamepads. */\n gamepads(): number[];\n /** @internal — hosts/tests: deliver an event exactly as the host listener would. */\n _emit(kind: number, code: string, gamepad: number, repeat: number): void;\n};\nexport {};\n","types/runtime/media.d.ts":"import { Emitter } from \"../core/events\";\nimport { Texture } from \"../gl/Texture\";\ntype MediaEvents = {\n /** Fired at each loop boundary while `loop` is true. */\n loopReached: () => void;\n /** Fired once when playback reaches the end while `loop` is false. */\n completed: () => void;\n};\ndeclare abstract class MediaPlayer extends Emitter<MediaEvents> {\n protected _src: string;\n private _playing;\n private _loop;\n private _volume;\n play(): void;\n pause(): void;\n /** Pause and rewind to the start. */\n stop(): void;\n get playing(): boolean;\n set playing(value: boolean);\n get volume(): number;\n set volume(value: number);\n get loop(): boolean;\n set loop(value: boolean);\n /** Current playback position, in seconds. Settable to seek. */\n get time(): number;\n set time(value: number);\n /** Total media length in seconds (0 until metadata has loaded). */\n get duration(): number;\n /** @deprecated There is nothing to dispose — a player the app stops referencing is released by\n * the runtime (a playing one at its end). Kept as `stop()` so old code still silences the player;\n * call `stop()` / `pause()` instead. */\n dispose(): void;\n}\nexport declare class AudioPlayer extends MediaPlayer {\n constructor(src?: string);\n}\nexport declare class VideoPlayer extends MediaPlayer {\n constructor(src?: string);\n /** A 3D Texture that samples this video (e.g. for a Material.video()). Owned by the player. */\n get texture(): Texture;\n}\nexport {};\n","types/runtime/misc.d.ts":"import type { ColorInput } from \"../core/color\";\n/** Show a transient toast notification. */\nexport declare const toast: (msg: string) => void;\n/** Open `url` in the system browser / external handler (fire-and-forget, like `share`). Silent\n * no-op on hosts without one (headless). */\nexport declare const openURL: (url: string) => void;\nexport type SvgSourceValue = {\n readonly svg: string;\n /** The source-level tint (a mask recolor under the `tintColor` style, which wins): any color, or\n * a theme `var(--…)`. */\n tintColor: ColorInput | null;\n};\n/** Wrap raw SVG XML so it can be used as an image source. */\nexport declare const SvgSource: (svg: string) => SvgSourceValue;\n","types/runtime/net.d.ts":"import { Emitter } from \"../core/events\";\ntype SocketEvents = {\n open: () => void;\n message: (data: any) => void;\n close: (code?: number) => void;\n error: () => void;\n};\nexport declare class WebSocket extends Emitter<SocketEvents> {\n private _id;\n constructor(url: string);\n /** Send a text frame. */\n send(message: string): void;\n close(): void;\n private _onMessage;\n}\nexport {};\n","types/runtime/rpc.d.ts":"/**\n * Client transport for the app backend (docs/backend-plan.md §3.2 / §3.3). The compiler replaces\n * every `*.server.ts` module in the client bundle with a stub whose exports are built by the three\n * globals below — user code never calls them; it imports the server function and calls it.\n *\n * export const listNotes = __rpc(\"<serverUrl>\", \"notes.server.ts#listNotes\")\n * export const chat = __channel(\"<serverUrl>\", \"chat.server.ts#chat\")\n * export const db = __serverOnly(\"schema.server.ts#db\")\n *\n * Wire (implemented by the runner):\n * POST <serverUrl>/api/<id> body {\"args\":[…]}, `authorization: Bearer <session>` when known\n * — with a `File` among the arguments: multipart, the field `args` is\n * that JSON with `{\"$file\": <i>}` where the file stood, `file<i>` the files\n * → 200 {\"ok\":true,\"result\":…,\"session\"?:\"…\"} | {\"ok\":false,\"status\":n,\"message\":\"…\",\"session\"?:\"…\"}\n * WS <serverUrl>/ws the channel socket — its frames are ./wire.ts\n *\n * The session token is transport-owned (cookie-like): stored under `lecodes.session:<serverUrl>` in\n * localStorage, sent on every call and on the socket, replaced whenever a response carries `session`.\n * User code never sees it — \"am I logged in\" is an endpoint (`me()`), see the plan.\n */\nimport type { ChannelSubscription } from \"../server/channel\";\n/** Rejection value of a failed endpoint call: `status` mirrors the server's `ApiError`\n * (0 = the request itself failed: no network / no server). */\nexport declare class RpcError extends Error {\n readonly status: number;\n constructor(status: number, message: string);\n}\n/** Build the client proxy of endpoint `id`. Positional args travel as a JSON array. */\nexport declare const __rpc: (serverUrl: string, id: string) => (...args: unknown[]) => Promise<any>;\n/** A server-only export (db, models, helpers) referenced from client code: any use throws. */\nexport declare const __serverOnly: (id: string) => any;\n/**\n * Build the client proxy of channel `id` — what a `channel()` export of a `*.server.ts` file is in\n * the app (its type is the server's: src/server/channel.ts). `subscribe([...args,] handler, options?)`:\n * what stands before the handler travels to the channel's `groupBy`.\n */\nexport declare const __channel: (serverUrl: string, id: string) => {\n subscribe(...all: unknown[]): ChannelSubscription;\n publish(): never;\n};\n","types/runtime/service.d.ts":"export {};\n","types/runtime/share.d.ts":"import type { File, FetchResponse } from \"./fetch\";\nexport declare function share(media: File | FetchResponse, text?: string): void;\n","types/runtime/storage.d.ts":"export declare const localStorage: {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n};\n","types/runtime/touch.d.ts":"export declare class ClickEvent<T = any> {\n readonly type = \"click\";\n readonly pointerId: number;\n readonly clientX: number;\n readonly clientY: number;\n /** World-space hit position (2D scenes only; undefined in 3D). */\n worldX?: number;\n worldY?: number;\n target: T;\n constructor(clientX: number, clientY: number, pointerId: number);\n}\nexport interface TrackHandler {\n onMove?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onEnd?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onCancel?(): void;\n claim?: boolean | \"pan-x\" | \"pan-y\" | \"pan-down\" | \"pan-up\" | \"pan-left\" | \"pan-right\";\n}\nexport declare class TouchStartEvent<T = any> {\n readonly type = \"touchstart\";\n readonly pointerId: number;\n readonly clientX: number;\n readonly clientY: number;\n /** World-space hit position (2D scenes only; undefined in 3D). */\n worldX?: number;\n worldY?: number;\n target: T;\n constructor(clientX: number, clientY: number, pointerId: number);\n /** Capture subsequent moves/end for this pointer (drag/pan gestures). */\n track(handler: TrackHandler): void;\n}\n/** Delivered to a `UIButton` `onLongPress` handler when a finger is held on the button past the\n * host's long-press threshold. Like `TouchStartEvent` it can `track(...)` the rest of the gesture —\n * so the common \"press-and-hold, then drag to move\" flow is one handler: start the drag from here. */\nexport declare class LongPressEvent<T = any> {\n readonly type = \"longpress\";\n readonly pointerId: number;\n readonly clientX: number;\n readonly clientY: number;\n /** World-space hit position (2D scenes only; undefined in 3D). */\n worldX?: number;\n worldY?: number;\n target: T;\n constructor(clientX: number, clientY: number, pointerId: number);\n /** Capture subsequent moves/end for this pointer — drag the element after the hold. */\n track(handler: TrackHandler): void;\n}\n/** What a hover `track()` takes: the cursor's moves inside the element (only delivered when\n * `onMove` is present — otherwise the host never crosses into JS for them), `onEnd` when it\n * leaves (with the last position), `onCancel` when the element went away underneath it. No\n * `claim`: a hover competes with nothing. */\nexport interface HoverTrackHandler {\n onMove?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onEnd?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onCancel?(): void;\n}\n/** Delivered to a `UIButton` `onMouseEnter` handler when a mouse cursor (no button) enters the\n * button. There is no separate leave event: `ev.track({ onEnd })` follows this hover to its end,\n * `onMove` follows the cursor inside — the visual state itself is the reserved `$hovered` class.\n * Touch never produces one. */\nexport declare class MouseEnterEvent<T = any> {\n readonly type = \"mouseenter\";\n readonly clientX: number;\n readonly clientY: number;\n target: T;\n constructor(clientX: number, clientY: number);\n /** Follow this hover: moves inside the element, its end (the cursor left), its cancel. */\n track(handler: HoverTrackHandler): void;\n}\n","types/runtime/wire.d.ts":"/**\n * The frames of the channel socket (`<serverUrl>/ws`) — the ONE description both ends are written\n * against: the client transport (./rpc.ts) and the server's hub (../server/channelHub.ts, which the\n * runner and the local backend of `lecodes dev` both run). JSON text frames, one per message.\n *\n * → hello who is on this socket. Sent first, and again whenever the session changes: the server\n * then DROPS the socket's subscriptions (they were granted to someone else) and the\n * client sends them again, under new ids.\n * → sub subscribe to channel `ch`; `args` are what the app passed to `subscribe` before the\n * handler — the channel's `groupBy` reads them.\n * → unsub\n * ← session a token minted while the socket was served (the first contact of a guest): the client\n * stores it; nothing is dropped, the server already has it.\n * ← ok the subscription stands; `group` is where the server put it (null = a channel without\n * groups). The client learns its group only here — it never names one.\n * ← err refused (a hook threw) — the subscription is gone.\n * ← ev one published message, addressed by channel + group so the server sends one frame to\n * every socket of a group; the client hands it to each of its subscriptions there.\n *\n * A group's value is not a secret: its subscriber is told it.\n */\n/** What `groupBy` may answer. `42` and `\"42\"` are two groups. */\nexport type ChannelGroup = string | number;\nexport type ClientFrame = {\n t: \"hello\";\n session: string | null;\n} | {\n t: \"sub\";\n id: number;\n ch: string;\n args: unknown[];\n} | {\n t: \"unsub\";\n id: number;\n};\nexport type ServerFrame = {\n t: \"session\";\n session: string;\n} | {\n t: \"ok\";\n id: number;\n group: ChannelGroup | null;\n} | {\n t: \"err\";\n id: number;\n status: number;\n message: string;\n} | {\n t: \"ev\";\n ch: string;\n group: ChannelGroup | null;\n data: unknown;\n};\n","types/scene/defineScene.d.ts":"import { use, ref, make, type AspectEntry, type MakeEntry as SharedMakeEntry } from \"./grammar\";\nimport type { Vec3Like } from \"../math/vec\";\nimport { Scene, type SceneOptions } from \"../gl/Scene\";\nimport { Node } from \"../gl/Node\";\nimport { Mesh } from \"../gl/Mesh\";\nimport { Model } from \"../gl/Model\";\nimport { type LightmapTransmit } from \"../gl/Lightmap\";\nimport { type FoliageOptions } from \"../gl/Foliage\";\nimport { type TerrainLayer, type TerrainRegion, type TerrainOptions } from \"../gl/terrain/Terrain\";\nimport { Light, type SunOptions } from \"../gl/Light\";\nimport { type MaterialDef } from \"./material\";\nimport type { CapsuleOptions, CylinderOptions, PlaneOptions, SphereOptions } from \"../gl/Geometry\";\nimport { GizmoBuffer } from \"./gizmos\";\nexport type MeshDef = {\n kind: \"box\";\n size?: Vec3Like | number;\n} | ({\n kind: \"sphere\";\n} & SphereOptions) | ({\n kind: \"cylinder\";\n} & CylinderOptions) | ({\n kind: \"capsule\";\n} & CapsuleOptions) | ({\n kind: \"plane\";\n} & PlaneOptions);\nexport type LightDef = {\n kind: \"sun\";\n} & SunOptions;\n/** A stamp: the terrain conforms to another node of this file (a road) at load — see Terrain.conform. */\nexport type TerrainStampDef = {\n /** Path of the node (a Mesh, a Model, or a node holding them) the ground hugs. */\n node: string;\n offset?: number;\n falloff?: number;\n mode?: \"both\" | \"lower\" | \"raise\";\n};\n/** The `terrain: {}` source block (docs/terrain-plan.md §3.3): a `.terrain` file OR a flat grid to\n * generate from, its layers, and the stamps / holes applied at load (in order, after every node of the\n * file exists — a road built by `make()` is a valid target). Add `Shape { heightfield: true }` +\n * `Physics { motion: 'static' }` in `aspects` for collision. */\nexport type TerrainNodeDef = {\n /** `asset('./assets/terrain/valley.terrain')` — heights / holes / control from a file. */\n data?: string;\n size?: number;\n sizeX?: number;\n sizeZ?: number;\n cellSize?: number;\n chunk?: number;\n layers?: TerrainLayer[];\n normals?: TerrainOptions[\"normals\"];\n tint?: TerrainOptions[\"tint\"];\n stamps?: TerrainStampDef[];\n holes?: TerrainRegion[];\n};\nexport type { MaterialDef };\nexport { use, ref, make };\nexport type { AspectEntry };\n/** A `make(fn, args)` source entry whose factory returns a 3D {@link Node}. */\nexport type MakeEntry<A extends Record<string, unknown> = Record<string, unknown>> = SharedMakeEntry<A, Node>;\n/** Transform overrides for one INTERNAL node of a GLB model or a prefab instance\n * (`overrides` on a model/prefab node, keyed by part path). */\nexport type ModelOverrideDef = {\n position?: Vec3Like;\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n visible?: boolean;\n /** Materials by primitive SLOT of this part (`0` for a single-material mesh; the editor lists\n * the slots with their glTF material names): a material asset, an inline def, or a custom\n * shader. Slots left out keep the glTF material. */\n materials?: Record<number | string, MaterialDef>;\n};\n/** Camera projection settings, shared by the `camera:` source block and the top-level `camera:`\n * block. All optional — an omitted key keeps the host default (60° / 0.01 / 1000). */\nexport type CameraProjectionDef = {\n /** Vertical field of view in degrees (default 60) — smaller is a longer lens. */\n fov?: number;\n /** Near clip distance (default 0.01). */\n near?: number;\n /** Far clip distance = view range (default 1000); geometry past it is culled. */\n far?: number;\n};\n/** The `camera: {}` source block — projection settings for the node that drives the view. */\nexport type CameraNodeDef = CameraProjectionDef;\nexport type SceneNodeDef = {\n mesh?: MeshDef;\n /** GLB url — `asset('./hero.glb')`. */\n model?: string;\n light?: LightDef;\n /** A heightmap ground — see {@link TerrainNodeDef}. */\n terrain?: TerrainNodeDef;\n /** The scene camera as a NODE: in play mode `scene.camera` follows this node's world transform\n * every frame (so movement aspects on it are camera flythroughs); the editor shows a frustum\n * marker and refuses to delete the last camera node. The first camera node in file order wins;\n * cameras inside prefabs are ignored (like a prefab's `camera:` block). */\n camera?: CameraNodeDef;\n /** A code-built subtree — `make(factoryFn, { ...literal args })`. */\n make?: MakeEntry<any>;\n /** Another scene file used as a reusable composition — the imported handle:\n * `import streetlamp from './streetlamp.scene'` … `lamp: { prefab: streetlamp }`. Its nodes\n * instantiate under this node per instance (env/camera are the instancing file's business and\n * are ignored); `ref()`s inside the prefab resolve file-locally, per instance. */\n prefab?: SceneHandle<any>;\n /** Material for a `mesh` source. */\n material?: MaterialDef;\n /** Model/prefab sources: transform overrides for the INTERNAL nodes, keyed by part path\n * (see the part-path grammar above `modelPartRows`). Unresolved paths are ignored. */\n overrides?: Record<string, ModelOverrideDef>;\n /** On a CHILD of a model/prefab node: parent this node to that INTERNAL part of the parent's\n * asset at build time (part path — the same grammar `overrides` keys use), e.g. a flashlight\n * in a hand. The transform stays local to the part. A stale path (asset changed) falls back\n * to the parent root with a console warning. */\n mount?: string;\n position?: Vec3Like;\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n visible?: boolean;\n /** Editor-only: viewport manipulation won't target this node (fields still edit). No runtime effect. */\n locked?: boolean;\n /** Editor-only, `model` nodes: the POSE the scene editor shows — a clip looped while editing\n * (`time` freezes it at that second instead), so attachments / sight lines / a first-person eye\n * are placed against the animated pose, not the rest pose. Never applied when the scene runs. */\n editor?: {\n clip?: string;\n time?: number;\n };\n /** `mesh` / `model` nodes: real-time shadow flags. On a `model` they reach every renderable of\n * the GLB instance, so `castShadows: false` on a first-person viewmodel covers the whole gun. */\n castShadows?: boolean;\n receiveShadows?: boolean;\n /** Baked lighting (a scene with `env.lightmap`): is this model/mesh node a lightmap STATIC — a\n * receiver and an occluder in the bake, real-time shadow casting off once the bake applies?\n * Default: static unless a `Physics` aspect moves the node (`dynamic` — Physics' default — or\n * `kinematic`). Set it only to override that rule; prefab subtrees inherit the verdict. */\n lightmap?: boolean;\n /** `model` nodes: vegetation — load through the FOLIAGE tier (wind, touch bending, per-copy tint; see\n * `Foliage`). `{ fade: [start, end] }` also thins the cards out over that distance range (m) and drops the\n * copy past `end` — for ground cover. The fade is per ASSET: every node of the same GLB shares it. */\n foliage?: boolean | {\n fade?: [number, number];\n };\n /** Navigation (a scene with `env.navmesh`, see navmesh.md): every STATIC body is walkable by\n * default. `false` leaves this one out of the bake; `'unwalkable'` cuts its footprint out\n * (nobody stands on or crosses it). */\n nav?: false | \"unwalkable\";\n /** The named navmesh area this static body's surface belongs to (a key of `env.navmesh.areas`). */\n navArea?: string;\n aspects?: readonly AspectEntry<any>[];\n children?: Record<string, SceneNodeDef>;\n};\nexport type SceneCameraDef = CameraProjectionDef & {\n position?: Vec3Like;\n /** Point the camera looks at. */\n target?: Vec3Like;\n};\n/** `env.lightmap` — the level's baked lighting (engines/bake): the files `lecodes lightmap bake`\n * writes. Absent = real-time only. */\nexport type SceneLightmapDef = {\n /** `asset('./assets/lightmap/level.bake')` */\n data: string;\n /** `asset('./assets/lightmap/level-light.ktx2')` — or, for a bake that took more than one atlas PAGE\n * (`lecodes lightmap bake --pages`), every page in order: `[asset('x-light.ktx2'), asset('x-light_1.ktx2')]`. */\n light: string | string[];\n /** `asset('./assets/lightmap/level-aux.ktx2')` (pages like `light`) — sun / sky visibility + light direction. */\n aux: string | string[];\n /** DEBUG: the page sets a `lecodes lightmap bake --split` wrote (`<stem>-direct[_n].ktx2`, `<stem>-indirect[_n].ktx2`),\n * pages like `light` — the `Lightmap.debug(\"direct\" | \"indirect\")` views bind them in place of `light`. */\n direct?: string | string[];\n indirect?: string | string[];\n /** `asset('./assets/lightmap/level-probes.ktx2')` — the bake's reflection probes (one prefiltered cubemap of the level's\n * radiance per probe; every static reflects the nearest). Absent = statics reflect the sky's SH alone. */\n probes?: string;\n /** FOR THE BAKE: the radiance in cd / m² of emission 1.0 on this level (emissive factor x strength x map) - every lit\n * region of an emissive surface bakes as a rectangle lamp. An imported pack's emission is a LOOK (the school's panels\n * say 10); this is where the level says what they give: a 1.3 m ceiling panel of ~8000 lm is ~1600 nits. Default: what\n * the camera makes of 1.0 (`1.2 x 2^EV100`). 0 = emissive surfaces light nothing. `--emissive-nits` overrides. */\n emissiveNits?: number;\n /** `false` = the emissive surfaces light nothing in the bake - the level is lit by its lamps (`Light.point` with a\n * `bakeArea` next to every panel, the Unity packs' way) and the panels are decoration; `emissiveNits` then only says how\n * bright their glow is DRAWN (scene-referred: nits through the camera's exposure). Default true. */\n emissiveBake?: boolean;\n /** FOR THE BAKE: materials that let light THROUGH them, by glTF material name (`\"name*\"` = every name with that start) →\n * the share of a shadow ray that passes, tinted by the material's base colour x map: `{ mat_awning: 0.3 }` puts the\n * awning's warm, patterned light on the sand. The surface stays opaque - baked, drawn as before, a shadow caster.\n * `{ through, diffuse }` splits it: `through` goes straight (the picture of the map), `diffuse` is scattered by the\n * fibres (the underside glows, a soft fill with no picture) - dense canvas: `{ through: 0.08, diffuse: 0.25 }`. */\n transmit?: Record<string, LightmapTransmit>;\n /** `asset('./assets/lightmap/level.lgrid')` — THE LIGHT GRID for movers: every node a Physics aspect or a\n * CharacterController moves (and what code marks with `Lightmap.track`) takes its ambient light from the bake at the\n * place it is at, whatever its shader. Absent = movers keep the scene's IBL. */\n volume?: string;\n /** A DEBUG multiplier on the atlas' lux (default 1). */\n lightScale?: number;\n};\n/** `env.navmesh` — the level's navigation mesh (see navmesh.md): the file `lecodes navmesh bake`\n * writes, the agent size it is built for, and the named areas. Absent = no navigation. */\nexport type SceneNavmeshDef = {\n /** `asset('./assets/nav/<scene>.navmesh')` */\n data: string;\n /** The agent the mesh is built for (radius 0.4 · height 1.8 · climb 0.4 · slope 50 by default). */\n agent?: {\n radius?: number;\n height?: number;\n climb?: number;\n slope?: number;\n };\n /** Named areas → traversal cost (1 = plain ground); nodes join one with `navArea`. */\n areas?: Record<string, number>;\n};\nexport type SceneDef = {\n env?: SceneOptions & {\n lightmap?: SceneLightmapDef;\n navmesh?: SceneNavmeshDef;\n foliage?: FoliageOptions;\n };\n camera?: SceneCameraDef;\n nodes?: Record<string, SceneNodeDef>;\n};\ntype SourceNodeOf<N extends SceneNodeDef> = N extends {\n model: string;\n} ? Model : N extends {\n mesh: MeshDef;\n} ? Mesh : N extends {\n light: LightDef;\n} ? Light : Node;\ntype AspectsOf<N extends SceneNodeDef> = N extends {\n aspects: readonly AspectEntry<infer A>[];\n} ? A : never;\ntype NodeOf<N extends SceneNodeDef> = [\n AspectsOf<N>\n] extends [never] ? SourceNodeOf<N> : With<SourceNodeOf<N>, AspectsOf<N>>;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\ntype ChildMapsOf<T extends Record<string, SceneNodeDef>, P extends string> = {\n [K in keyof T & string]: T[K] extends {\n children: infer C extends Record<string, SceneNodeDef>;\n } ? NodesOf<C, `${P}${K}/`> : never;\n}[keyof T & string];\ntype NodesOf<T extends Record<string, SceneNodeDef>, P extends string = \"\"> = {\n [K in keyof T & string as `${P}${K}`]: NodeOf<T[K]>;\n} & ([ChildMapsOf<T, P>] extends [never] ? unknown : UnionToIntersection<ChildMapsOf<T, P>>);\nexport type SceneNodes<D extends SceneDef> = D[\"nodes\"] extends Record<string, SceneNodeDef> ? NodesOf<D[\"nodes\"]> : Record<string, Node>;\nexport type LoadedScene<D extends SceneDef> = {\n scene: Scene;\n nodes: SceneNodes<D>;\n /** Path lookup — typed for this scene's literal paths, `Node | null` for arbitrary strings. */\n get: {\n <P extends keyof SceneNodes<D> & string>(path: P): SceneNodes<D>[P];\n (path: string): Node | null;\n };\n};\n/** One instance of a scene file built as a subtree (`handle.instantiate`). */\nexport type SceneInstance<D extends SceneDef> = {\n /** The wrapper node the file's nodes build under — position it, parent it, hide it. */\n root: Node;\n nodes: SceneNodes<D>;\n /** Anchor the instance on one of its own nodes: `root`'s local transform is set so that\n * `inner` coincides with the frame `root` is parented to (its origin and axes). One-shot,\n * from the CURRENT pose of `inner` — a rig's attachment frame (the eye place of a\n * first-person arms scene, the grip of a held prop). */\n alignTo(inner: Node): void;\n get: LoadedScene<D>[\"get\"];\n /** Remove the subtree from the scene and destroy it. */\n dispose(): void;\n};\n/** One INTERNAL node of a loaded GLB (editor introspection). */\nexport type ModelPartRow = {\n path: string;\n name: string;\n depth: number;\n node: Node;\n};\n/** Flatten a model's (or prefab instance's) internal hierarchy to rows (depth-first, the root\n * excluded). `__generated` containers are derived output, and def-built nodes (`_sceneDef` —\n * plain or `mount`ed children of the model) are addressed by their own def paths — both are\n * not parts, skipped. Filtering BEFORE segment math keeps `name[i]` indices stable no matter\n * what defs are parented in. */\nexport declare const modelPartRows: (root: Node) => ModelPartRow[];\n/** Where a def node attaches: its `mount` part when it resolves, else the parent itself. */\nexport declare const attachHost: (parent: Node, def: SceneNodeDef, path: string) => Node;\n/** The static verdict for one node def (the editor's \"Baked lighting\" switch shows the same rule).\n * Children of a mover are movers too — buildNodes carries that down, this is the node's own verdict. */\nexport declare const isLightmapStatic: (def: SceneNodeDef) => boolean;\n/** Edit mode: play the preview pose on a model node (`editor: { clip, time }`) — idempotent, the\n * harness re-applies it on inspector edits. No clip = back to the rest pose. */\nexport declare const applyEditorPose: (node: Node, pose: {\n clip?: string;\n time?: number;\n} | undefined) => void;\n/** Edit mode: otherwise-invisible nodes (empties, `camera:` nodes) get an ANCHORED gizmo marker —\n * an axis cross / a frustum in the node's local frame (scene/gizmos.ts) — so they show and pick\n * in the viewport. Never scene content: nothing renders in Filament, nothing outlines, and the\n * engine follows the node live, so the buffer is filled once and lives on the node\n * (`_editorMarker`) — `sceneEditor.gizmos()` reads it off the handle's own def nodes, so a removed\n * node's marker goes with its record and prefab / instance internals (not selectable) draw none. */\nexport declare const addEditorMarker: (node: Node, def: SceneNodeDef) => void;\n/** fov / near / far from a camera block onto the live camera. The build path leaves an empty block\n * alone (a host may run with its own configured fov); `reset` — the editor's live patch — fills\n * omitted keys with the defaults instead, so clearing a field in the inspector takes effect. */\nexport declare const applyCameraProjection: (scene: Scene, def: CameraProjectionDef, reset?: boolean) => void;\nexport declare const foreignRuns: Map<Node, EditorRun[]>;\n/** One live editor-run aspect instance (edit mode only). */\nexport type EditorRun = {\n /** Absolute path of the host def node (re-keyed on rename/reparent). */\n hostPath: string;\n node: Node;\n /** Index within the def's `aspects` array — the doc's aspect index addresses it. */\n index: number;\n inst: {\n rebuild?(): void | Promise<void>;\n };\n /** Async rebuild() supersession counter (see safeRebuild). */\n generation: number;\n /** Mutable props snapshot — `sceneEditor.setProp` updates it and re-derives `deps`. Holds the\n * DOC-LITERAL `$ref` strings (never resolved paths): the inspector's doc-sync compares these\n * against the file's props, so rewriting them would re-fire on every render. */\n props: Record<string, unknown>;\n /** ABSOLUTE paths the ref() props resolved to — a change to any of them (or anything inside\n * their subtrees) re-runs rebuild(). Re-derived after every structural change. */\n deps: Set<string>;\n /** Editor lines drawn by the last rebuild() (`Gizmos.*` calls — see scene/gizmos.ts). */\n gizmos: GizmoBuffer;\n};\n/** Re-assign every ref-carrying prop from the CURRENT nodes map — a live patch replaces node\n * instances, so a generator's resolved fields would otherwise point at destroyed nodes. */\nexport declare const assignRefProps: (run: EditorRun, nodes: Record<string, Node>) => void;\n/** EditorRun.index for a node's make() run (aspect runs use their array index, always >= 0). */\nexport declare const MAKE_INDEX = -1;\nexport declare class SceneHandle<D extends SceneDef = SceneDef> {\n readonly def: D;\n private _loading?;\n constructor(def: D);\n /** Instantiate the scene (idempotent — subsequent calls return the same instance). Does not open. */\n load(): Promise<LoadedScene<D>>;\n /** Load and make active. */\n open(): Promise<LoadedScene<D>>;\n /**\n * Build this scene file as a reusable SUBTREE inside an existing scene — a weapon under a hand\n * bone, a streetlamp per street corner — as many times as you like (unlike `load()`, which is\n * the one-instance \"scene as a level\" path). The nodes build under a fresh wrapper node (`root`)\n * parented to `parent` (or left unparented); `env` / `camera` are ignored like a prefab's. The\n * file's transforms are local to the wrapper, so author it with the wrapper as the attachment\n * point. `ref()`s resolve per instance; aspects attach per instance. `dispose()` removes the\n * subtree from the scene and destroys it.\n */\n instantiate(opts: {\n scene: Scene;\n parent?: Node | null;\n name?: string;\n }): Promise<SceneInstance<D>>;\n}\n/**\n * Define a scene as data — the default export of a `.scene.ts` file. Returns a typed handle:\n * `const { scene, nodes, get } = await handle.open()` gives `nodes[path]` typed by its source\n * block (Mesh / Model / Light / Node) with its `use(...)`d aspects attached — root nodes read as\n * plain properties (`nodes.hero`), nested ones by path (`nodes['hero/halo']` / `get('hero/halo')`).\n */\nexport declare const defineScene: <const D extends SceneDef>(def: D) => SceneHandle<D>;\n","types/scene/editor.d.ts":"import { type AspectClassInfo } from \"../core/fields\";\nimport { InspectorUI, type InspectorEvent, type InspectorWidget } from \"../core/InspectorUI\";\nimport type { Material } from \"../gl/Material\";\nimport type { Node } from \"../gl/Node\";\nimport { type ModelPartRow, type SceneHandle, type SceneNodeDef } from \"./defineScene\";\nimport { GizmoBuffer, type GizmoBatch } from \"./gizmos\";\ntype Handle = SceneHandle<any>;\nexport declare const sceneEditor: {\n patchNode: (handle: Handle, path: string, def: SceneNodeDef | null) => Promise<Node | null>;\n renameNode: (handle: Handle, path: string, newName: string) => string | null;\n reparentNode: (handle: Handle, path: string, newParentPath: string | null) => string | null;\n nodeChanged: (handle: Handle, path: string) => void;\n modelParts: (handle: Handle, path: string) => Promise<ModelPartRow[]>;\n describeAspects: (handle: Handle) => AspectClassInfo[];\n setProp: (handle: Handle, hostPath: string, index: number, key: string, value: unknown) => boolean;\n setMakeArg: (handle: Handle, hostPath: string, key: string, value: unknown) => boolean;\n gizmos: (handle: Handle) => {\n version: number;\n batches: GizmoBatch[];\n };\n inspectorRender: (handle: Handle, hostPath: string, index: number, props: Record<string, unknown>, event?: InspectorEvent) => InspectorWidget[] | null;\n /** The preview pose of a model node (`editor: { clip, time }`) — idempotent; no clip = the rest pose. */\n applyPose: (node: Node, pose: {\n clip?: string;\n time?: number;\n } | undefined) => void;\n isLocked: (node: Node) => boolean;\n setLocked: (node: Node, locked: boolean) => void;\n /** Assign a material def to one slot of a node (a material asset handle, an inline def, a shader). */\n assignMaterial: (node: Node, slot: number, def: import(\"./material\").MaterialDef) => Promise<Material>;\n /** One parameter into a live material: a value, or a texture URL that loads in. */\n setMaterialParam: (material: Material, name: string, value: import(\"./material\").MaterialParamValue | null) => Promise<void>;\n isBuiltinMaterial: (material: Material) => boolean;\n forgetMaterial: (node: Node, slot: number) => void;\n GizmoBuffer: typeof GizmoBuffer;\n withGizmoScope: <T>(buffer: GizmoBuffer, fn: () => T) => T;\n runCard: (ui: InspectorUI, render: (ui: InspectorUI) => void, event?: InspectorEvent) => InspectorWidget[];\n /** The registry `registerEditorWindow` / `registerEditorTool` fill (`*.editor.ts` files). */\n plugins: {\n windows: {\n title: string;\n render: import(\"./editorPlugins\").EditorWindowFn;\n }[];\n tools: {\n name: string;\n hooks: import(\"./editorPlugins\").EditorToolHooks;\n }[];\n };\n};\n/** The contract of an editor's in-world half with the SDK — the type of the `__sceneEditor` global. */\nexport type SceneEditorApi = typeof sceneEditor;\nexport {};\n","types/scene/editorPlugins.d.ts":"import type { InspectorUI } from \"../core/InspectorUI\";\n/** A geometry hit under the viewport pointer, handed to tools. Physics builds raycast the scene's\n * meshes (precise); otherwise (and on misses) the hit falls back to the ground plane (y = 0). */\nexport type EditorRayHit = {\n point: [number, number, number];\n normal: [number, number, number];\n /** Absolute path of the scene-file node the hit belongs to (\"city/in1/pt1\") — null for\n * ground-plane fallback hits. */\n node: string | null;\n};\n/**\n * The editor scripting API handed to windows and tools. Nodes are addressed by ABSOLUTE PATH —\n * '/'-joined names from the scene root; a root node's path is its bare name. Doc-op methods write\n * the scene DOCUMENT through the editor's normal commit path (undo, file, live patching all\n * included); they return false / no-op when the document can't take the edit (sibling-name\n * collision, unknown path).\n */\nexport type EditorApi = {\n /** The currently selected node path (or `path::part` key for asset internals), null when\n * nothing is selected. */\n readonly selection: string | null;\n select(path: string | null): void;\n /** The scene document's nodes: absolute path, sibling-unique display name, source kind\n * (mesh / model / light / group / …). */\n nodes(): {\n path: string;\n name: string;\n kind: string;\n }[];\n /** First unused \"base\", \"base2\", \"base3\", … name among the SIBLINGS under `parentPath`\n * (scene root when omitted). */\n uniqueName(base: string, parentPath?: string): string;\n /** Add a ROOT node from plain def data (scene-file grammar; a string `model` value means an\n * asset path). `name` may not contain '/' or ':'. One undo step unless grouped by `transact`. */\n addNode(name: string, def: Record<string, unknown>): boolean;\n /** Write one def prop (transforms apply live; anything else patches/re-runs the node). */\n setProp(path: string, key: string, value: unknown): boolean;\n removeNode(path: string): void;\n /** Duplicate a node; returns the copy's path (null when it can't). */\n duplicate(path: string): string | null;\n /** Raycast the scene under a viewport pixel (same hit rules as tool clicks). */\n raycast(screenX: number, screenY: number): EditorRayHit | null;\n /** Group every doc edit inside `fn` into ONE undo step. */\n transact(fn: () => void): void;\n /** Read one def prop of a node as document data (`asset()` refs come as `{ $asset: \"./x\" }`);\n * undefined when the node or key doesn't exist. */\n getProp(path: string, key: string): unknown;\n /** Write a BINARY asset file for a node (a terrain's `.terrain`, a baked mask…). `ref` = the\n * node's existing def-relative `asset()` ref to overwrite, or null to create `./<name>` at the\n * project root (a free name is picked on collisions). Resolves to the ref to store in the node's\n * def (`{ $asset: ref }` via `setProp`), null when the host can't write files. Not a doc edit —\n * it is not undoable; keep the doc pointing at the file. */\n writeAsset(path: string, ref: string | null, name: string, bytes: Uint8Array): Promise<string | null>;\n};\nexport type EditorWindowFn = (ui: InspectorUI, editor: EditorApi) => void;\nexport type EditorToolHooks = {\n /** CSS cursor for the viewport while this tool is active (default \"crosshair\"). */\n cursor?: string;\n /** A short glyph (one character / emoji) for the tool's toolbar button — tools without one all\n * share the generic wand icon, so any editor with two or more tools should set it. */\n icon?: string;\n /** A viewport click while the tool is active — `hit` is the raycast result under the pointer.\n * Viewport clicks route to the tool while it is active. */\n onViewportClick?(hit: EditorRayHit, editor: EditorApi): void;\n /** Drag tools (brushes): a primary-button drag in the viewport routes here instead of orbiting\n * the camera — start / every pointer move (with the hit under it, null while off-world) /\n * release. A tool with `onDragStart` gets NO `onViewportClick` for the same gesture. */\n onDragStart?(hit: EditorRayHit, editor: EditorApi): void;\n onDrag?(hit: EditorRayHit | null, editor: EditorApi): void;\n onDragEnd?(editor: EditorApi): void;\n /** The pointer moved over the viewport with no button down (throttled to the frame) — draw a\n * brush cursor through `Gizmos`; null when nothing is under it. */\n onHover?(hit: EditorRayHit | null, editor: EditorApi): void;\n};\n/** Register an editor panel — a collapsible overlay docked over the viewport (the inspector rail\n * stays selection-scoped). A window that emits `ui.toolButton` for a tool becomes that tool's\n * settings panel: activating the tool expands and highlights it. `render` re-runs immediate-mode\n * on every interaction — same protocol as `static inspector` cards. */\nexport declare const registerEditorWindow: (title: string, render: EditorWindowFn) => void;\n/** Register a viewport tool — a toolbar entry beside move/rotate/scale (activate it there or via\n * `ui.toolButton(label, name)`). While active, viewport clicks arrive as raycast hits. */\nexport declare const registerEditorTool: (name: string, hooks: EditorToolHooks) => void;\n","types/scene/gizmos.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Mat4Like } from \"../math/mat4\";\nimport type { Vec3Like } from \"../math/vec\";\n/** The anchor of a gizmo call: any object with an engine entity id (a `Node`). */\nexport type GizmoAnchor = {\n readonly id: number;\n};\nexport type GizmoStyle = {\n /** Any color (a CSS color string, `0xRRGGBB`, `[r, g, b(, a)]`; its alpha multiplies `alpha`);\n * default a neutral light gray. */\n color?: ColorInput;\n /** 0..1, default 1. */\n alpha?: number;\n /** Anchor: points are in this node's LOCAL frame (scale ignored); the lines follow the node\n * live, are pickable (a click selects the node) and turn the selection accent when it is\n * selected. Omit for world-space lines (not pickable). */\n node?: GizmoAnchor | null;\n};\n/** One color batch of LINES (flat `[x,y,z, x,y,z]` per segment) — what a host hands the engine\n * (`color` a CSS color string, '#rrggbbaa' from here). With `entityId` the segments are in that\n * entity's local frame (see GizmoStyle.node). */\nexport type GizmoBatch = {\n color: string;\n alpha: number;\n segments: number[];\n entityId?: number;\n};\n/** The per-run collector (owned by the scene loader's EditorRun). Batches are keyed by style so a\n * hundred same-colored segments cost one draw. */\nexport declare class GizmoBuffer {\n batches: GizmoBatch[];\n private _byStyle;\n clear(): void;\n segments(style: GizmoStyle | undefined): number[];\n}\n/**\n * Editor-only line drawing, available inside generator `rebuild()`, `make()` factories and editor\n * tool hooks. Points are WORLD space. Drawn by the scene editor's viewport overlay (depth-test\n * off — a path through a wall is still a path); invisible everywhere else.\n */\nexport declare const Gizmos: {\n /** One segment from `a` to `b`. */\n line(a: Vec3Like, b: Vec3Like, style?: GizmoStyle): void;\n /** Consecutive segments through `points`; `closed` joins the last point back to the first. */\n polyline(points: readonly Vec3Like[], style?: GizmoStyle & {\n closed?: boolean;\n }): void;\n /** A wireframe camera frustum looking down −Z: the four edges from the origin to a rect\n * `length` metres ahead sized by `fov` (vertical, degrees) × `aspect` (default 16:9), plus an\n * \"up\" fin above the rect. Anchor it (`{ node }`) for a camera node's marker — the frustum\n * then follows the node's pose; `matrix` places an unanchored one in world space. */\n frustum(fov: number, style?: GizmoStyle & {\n aspect?: number;\n length?: number;\n matrix?: Mat4Like;\n }): void;\n /** A three-axis cross centred on `p` (a point marker); `size` = half extent, default 0.1. */\n cross(p: Vec3Like, size?: number, style?: GizmoStyle): void;\n};\n","types/scene/grammar.d.ts":"import type { Aspect, AspectCtor } from \"../core/Aspect\";\nimport type { Node } from \"../gl/Node\";\n/** One aspect to attach, created by `use(Ctor, props)`. */\nexport type AspectEntry<A extends Aspect<any, any> = Aspect<any, any>> = {\n ctor: AspectCtor<A>;\n props?: Partial<A>;\n};\n/** Reference an aspect in a scene file: `aspects: [use(Physics, { motion: 'static' })]`. Props are\n * typechecked against the aspect's fields, exactly like `node.aspect(Ctor, props)`. */\nexport declare const use: <A extends Aspect<any, any>>(ctor: AspectCtor<A>, props?: Partial<A>) => AspectEntry<A>;\n/** A `make(fn, args)` source entry — see {@link make}. `N` is the node family the factory returns\n * (3D `Node` by default; a `.scene2d.ts` file's factories return `Node2D`). */\nexport type MakeEntry<A extends Record<string, unknown> = Record<string, unknown>, N = Node> = {\n fn: (args: A) => N | Promise<N>;\n args?: A;\n};\n/**\n * A code-created source in a scene file: `tower: { make: make(buildTower, { floors: 5 }), … }`.\n * The factory runs after every scene node exists (so `ref()` args resolve, forward references\n * included) and its returned subtree mounts under the def node — the def's transform stays\n * editor-owned, so moving the node never re-calls the factory. Args must be literal data (same\n * grammar as aspect props); in the editor they edit as fields, and an arg change re-CALLS the\n * factory live — the code is already in the bundle, so no compile happens. Keep factories pure\n * builders: same args → same subtree, no side effects outside the returned nodes.\n */\nexport declare const make: <A extends Record<string, unknown>, N>(fn: (args: A) => N | Promise<N>, args?: A) => MakeEntry<A, N>;\n/**\n * Reference another scene node by PATH in an aspect's props:\n * `use(Road, { from: ref('pointA'), to: ref('lane/pointB') })`. Resolves to the live node when\n * aspects attach — after EVERY node of the scene exists, so declaration order doesn't matter.\n * Resolution is scoped upward from the host node (like variable scoping): the host's own children\n * first, then its siblings, then each ancestor's scope up to the scene root. The FIRST segment\n * binds the scope; the remaining segments descend from there. Refs address def nodes only (no\n * `::`/`name[i]` asset-internal segments); an unknown path resolves to `null` (type your aspect\n * field `Node | null`). Scene files only — hand-written code passes nodes directly:\n * `node.aspect(Road, { from: nodes.pointA })`.\n */\nexport declare const ref: <T = Node>(path: string) => T;\nexport declare const isNodeRef: (v: unknown) => v is {\n $ref: string;\n};\n/** Resolve one ref string against a path-keyed nodes record, scoped upward from `hostPath` (own\n * children → parent's scope (siblings + the host itself) → each ancestor scope → root, `\"\"`).\n * The ref's FIRST segment binds the scope — a match there is final even when the rest of the\n * path doesn't exist (lexical shadowing). Returns the target's ABSOLUTE path, or null.\n * `Object.hasOwn`, not indexing: a node named `constructor` must not resolve via the prototype. */\nexport declare const resolveRefPath: (nodes: Record<string, unknown>, hostPath: string, ref: string) => string | null;\n/** Swap `ref()` markers in aspect props for the live nodes (top level + one array level deep),\n * resolved scoped-upward from `hostPath` (\"\" = root scope only — the 2D flat-map case). */\nexport declare const resolveRefs: <N>(props: Record<string, unknown> | undefined, nodes: Record<string, N>, hostPath?: string) => Record<string, unknown> | undefined;\n/** ABSOLUTE paths of the nodes a props record's ref() values resolve to (editor dep tracking).\n * An unresolved ref contributes no dep — the handle re-derives deps after structural changes. */\nexport declare const collectRefDeps: (props: Record<string, unknown>, nodes: Record<string, unknown>, hostPath: string) => Set<string>;\n/** The edit-mode flag an editor host sets before running the bundle (shared by both formats). */\nexport declare const EDIT_FLAG = \"__lecodesSceneEdit\";\nexport declare const isEditMode: () => boolean;\n","types/scene/level.d.ts":"import { Node } from \"../gl/Node\";\nimport { type Vec3Like } from \"../math/vec\";\n/** One placement handed to a `build` function (all coordinates local to the group). */\nexport type LevelSpot = {\n /** 0-based placement index. */\n index: number;\n /** Local position the node will be placed at (before jitter was already applied). */\n position: [number, number, number];\n /** Yaw in degrees the node will face (already resolved from the `yaw` option). */\n yaw: number;\n /** Deterministic per-call random stream (seeded) — use for per-spot variation. */\n rng: () => number;\n};\n/** What to place: a GLB url (loaded once, cloned per spot), or a builder function. A builder\n * returning `null` skips that spot (thin a line, punch a gap in a grid). */\nexport type LevelBuild = string | ((spot: LevelSpot) => Node | null | Promise<Node | null>);\n/** Static collision for url builds: 'mesh' = exact triangles, 'convex' = convex hull,\n * 'box' = auto box from the mesh bounds, 'none' (default) = no collider. */\nexport type LevelCollider = \"mesh\" | \"convex\" | \"box\" | \"none\";\ntype PlaceCommon = {\n build: LevelBuild;\n /** Static Shape+Physics attached to url-built nodes (default 'none'). Function builds attach\n * their own aspects instead. */\n collider?: LevelCollider;\n /** Facing: degrees, 'random', 'face' (forward +Z toward the helper's direction), or 'align'\n * (the model's X length-axis along the direction — what fence/wall panels want). Each helper\n * picks its natural default. */\n yaw?: number | \"random\" | \"face\" | \"align\";\n /** Random XZ offset per spot, meters: a radius, or [maxX, maxZ]. */\n jitter?: number | [number, number];\n /** Seed for the deterministic random stream (default 1). */\n seed?: number;\n /** Child name prefix (default: the url's basename, else 'item'). */\n name?: string;\n};\nexport type LevelLineOptions = PlaceCommon & {\n from: Vec3Like;\n to: Vec3Like;\n /** Fixed number of placements (endpoints included when count > 1)… */\n count?: number;\n /** …or a spacing in meters (placements from `from` toward `to`, last one ≤ `to`). */\n step?: number;\n};\nexport type LevelGridOptions = PlaceCommon & {\n /** Grid center (default [0,0,0]). */\n center?: Vec3Like;\n cols: number;\n rows: number;\n /** Cell size in meters: one number or [alongX, alongZ]. */\n spacing: number | [number, number];\n};\nexport type LevelRingOptions = PlaceCommon & {\n /** Ring center (default [0,0,0]). */\n center?: Vec3Like;\n radius: number;\n count: number;\n /** Start angle in degrees (default 0 = +X). */\n start?: number;\n /** Arc to cover in degrees (default 360 = full ring, end exclusive). */\n arc?: number;\n /** 'face' orientation for rings: toward the center ('in', default) or away ('out'). */\n facing?: \"in\" | \"out\";\n};\nexport type LevelScatterOptions = PlaceCommon & {\n /** Rectangle center (default [0,0,0]). */\n center?: Vec3Like;\n /** Rectangle extent in meters: [sizeX, sizeZ] or one number for a square. */\n size: number | [number, number];\n count: number;\n /** Minimum distance between any two placements (rejection-sampled; the helper places as many\n * as fit within the attempt budget and logs when it falls short). */\n minSpacing?: number;\n /** Keep-out circles `{ x, z, r }` (local), or a predicate — return true to REJECT a point. */\n avoid?: {\n x: number;\n z: number;\n r: number;\n }[] | ((x: number, z: number) => boolean);\n /** Y for every placement (default 0 — scatter is planar; vary height in a build fn). */\n y?: number;\n};\nexport type LevelPlaceOptions = PlaceCommon & {\n /** Explicit spots: [x, y, z] or [x, y, z, yawDegrees]. */\n at: (readonly number[])[];\n};\n/** Procedural level building — see the module header. All helpers return a Promise<Node> group to\n * return from a `make()` factory (or add to a scene from plain code). */\nexport declare const Level: {\n line: (opts: LevelLineOptions) => Promise<Node>;\n grid: (opts: LevelGridOptions) => Promise<Node>;\n ring: (opts: LevelRingOptions) => Promise<Node>;\n scatter: (opts: LevelScatterOptions) => Promise<Node>;\n place: (opts: LevelPlaceOptions) => Promise<Node>;\n /** The seeded PRNG the helpers use (mulberry32) — for custom generators that must stay\n * deterministic alongside them. */\n rng: (seed: number) => (() => number);\n};\nexport {};\n","types/scene/material.d.ts":"import type { ColorInput } from \"../core/color\";\nimport { Material, type LitMaterialOptions, type UnlitMaterialOptions } from \"../gl/Material\";\nimport type { Node } from \"../gl/Node\";\n/** A shader parameter value as scene files write it: number, boolean, `#colour`, texture URL\n * (`asset('./x.png')`), or a numeric vector. */\nexport type MaterialParamValue = number | boolean | string | number[];\ntype WithMapUrl<T> = Omit<T, \"map\"> & {\n /** Base-colour texture — a `Texture`, a `Canvas`, or `asset('./x.png')` (a URL string). */\n map?: LitMaterialOptions[\"map\"] | string;\n};\nexport type LitMaterialDef = WithMapUrl<LitMaterialOptions>;\nexport type UnlitMaterialDef = WithMapUrl<UnlitMaterialOptions>;\n/** A custom Filament shader (`asset('./x.mat')` — compiled by the platform / `lecodes shaders`)\n * plus its parameter values. */\nexport type ShaderMaterialDef = {\n shader: string;\n params?: Record<string, MaterialParamValue>;\n};\nexport type MaterialDef = {\n lit: LitMaterialDef;\n} | {\n unlit: UnlitMaterialDef;\n} | {\n shadow: ColorInput;\n} | ShaderMaterialDef\n/** A material asset (`import m from './x.material'`) — one shared instance. */\n | MaterialHandle\n/** A code-level Material instance — valid at runtime; the editor shows it read-only. */\n | Material;\n/** The data forms of MaterialDef (everything but a live instance / handle). */\nexport type MaterialData = Exclude<MaterialDef, MaterialHandle | Material>;\n/** Push one parameter into a live material. Textures load asynchronously — the returned promise\n * settles once the value is applied (immediately for scalars). */\nexport declare const applyMaterialParam: (material: Material, name: string, value: MaterialParamValue | null) => Promise<void>;\n/** Build a live Material from a data def. Resolves once every texture it names has loaded. */\nexport declare const createMaterialFromData: (def: MaterialData) => Promise<Material>;\n/**\n * A material asset: the default export of a `*.material.ts` file. `load()` yields ONE shared\n * `Material` (cached); scene files hand the handle to `material:` and the loader resolves it.\n * The editor edits the asset live through `setParam` / `reset` — every node the handle was\n * applied to follows (`_users`).\n */\nexport declare class MaterialHandle {\n def: MaterialData;\n private _instance;\n private _loading;\n /** Every (node, slot) this handle was applied to through a scene — the editor re-assigns them\n * when the asset's shader changes. */\n readonly _users: Set<{\n node: Node;\n slot: number;\n }>;\n constructor(def: MaterialData);\n /** The shared material instance (built on first use). */\n load(): Promise<Material>;\n /** The live instance, if built yet. */\n get material(): Material | null;\n /** Editor: assign this material to `node`'s `slot`, remembering the user. */\n _applyTo(node: Node, slot: number): Promise<Material>;\n /** Editor: one parameter value, applied live to the shared instance (a texture loads in). */\n setParam(name: string, value: MaterialParamValue | null): void;\n /** Editor: replace the whole definition (a shader/kind switch) — rebuilds the instance and\n * re-assigns every user. */\n reset(def: MaterialData): Promise<Material>;\n}\n/** Resolve any `material:` value to a live Material (a handle's shared instance, a data def's\n * fresh one, a code instance as is). */\nexport declare const resolveMaterialDef: (def: MaterialDef) => Promise<Material>;\n/** Resolve and assign a `material:` value to one slot of a node (tracking handle users). */\nexport declare const assignMaterialDef: (node: Node, slot: number, def: MaterialDef) => Promise<Material>;\n/**\n * Define a material as data — the default export of a `*.material.ts` file. Import it into scene\n * files (`material: handle`) or code (`const m = await handle.load()`).\n */\nexport declare const defineMaterial: (def: MaterialData) => MaterialHandle;\nexport {};\n","types/server/auth/api.d.ts":"/**\n * `db.auth` — the BUNDLE side of sign-in, what `*.server.ts` code calls on a db made with\n * `defineDb({...}).withAuth({ model: \"User\" })`:\n *\n * const db = defineDb({ User, Post }).withAuth({ model: \"User\" })\n *\n * export async function register(login: string, password: string, name: string) {\n * await db.auth.signUpWithPassword(login, password, { name })\n * }\n * export async function me() { return db.auth.user().select({ id: true, name: true }) }\n * export async function removePost(id: number) {\n * await db.auth.requireUser({ role: \"admin\" }).select({ id: true })\n * …\n * }\n *\n * The platform knows a request's session and the ID of its user (the host resolved the token before\n * the endpoint ran). Everything else about a user is a row of the project's own model, and is READ:\n * `user()` / `requireUser()` are queries over that model — typed by it, run when awaited — narrowed to\n * the user of the request. Sign-in operations forward to the host's `AuthOps` on\n * `globalThis.__lecodesAuth` (a seam: the compiled bundle carries its own SDK copy).\n */\n/** The collections of a db with auth, by role (defineDb.ts). */\nexport type AuthCollections = {\n model: string;\n user: any;\n session: any;\n identity: any;\n};\nexport declare const createAuthApi: (tables: () => AuthCollections) => {\n user: () => any;\n requireUser: (where?: Record<string, unknown>) => any;\n readonly sessionId: number;\n signUpWithPassword: (login: string, password: string, data?: Record<string, unknown>) => Promise<void>;\n signInWithPassword: (login: string, password: string) => Promise<void>;\n setPassword: (password: string) => Promise<void>;\n sendCode: (email: string) => Promise<void>;\n signInWithCode: (email: string, code: string) => Promise<void>;\n signIn: (userId: number) => Promise<void>;\n signOut: () => Promise<void>;\n readonly sessions: any;\n readonly identities: any;\n};\n","types/server/auth/appConfig.d.ts":"/**\n * The project's `app.json` subset the server runtime reads: the app's name (the sign-in mail).\n *\n * This module is a placeholder the COMPILER REPLACES: `compileServerBundle({ app })` puts a module with the\n * real values at this same path in chisel's file map (project files win over SDK files), so every SDK module\n * that imports `app` gets the project's config as a plain dependency — no globals, no evaluation-order games.\n * Outside a compiled bundle (tests, tooling) `globalThis.__lecodesApp` can stand in.\n */\nexport type AppConfig = {\n name?: string;\n};\nexport declare const app: AppConfig;\n","types/server/auth/models.d.ts":"/**\n * The two models sign-in adds to a database — `defineDb({...}).withAuth({ model: \"User\" })`:\n *\n * Session one device: the hash of its token, and the user it is signed in as (none = a guest)\n * Identity one way a user signs in: `email:<address>` or `login:<name>` (with the password's hash\n * when one is set) — several per user.\n *\n * They are the PLATFORM's: a project never declares them and never writes to them — it may refer to a\n * session (`t.one(\"Session\")`: a guest's cart) and read both through `db.auth.sessions` /\n * `db.auth.identities`, which leave the secrets out. The user model is the project's own, an ordinary\n * `model({...})`: the platform creates a row of it the first time someone signs in and knows nothing\n * of it but the id.\n */\nexport type { AppConfig } from \"./appConfig\";\n/** What an `Identity` row is of: an email, or a login (a name with no address behind it). */\nexport type IdentityProvider = \"email\" | \"login\";\nexport declare const AUTH_SESSION_MODEL = \"Session\";\nexport declare const AUTH_IDENTITY_MODEL = \"Identity\";\n/** A session as a project reads it (`db.auth.sessions`, a `t.one(\"Session\")` relation). */\nexport declare const sessionPublicFields: () => {\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n lastSeenAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n revoked: import(\"../db\").Field<boolean, {\n kind: \"scalar\";\n scalar: \"bool\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n};\nexport type SessionPublicFields = ReturnType<typeof sessionPublicFields>;\n/** The whole `Session`; `user` points at the model `withAuth` named. */\nexport declare const sessionFields: (userModel: string) => {\n pendingEmail: import(\"../db\").Field<string, {\n kind: \"scalar\";\n scalar: \"string\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n codeHash: import(\"../db\").Field<string, {\n kind: \"scalar\";\n scalar: \"string\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n codeExpires: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n codeAttempts: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"int\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n user: import(\"../db\").Field<never, {\n kind: \"one\";\n scalar: \"\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: string;\n }>;\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n lastSeenAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n revoked: import(\"../db\").Field<boolean, {\n kind: \"scalar\";\n scalar: \"bool\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n /** sha256 of the bearer token the device holds — the token itself is never stored. */\n tokenHash: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n};\n/** A sign-in method as a project reads it (`db.auth.identities`) — no hash. */\nexport declare const identityPublicFields: () => {\n /** `\"email\" | \"login\"` */\n provider: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** What the person types to sign in: the address, or the login. */\n subject: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** When the subject was proven (a code). Unset = a password sign-up whose address wasn't confirmed. */\n verifiedAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n};\nexport type IdentityPublicFields = ReturnType<typeof identityPublicFields>;\n/** The whole `Identity`. */\nexport declare const identityFields: (userModel: string) => {\n /** `<provider>:<subject>` — marcidb has no composite @unique, this is the one-row-per-identity guarantee. */\n key: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** scrypt hash of the password (`email` / `login` identities). */\n hash: import(\"../db\").Field<string, {\n kind: \"scalar\";\n scalar: \"string\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n /** `\"email\" | \"login\"` */\n provider: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** What the person types to sign in: the address, or the login. */\n subject: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** When the subject was proven (a code). Unset = a password sign-up whose address wasn't confirmed. */\n verifiedAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n user: import(\"../db\").Field<never, import(\"../db/fields\").Meta<{\n kind: \"one\";\n model: string;\n }>>;\n};\n","types/server/auth/types.d.ts":"/**\n * Shared shapes of the auth layer. Two sides meet through them:\n * - the BUNDLE side (`db.auth`, ./api.ts) — what `*.server.ts` code calls;\n * - the HOST side (./host.ts) — sessions, passwords and email codes, run by the runner with the\n * project's db handle. Installed on `globalThis.__lecodesAuth`.\n */\nimport type { RequestContext } from \"../context\";\n/** Per-request auth state, resolved by the host before the endpoint runs (`RequestContext.auth`): the\n * device's session and the id of the user it is signed in as. Nothing of the user's row — a project\n * reads that itself (`db.auth.user()`). */\nexport type AuthState = {\n sessionId: number;\n userId: number | null;\n /** A token to hand back to the client in this response (a new guest session, or a rotation). */\n issuedToken?: string;\n};\n/** Host operations `db.auth` forwards to (all request-scoped through `ctx`). A sign-in resolves once the\n * session is bound; who it is bound to is read through `db.auth.user()`. */\nexport type AuthOps = {\n /** `data` = the fields of the new user's row (the project's own model). */\n signUpWithPassword(ctx: RequestContext, login: string, password: string, data?: Record<string, unknown>): Promise<void>;\n signInWithPassword(ctx: RequestContext, login: string, password: string): Promise<void>;\n setPassword(ctx: RequestContext, password: string): Promise<void>;\n sendCode(ctx: RequestContext, email: string): Promise<void>;\n signInWithCode(ctx: RequestContext, email: string, code: string): Promise<void>;\n signIn(ctx: RequestContext, userId: number): Promise<void>;\n signOut(ctx: RequestContext): Promise<void>;\n /** The sessions of the current user (or just this device's, when signed out), as a query. */\n sessions(ctx: RequestContext): any;\n /** The current user's sign-in methods, as a query — the hash is not in it. */\n identities(ctx: RequestContext): any;\n};\n","types/server/channel.d.ts":"/**\n * Channels: the server's messages to the app. A server function is a call from the app to the\n * server; a channel is the other direction, typed by the same export.\n *\n * export const postsChannel = channel<Post>() // to everyone listening\n * export const noticesChannel = channel<Notice>() // to each their own\n * .groupBy(async () => (await db.auth.requireUser().select({ id: true })).id)\n *\n * postsChannel.publish(post) // server\n * noticesChannel.publish(userId, notice)\n *\n * postsChannel.subscribe(post => …) // app\n * noticesChannel.subscribe(notice => …)\n *\n * `groupBy` runs on the server when an app subscribes, with what the app passed to `subscribe`\n * before the handler, and answers the group that subscriber is in; `publish(group, message)` reaches\n * that group. `authorize` only decides who may listen. Both refuse by throwing (`ApiError`), and\n * both run in the request scope of the subscriber, so `db.auth` works in them.\n *\n * A channel's identity is its export (`<path>#<name>`), assigned by the runtime when the bundle is\n * loaded (`loadServerModules`); `publish` before that is an error. Delivery goes through the\n * `globalThis.__lecodesPublish` seam the host installs (same reason as ./context.ts: the bundle\n * carries its own SDK copy). In the app the export is another object altogether — the proxy\n * `__channel` of src/runtime/rpc.ts — which is why `subscribe` here only throws.\n */\nimport type { ChannelGroup } from \"../runtime/wire\";\nexport type { ChannelGroup };\n/** What `subscribe` answers: the subscription lives until `close()`. */\nexport type ChannelSubscription = {\n close(): void;\n};\nexport type SubscribeOptions = {\n /** The connection dropped and came back: what was published in between is lost — read the state again. */\n reconnect?: () => void;\n /** The server refused the subscription (a hook threw): an `RpcError`, its `status` the hook's.\n * Without it the refusal is logged. The subscription is not over: the server is asked again\n * when the session changes, so this may be called more than once. */\n error?: (e: Error & {\n readonly status: number;\n }) => void;\n};\n/** A channel every subscriber hears alike. */\nexport interface Channel<M> {\n /** Who may listen: runs on the server at every subscription, throw to refuse. */\n authorize(check: () => void | Promise<void>): Channel<M>;\n /** Split the subscribers: `group` runs on the server at every subscription — with what the app\n * passed to `subscribe` — and answers the group of that subscriber. Throw to refuse. */\n groupBy<K extends ChannelGroup, A extends unknown[] = []>(group: (...args: A) => K | Promise<K>): GroupedChannel<M, K, A>;\n /** Server: send `message` to every subscriber (at most once — nothing is kept for a socket that is away). */\n publish(message: M): void;\n /** App: listen until `close()`. */\n subscribe(handler: (message: M) => void, options?: SubscribeOptions): ChannelSubscription;\n}\n/** A channel whose subscribers are in groups (`groupBy`). */\nexport interface GroupedChannel<M, K extends ChannelGroup, A extends unknown[]> {\n /** Server: send `message` to the subscribers of `group`. */\n publish(group: K, message: M): void;\n /** App: listen until `close()`; the arguments before the handler go to the channel's `groupBy`. */\n subscribe(...args: [...args: A, handler: (message: M) => void, options?: SubscribeOptions]): ChannelSubscription;\n}\ntype Publisher = (channelId: string, group: ChannelGroup | null, message: unknown) => void;\n/** Host hook (runner / local backend / test harness): where `publish` delivers to. */\nexport declare const setChannelPublisher: (publisher: Publisher | null) => void;\nexport declare const isChannelGroup: (v: unknown) => v is ChannelGroup;\nexport declare const channel: <M = unknown>() => Channel<M>;\nexport declare const isChannel: (v: unknown) => v is ChannelRecord;\n","types/server/context.d.ts":"/**\n * Request context for server code. The runner keeps the current request in an AsyncLocalStorage\n * and exposes it through `globalThis.__lecodesRequest` — a *global* seam on purpose: the compiled\n * server bundle carries its own copy of this module (chisel bundles the SDK in), so the host can't\n * hand it a value by import. `request` reads through that seam; outside a request (module load,\n * timers after the response) every member is undefined.\n */\nexport type RequestContext = {\n /** Endpoint id `<path>#<export>` (or the channel id for a subscription's hooks). */\n id: string;\n headers: Record<string, string>;\n ip?: string;\n /** Bearer session token as sent by the client transport (raw; auth resolves it). */\n sessionToken?: string;\n /** Set by the auth runtime after resolving the token — read via `db.auth`, not here. */\n auth?: unknown;\n /** The files a multipart call carried, as the receiving process left them (./files/host.ts `Upload`). */\n uploads?: unknown[];\n /** What `/files/<id>/<name>` is appended to in a stored file's url: the backend's own base, as this request reached it. */\n filesBase?: string;\n};\ntype Provider = () => RequestContext | undefined;\n/** Host hook (runner / test harness): install the current-request provider. */\nexport declare const setRequestProvider: (provider: Provider | null) => void;\n/** The current request (server global). Undefined members outside a request. */\nexport declare const request: {\n readonly id: string | undefined;\n readonly headers: Record<string, string>;\n readonly ip: string | undefined;\n};\nexport {};\n","types/server/db/defineDb.d.ts":"/**\n * `model({...})` + `defineDb({ User, Post })` — the schema registry and the typed db handle.\n *\n * Runtime responsibilities: validate relation names, resolve `t.many()` back-fields, emit the `.marci`\n * schema text (`db.$schema`), and turn collection calls into lazy `Op`s over a `MarciTransport`\n * (`marcidb-embedded` handle, HTTP client, or a test fake). The transport is either passed to\n * `defineDb(models, { transport })` or provided by the host through `setDbTransport()` — user code\n * never sees a connection string.\n */\nimport { type FieldDef } from \"./fields\";\nimport { type MarciTransport } from \"./marci/query\";\nimport type { Db, Fields, Model, Schema, ValidateRefs } from \"./types\";\nexport declare const model: <F extends Fields>(fields: F) => Model<F>;\n/** Host hook: the runner/dev-server installs the project's transport before loading user code. */\nexport declare const setDbTransport: (transport: MarciTransport | null) => void;\n/**\n * Every `defineDb` call registers its handle here so the host finds the schema whether or not the\n * project exports `db` (`const db = defineDb(...)` used only inside endpoints is the common case).\n * The host reads and clears the list after evaluating a bundle (`loadServerModules`).\n */\nexport declare const takeRegisteredDbs: () => Db<any>[];\n/** A reference to a previous operation's result inside `$transaction` (resolved server-side): `ref(\"0.id\")`. */\nexport declare const ref: (path: string) => any;\ntype ModelMeta = {\n name: string;\n fields: Record<string, FieldDef>;\n idKeys: string[];\n /** id is a single uuid key we generate on insert. */\n uuidId: boolean;\n};\nexport declare const toMarci: (metas: Record<string, ModelMeta>) => string;\nexport type DefineDbOptions = {\n transport?: MarciTransport;\n};\n/**\n * The schema registry: model name = key (`db.user` ← `User`). Relation strings are checked against the\n * keys both at the type level (`ValidateRefs`) and at runtime.\n *\n * A db is SEALED by its first use — a query, a read of its schema, the host taking it after the file\n * has loaded. Until then `.withAuth({ model })` may still change what it holds: it adds the platform's\n * `Session` and `Identity` models (../auth/models.ts) pointing at the project's model of a user, and\n * gives the db its `auth`. So `withAuth` belongs to the definition, written on `defineDb(...)` itself;\n * on a db that has been used it throws.\n */\nexport declare const defineDb: <const S extends Schema>(declared: S & ValidateRefs<S>, options?: DefineDbOptions) => Db<S>;\nexport {};\n","types/server/db/fields.d.ts":"/**\n * `t` — field builders for `model({...})`. Each builder returns an immutable `Field` carrying a runtime\n * `FieldDef` (what `.marci` is emitted from) and two phantom type parameters: the TS value type and a\n * `FieldMeta` record (kind / optional / default / …) that `defineDb`'s type layer projects into row,\n * insert, update, select and where types. Chained modifiers return a NEW field (builders are never\n * mutated), so `const s = t.string(); { a: s, b: s.optional() }` behaves as expected.\n */\nimport type { JsonValue } from \"./marci/query\";\nimport type { StoredFile, StoredImage } from \"../files/models\";\nexport type ScalarKind = \"string\" | \"int\" | \"float\" | \"bool\" | \"date\" | \"uuid\" | \"\";\nexport type FieldKind = \"scalar\" | \"json\" | \"enum\" | \"struct\" | \"one\" | \"many\" | \"list\" | \"file\";\nexport type OnDelete = \"cascade\" | \"setNull\" | \"restrict\";\n/** Phantom metadata — the type-level twin of `FieldDef`. */\nexport type FieldMeta = {\n kind: FieldKind;\n scalar: ScalarKind;\n optional: boolean;\n hasDefault: boolean;\n array: boolean;\n isId: boolean;\n /** Related model name for one/many/list; \"\" otherwise. */\n model: string;\n};\ntype DefaultMeta = {\n kind: \"scalar\";\n scalar: \"\";\n optional: false;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n};\nexport type Meta<O extends Partial<FieldMeta>> = {\n [P in keyof FieldMeta]: P extends keyof O ? O[P] : DefaultMeta[P];\n};\ntype SetMeta<M extends FieldMeta, K extends keyof FieldMeta, V> = {\n [P in keyof FieldMeta]: P extends K ? V : M[P];\n};\n/** Runtime field definition — everything the `.marci` emitter and the runtime need. */\nexport type FieldDef = {\n kind: FieldKind;\n scalar?: ScalarKind;\n optional: boolean;\n unique: boolean;\n index: boolean;\n hasDefault: boolean;\n default?: unknown;\n array: boolean;\n isId: boolean;\n onDelete?: OnDelete;\n fulltext?: \"multi\" | \"english\" | \"russian\";\n vector?: {\n size: number;\n metric: \"cosine\" | \"euclidean\";\n };\n /** enum */\n values?: readonly string[];\n /** struct */\n fields?: Record<string, Field<any, any>>;\n /** one / many / list */\n model?: string;\n /** file: a picture (`t.image()`) — `max` is the most its longer side may be, px. */\n image?: {\n max: number;\n };\n /** many: the field on the related model that holds the reference (`@bind`); resolved by defineDb when omitted. */\n back?: string;\n};\ntype DefaultOf<T, M extends FieldMeta> = M[\"scalar\"] extends \"date\" ? \"now\" | number : M[\"array\"] extends true ? T[] : T;\nexport interface Field<T, M extends FieldMeta = FieldMeta> {\n /** phantom (type-level only — never set at runtime) */ readonly __t?: T;\n /** phantom (type-level only — never set at runtime) */ readonly __m?: M;\n readonly def: FieldDef;\n /** Nullable column (`String?`). */\n optional(): Field<T, SetMeta<M, \"optional\", true>>;\n /** `@unique` (on a relation: one-to-one). */\n unique(): Field<T, M>;\n /** `@index` — used by `$where`, `$order`, aggregations. */\n index(): Field<T, M>;\n /** `@default(...)`; `\"now\"` on `t.date()` → `now()`. Makes the field optional on insert. */\n default(value: DefaultOf<T, M>): Field<T, SetMeta<M, \"hasDefault\", true>>;\n /** Primitive list (`String[]`). */\n array(): Field<T, SetMeta<M, \"array\", true>>;\n /** `@id` — primary key (several → composite). A field literally named `id` is the key implicitly. */\n id(): Field<T, SetMeta<M, \"isId\", true>>;\n /** Referential policy for `t.one()` (defaults: required → restrict, optional → setNull). */\n onDelete(policy: OnDelete): Field<T, M>;\n /** `@fulltext(...)` module index on a string field; query with `$search`. */\n fulltext(lang?: \"multi\" | \"english\" | \"russian\"): Field<T, M>;\n /** `Float[n] @vector(metric)` — nearest-neighbour index; query with `$near`. */\n vector(size: number, metric?: \"cosine\" | \"euclidean\"): Field<T, M>;\n}\nexport declare const t: {\n string: () => Field<string, Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** 64-bit signed integer. */\n int: () => Field<number, Meta<{\n kind: \"scalar\";\n scalar: \"int\";\n }>>;\n /** 64-bit float. */\n float: () => Field<number, Meta<{\n kind: \"scalar\";\n scalar: \"float\";\n }>>;\n bool: () => Field<boolean, Meta<{\n kind: \"scalar\";\n scalar: \"bool\";\n }>>;\n /** Epoch milliseconds — reads and writes as `number`. */\n date: () => Field<number, Meta<{\n kind: \"scalar\";\n scalar: \"date\";\n }>>;\n /** UUID string (16 bytes in storage). On an `id` field the runtime generates it on insert. */\n uuid: () => Field<string, Meta<{\n kind: \"scalar\";\n scalar: \"uuid\";\n }>>;\n /** Any JSON value; `J` is TS-only (marcidb stores it schemaless). Filter by dot-path in `$where`. */\n json: <J = JsonValue>() => Field<J, Meta<{\n kind: \"json\";\n }>>;\n /** String enum: `t.enum(\"draft\", \"published\")`. */\n enum: <const V extends readonly [string, ...string[]]>(...values: V) => Field<V[number], Meta<{\n kind: \"enum\";\n }>>;\n /** Owned nested object (marcidb `struct`): created/updated with the parent, no id of its own. */\n struct: <F extends Record<string, Field<any, any>>>(fields: F) => Field<F, Meta<{\n kind: \"struct\";\n }>>;\n /** Reference to one row of `model` (by id). Required unless `.optional()`. */\n one: <N extends string>(model: N) => Field<never, Meta<{\n kind: \"one\";\n model: N;\n }>>;\n /** Reverse side of a `t.one()` on `model` (the field is inferred when unambiguous). Read-only list. */\n many: <N extends string>(model: N, backField?: string) => Field<never, Meta<{\n kind: \"many\";\n model: N;\n }>>;\n /**\n * A stored file: written as a `File` (an upload — an endpoint's parameter), read as\n * `{ url, name, type, size, width?, height? }`. `.optional()` = may be empty, `.array()` = an ordered\n * list of files. It is deleted with its row — or when the field is given another file, or `null`.\n */\n file: () => Field<StoredFile, Meta<{\n kind: \"file\";\n }>>;\n /**\n * A stored PICTURE — a `t.file()` that takes images only and keeps them fit to show: turned the way\n * the camera meant, without its metadata (a photo's place and time), as WebP, and no larger than\n * `max` px on its longer side (2048 when not said; a picture is never enlarged).\n * Read as a `StoredFile` whose `width` and `height` are always there. A GIF is kept as it is.\n */\n image: (options?: {\n max?: number;\n }) => Field<StoredImage, Meta<{\n kind: \"file\";\n }>>;\n /** Ordered relation list stored inline (`@list`) — hand-arranged collections, duplicates allowed. */\n list: <N extends string>(model: N) => Field<never, Meta<{\n kind: \"list\";\n model: N;\n }>>;\n};\nexport type T = typeof t;\nexport {};\n","types/server/db/index.d.ts":"export { t } from \"./fields\";\nexport type { Field, FieldDef, FieldMeta } from \"./fields\";\nexport { model, defineDb, ref, setDbTransport, toMarci } from \"./defineDb\";\nexport type { DefineDbOptions } from \"./defineDb\";\nexport type { Auth, Db, DbWithAuth, UserQuery, Model, Schema, Row, Id, Insert, Update, Select, Where, Query, QueryObject, Result, Collection, ScalarSelect, Types } from \"./types\";\nexport type { Op, MarciOp, MarciTransport, JsonValue, Sub } from \"./marci/query\";\n","types/server/db/marci/query.d.ts":"export type ServiceKeys = \"$where\" | \"$order\" | \"$limit\" | \"$skip\" | \"$cursor\";\nexport type JsonValue = string | number | boolean | null | JsonValue[] | {\n [key: string]: JsonValue;\n};\nexport type AggregateKeys = {\n $count: true;\n} | {\n $sum: string;\n} | {\n $avg: string;\n} | {\n $min: string;\n} | {\n $max: string;\n};\nexport type GetResult<TModel, TSelect> = TModel extends any ? {\n -readonly [K in keyof Omit<TSelect, ServiceKeys> as TSelect[K] extends false | undefined ? never : K extends keyof TModel ? K : never]: K extends keyof TModel ? TSelect[K] extends true ? TModel[K] : TSelect[K] extends Record<string, any> ? TModel[K] extends readonly object[] ? TSelect[K] extends AggregateKeys ? AggregateResult<NonNullable<TModel[K][number]>, TSelect[K]> : GetResult<NonNullable<TModel[K][number]>, TSelect[K]>[] : GetResult<NonNullable<TModel[K]>, TSelect[K]> | Extract<TModel[K], null> : TModel[K] : never;\n} : never;\nexport type RefUpdate<I> = {\n \"$connect\"?: I;\n};\nexport type RefUpdateStruct<I, U> = {\n \"$update\"?: U;\n \"$ensure\"?: I;\n \"$set\"?: I;\n};\n/** Relation to independent rows — link operations only, the rows themselves are never created\n * or deleted. `$set` replaces link membership with exactly the given set (missing links are\n * disconnected, new ones connected); `$connect` links (idempotent); `$remove` unlinks. */\nexport type RefListUpdate<I> = {\n \"$set\"?: I[];\n \"$connect\"?: I | I[];\n \"$remove\"?: I | I[];\n};\n/** `@list` relation: an ordered inline id array — a sequence, so the same id may appear several\n * times. `$set` replaces the whole array (also the reorder operation); `$connect` appends at the\n * end (an already-present id gains another occurrence); `$connectUnique` appends only ids not\n * already present; `$remove` removes every occurrence. */\nexport type RefListUpdateOrdered<I> = {\n \"$set\"?: I[];\n \"$connect\"?: I | I[];\n \"$connectUnique\"?: I | I[];\n \"$remove\"?: I | I[];\n};\n/** Owned (struct) list: the children live and die with the parent. `$push` creates children,\n * `$update` edits single children in place (each item is the child's id fields — the shape\n * query results return — plus the changes under `data`), `$remove` deletes children by id,\n * `$set` replaces all children (deletes the current ones, creates the new). */\nexport type RefListUpdateStruct<I, U, Id> = {\n \"$push\"?: I | I[];\n \"$update\"?: (Id & {\n data: U;\n }) | (Id & {\n data: U;\n })[];\n \"$remove\"?: Id | Id[];\n \"$set\"?: I[];\n};\n/** Variable-length primitive array — a sequence, so the same value may appear several times.\n * `$push` appends at the end (duplicates kept); `$pushUnique` appends only values not already\n * present; `$remove` removes every occurrence; `$set` replaces the whole array (also the\n * positional-edit path — send the full new array). One operator per update. */\nexport type PrimitiveListUpdate<T> = {\n \"$set\"?: T[];\n \"$push\"?: T | T[];\n \"$pushUnique\"?: T | T[];\n \"$remove\"?: T | T[];\n};\nexport type Never<T> = {\n [K in keyof T]?: never;\n};\nexport type FieldOps = {\n \"$eq\": unknown;\n \"$ne\": unknown;\n \"$not\": unknown;\n \"$in\": unknown;\n \"$notIn\": unknown;\n \"$gt\": unknown;\n \"$gte\": unknown;\n \"$lt\": unknown;\n \"$lte\": unknown;\n \"$startsWith\": unknown;\n \"$includes\": unknown;\n \"$every\": unknown;\n \"$some\": unknown;\n \"$none\": unknown;\n \"$near\": unknown;\n \"$search\": unknown;\n};\nexport type Only<K extends keyof FieldOps, V> = {\n [P in K]: V;\n} & Never<Omit<FieldOps, K>>;\nexport type WhereValue<T> = (T & Never<{\n \"$and\": unknown;\n \"$or\": unknown;\n \"$not\": unknown;\n}>) | ({\n \"$and\": WhereValue<T>[];\n} & Never<T> & Never<{\n \"$or\": unknown;\n \"$not\": unknown;\n}>) | ({\n \"$or\": WhereValue<T>[];\n} & Never<T> & Never<{\n \"$and\": unknown;\n \"$not\": unknown;\n}>) | ({\n \"$not\": WhereValue<T>;\n} & Never<T> & Never<{\n \"$and\": unknown;\n \"$or\": unknown;\n}>);\nexport type ValueOps<T> = {\n \"$eq\"?: T;\n \"$ne\"?: T;\n \"$not\"?: T;\n \"$in\"?: T[];\n \"$notIn\"?: T[];\n};\nexport type NumOps<T> = {\n \"$gt\"?: T;\n \"$gte\"?: T;\n \"$lt\"?: T;\n \"$lte\"?: T;\n};\nexport type StrOps = {\n \"$includes\"?: string;\n \"$startsWith\"?: string;\n};\nexport type CompareValue<T> = T | (ValueOps<T> & Never<Omit<FieldOps, keyof ValueOps<T>>>);\nexport type CompareNumValue<T> = ValueOps<T> & NumOps<T> & Never<Omit<FieldOps, keyof ValueOps<T> | keyof NumOps<T>>>;\nexport type CompareStrValue<T> = ValueOps<T> & StrOps & Never<Omit<FieldOps, keyof ValueOps<T> | keyof StrOps>>;\nexport type UpdateNumValue = {\n \"$increment\": number;\n};\nexport type JsonType = \"string\" | \"number\" | \"boolean\" | \"object\" | \"array\" | \"null\";\nexport type JsonCondition = JsonValue | {\n \"$eq\"?: JsonValue;\n \"$ne\"?: JsonValue;\n \"$not\"?: JsonValue;\n \"$gt\"?: number | string;\n \"$gte\"?: number | string;\n \"$lt\"?: number | string;\n \"$lte\"?: number | string;\n \"$in\"?: JsonValue[];\n \"$notIn\"?: JsonValue[];\n \"$startsWith\"?: string;\n \"$includes\"?: string;\n \"$contains\"?: JsonValue;\n \"$exists\"?: boolean;\n \"$type\"?: JsonType;\n};\nexport type JsonPathWhere = {\n [path: string]: JsonCondition;\n};\nexport type CompareRefValue<T> = T | Only<\"$not\", T>;\nexport type CompareRefListValue<T> = Only<\"$every\", T> | Only<\"$some\", T> | Only<\"$none\", T>;\nexport type VectorSearch = {\n vector: number[];\n k?: number;\n threshold?: number;\n};\nexport type FullTextSearch = string | {\n query: string;\n limit?: number;\n};\nexport type CustomSearch = Record<string, any>;\nexport type CustomSearchValue<P> = Only<\"$near\", P> | Only<\"$search\", P>;\nexport type AggregateResult<TModel, T> = (T extends {\n $count: true;\n} ? {\n count: number;\n} : {}) & (T extends {\n $sum: string;\n} ? {\n sum: number | null;\n} : {}) & (T extends {\n $avg: string;\n} ? {\n avg: number | null;\n} : {}) & (T extends {\n $min: infer F;\n} ? {\n min: (F extends keyof TModel ? TModel[F] : never) | null;\n} : {}) & (T extends {\n $max: infer F;\n} ? {\n max: (F extends keyof TModel ? TModel[F] : never) | null;\n} : {});\ndeclare const __op: unique symbol;\nexport type Op<T> = PromiseLike<T> & {\n readonly [__op]: T;\n};\nexport type MarciOp = {\n model: string;\n action: string;\n query?: any;\n data?: any;\n id?: any;\n journal?: JournalArgs;\n};\n/** The arguments of a journal action (`$journalOpen` / `$journalRead` / `$journalDrop`). `wait` is in seconds. */\nexport type JournalArgs = {\n name: string;\n on?: readonly JournalOp[];\n after?: number;\n limit?: number;\n wait?: number;\n};\nexport type MarciTransport = {\n exec(op: MarciOp): Promise<any>;\n batch(ops: MarciOp[]): Promise<any[]>;\n};\nexport type ModelTypes = {\n name: string;\n model: any;\n id: Record<string, any>;\n /** What an empty select returns: id + every scalar field, as a `{ field: true }` shape. */\n scalars: Record<string, true>;\n select: Record<string, any>;\n query: Record<string, any>;\n where: any;\n order: Record<string, any>;\n insert: any;\n update: any;\n aggregate: Record<string, any>;\n reindex: boolean;\n};\ndeclare const __sub: unique symbol;\ndeclare const __sel: unique symbol;\nexport type Sub<Name extends string, Shape = any> = {\n readonly [__sub]: Name;\n readonly [__sel]: Shape;\n};\nexport type Effective<T extends ModelTypes, S> = [Exclude<keyof S, ServiceKeys>] extends [never] ? T[\"scalars\"] : S;\nexport type Resolve<S> = S extends {\n readonly [__sel]: infer X;\n} ? Resolve<X> : S extends object ? {\n [K in keyof S]: K extends `$${string}` ? S[K] : Resolve<S[K]>;\n} : S;\nexport type Rows<T extends ModelTypes, Sel> = GetResult<T[\"model\"], Resolve<Effective<T, Sel>>>;\nexport type BareId<I> = I extends {\n id: infer V;\n} ? V : never;\nexport type IdArg<I> = I | BareId<I>;\n/**\n * A lazy, immutable query over one model — `db.user` itself is one. Every clause returns a new query, so\n * queries compose (`const active = db.user.where({ active: true })`). `await` runs it as `findMany`; passing\n * it to `$transaction` batches it; placing it in another query's select makes it a sub-select. `Sel` is the\n * projection: id + scalars until `select(...)` sets a shape.\n */\nexport interface Query<T extends ModelTypes, Sel = T[\"scalars\"]> extends PromiseLike<Rows<T, Sel>[]> {\n readonly [__op]: Rows<T, Sel>[];\n readonly [__sub]: T[\"name\"];\n readonly [__sel]: Effective<T, Sel>;\n /** Filter (marcidb `$where`). Repeated calls are ANDed. */\n where(where: T[\"where\"]): Query<T, Sel>;\n /** Sort by one field: `order(\"age\", \"desc\")` or `order({ age: \"desc\" })`. */\n order(field: keyof T[\"order\"] & string, direction?: \"asc\" | \"desc\"): Query<T, Sel>;\n order(order: T[\"order\"]): Query<T, Sel>;\n limit(n: number): Query<T, Sel>;\n skip(n: number): Query<T, Sel>;\n /** Keyset cursor: rows strictly after this id in the current order (`$cursor`). */\n after(id: IdArg<T[\"id\"]>): Query<T, Sel>;\n /**\n * The projection. Values are `true`, a nested shape, or a sub-query of the relation's model\n * (`posts: db.post.limit(5)`, `posts: db.post.where({ published: true }).count()`). No argument, or no\n * field keys, selects id + every scalar. `$`-clauses are accepted here too (the object form).\n */\n select<S extends T[\"query\"] = T[\"scalars\"]>(shape?: S): Query<T, S>;\n /** The first matching row or `null`. */\n first(): Op<Rows<T, Sel> | null>;\n /** Row count; inside a select it becomes `{ count }` for the relation. */\n count(): Op<number> & Sub<T[\"name\"], {\n $count: true;\n }>;\n /** @deprecated pass the filter through the chain: `db.user.where(w).count()` (removed in the next minor). */\n count(query: {\n $where?: T[\"where\"];\n }): Op<number> & Sub<T[\"name\"], {\n $count: true;\n }>;\n aggregate<A extends T[\"aggregate\"]>(query: A): Op<AggregateResult<T[\"model\"], A>> & Sub<T[\"name\"], NoInfer<A>>;\n insert(data: T[\"insert\"]): Op<T[\"id\"]>;\n update(id: IdArg<T[\"id\"]>, data: T[\"update\"]): Op<void>;\n /** Applies `data` to every row the chain's `where` matches (all rows without one); resolves to the number of rows. */\n updateMany(data: T[\"update\"]): Op<number>;\n /** @deprecated pass the filter through the chain: `db.user.where(w).updateMany(data)` (removed in the next minor). */\n updateMany(query: {\n $where?: T[\"where\"];\n }, data: T[\"update\"]): Op<number>;\n delete(id: IdArg<T[\"id\"]>): Op<void>;\n /**\n * Deletes every row the chain's `where` matches (cascades apply, as for `delete`); resolves to the number\n * deleted. Refuses to run without a `where` — write `.where({})` to mean \"every row\".\n */\n deleteMany(): Op<number>;\n /** @deprecated use `.select(query)` — it takes the same object, merged with the chain (removed in the next minor). */\n findMany<Q extends T[\"query\"] = {}>(query?: Q): Op<Rows<T, Q>[]>;\n /** @deprecated use `.select(query).first()` (removed in the next minor). */\n findFirst<Q extends T[\"query\"] = {}>(query?: Q): Op<Rows<T, Q> | null>;\n}\n/** What a journal can record. Only deletes so far. */\nexport type JournalOp = \"delete\";\n/** One recorded change. `row` is the row as it last was: its id and every scalar field. */\nexport type JournalEntry<T extends ModelTypes, O extends JournalOp = JournalOp> = {\n seq: number;\n op: O;\n row: Rows<T, T[\"scalars\"]>;\n};\nexport type JournalOptions<O extends JournalOp> = {\n /** The operations to record. A journal that exists with other ones is an error, not a redefinition. */\n on: O | readonly O[];\n /** `false`: the loop ends when the journal is read through. By default it waits for the next entry. */\n wait?: boolean;\n};\n/**\n * A named, durable log of a model's changes. It starts recording when it is first asked for and keeps\n * every entry until the loop that reads it has moved past it — an entry whose loop body threw, or that\n * was never reached, is delivered again to the next reader of the same name.\n */\nexport interface Journal<T extends ModelTypes, O extends JournalOp = JournalOp> extends AsyncIterable<JournalEntry<T, O>> {\n /** Drops the journal with whatever it still holds; the model's writes stop paying for it. */\n drop(): Promise<void>;\n}\n/**\n * `db.<model>`: the root query, plus `reindex()` for models with a `@custom` (vector / full-text) index and\n * `$journal(name, { on })` — the journal of this model's changes under that name, created on first use.\n */\nexport type Collection<T extends ModelTypes> = Query<T> & (T[\"reindex\"] extends true ? {\n reindex(): Op<{\n ok: boolean;\n indexed: number;\n }>;\n} : {}) & {\n $journal<O extends JournalOp>(name: string, options: JournalOptions<O>): Journal<T, O>;\n};\n/** One field of a model, in slot order: `n` name, `k` key | body | one | many, `m` the relation's target model. */\nexport type FieldDesc = {\n n: string;\n k: \"key\" | \"body\" | \"one\" | \"many\";\n t?: string | null;\n m?: string;\n};\n/** Model name → its field descriptors (structs included, as relation targets). */\nexport type ModelsMeta = Record<string, readonly FieldDesc[]>;\nexport type QueryLayerOptions = {\n models: ModelsMeta;\n /** Runs one operation (a query, or a write) and resolves its result. */\n run(op: MarciOp): Promise<any>;\n /** Hook for `insert` payloads (the lecodes SDK generates uuid ids here). */\n prepareInsert?(model: string, data: any): any;\n};\n/**\n * The query builder over a set of models and a `run` function. Returns `op(descriptor)` — a lazy operation\n * (`await` runs it, `$transaction` takes its `__op`) — and `collection(model)`, the immutable `db.<model>`\n * root query. Transport-agnostic: the generated client and the embedded/HTTP transports supply `run`.\n */\nexport declare function createQueryLayer(options: QueryLayerOptions): {\n op: (descriptor: MarciOp) => any;\n collection: (model: string) => any;\n};\nexport {};\n","types/server/db/types.d.ts":"/**\n * Type layer: projects a `defineDb({ User: model({...}), … })` literal into marcidb's generic query\n * types (./marci/query.ts — vendored from marcidb, see scripts/sync-marcidb.ts): each model becomes the\n * `ModelTypes` bag marcidb's codegen would have emitted, and `db.<model>` is marcidb's own `Query<T>`.\n * Everything here is type-only; the runtime lives in ./defineDb.ts.\n *\n * Naming: `S` = the schema record (model name → Model), `N` = a model name, `F` = a fields record.\n */\nimport type { Field, FieldMeta } from \"./fields\";\nimport type { IdentityPublicFields, SessionPublicFields } from \"../auth/models\";\nimport type { StoredFile, UploadedFile as File } from \"../files/models\";\nimport type { CompareNumValue, CompareRefListValue, CompareRefValue, CompareStrValue, CompareValue, CustomSearchValue, FullTextSearch, JsonCondition, JsonPathWhere, Op, PrimitiveListUpdate, Query as MarciQuery, RefListUpdate, RefListUpdateOrdered, RefUpdate, RefUpdateStruct, Rows, Sub, UpdateNumValue, VectorSearch, WhereValue } from \"./marci/query\";\nexport type Fields = Record<string, Field<any, any>>;\nexport type Model<F extends Fields = Fields> = {\n readonly fields: F;\n readonly __model: true;\n};\nexport type Schema = Record<string, Model<any>>;\nexport type FieldsOf<M> = M extends Model<infer F> ? F : never;\ntype TsOf<Fld> = Fld extends Field<infer T, any> ? T : never;\ntype StructFieldsOf<Fld> = TsOf<Fld> extends Fields ? TsOf<Fld> : never;\ntype MetaOf<Fld> = Fld extends Field<any, infer M> ? M : never;\ntype ModelName<S, Fld> = MetaOf<Fld>[\"model\"] & keyof S & string;\ntype Nullable<M extends FieldMeta, T> = M[\"optional\"] extends true ? T | null : T;\ntype Arr<M extends FieldMeta, T> = M[\"array\"] extends true ? T[] : T;\ntype IsNum<M extends FieldMeta> = M[\"scalar\"] extends \"int\" | \"float\" | \"date\" ? true : false;\n/** Explicit `.id()` fields, or a field literally named `id`. */\ntype IdKeys<F extends Fields> = {\n [K in keyof F]: MetaOf<F[K]>[\"isId\"] extends true ? K : K extends \"id\" ? K : never;\n}[keyof F];\ntype IdValue<S, Fld> = MetaOf<Fld>[\"kind\"] extends \"one\" ? Id<S, ModelName<S, Fld>> : TsOf<Fld>;\n/** The id object of a model: `{ id: number }` implicitly, or the declared key fields. */\nexport type Id<S, N extends keyof S> = [\n IdKeys<FieldsOf<S[N]>>\n] extends [never] ? {\n id: number;\n} : {\n [K in IdKeys<FieldsOf<S[N]>>]: IdValue<S, FieldsOf<S[N]>[K]>;\n};\n/** What `update`/`delete` accept: the id object, or the bare value when the key is a single scalar. */\nexport type IdArg<S, N extends keyof S> = Id<S, N> | (Id<S, N> extends {\n id: infer V;\n} ? V : never);\ntype FieldRow<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Nullable<M, Row<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"many\" | \"list\" ? Row<S, ModelName<S, Fld>>[] : M[\"kind\"] extends \"struct\" ? Nullable<M, StructRow<S, StructFieldsOf<Fld>>> : Nullable<M, Arr<M, TsOf<Fld>>>;\n/** Full row type of a model (relations included) — the `TModel` marcidb's `GetResult` selects from. */\nexport type Row<S, N extends keyof S> = Id<S, N> & {\n [K in Exclude<keyof FieldsOf<S[N]>, IdKeys<FieldsOf<S[N]>>>]: FieldRow<S, FieldsOf<S[N]>[K]>;\n};\ntype StructRow<S, F extends Fields> = {\n [K in keyof F]: FieldRow<S, F[K]>;\n};\n/** What a query without a selection returns besides the id: the scalars, and the files. */\ntype ScalarKeys<F extends Fields> = {\n [K in keyof F]: MetaOf<F[K]>[\"kind\"] extends \"scalar\" | \"enum\" | \"json\" | \"file\" ? K : never;\n}[keyof F];\n/** The fields a row is ordered and aggregated by. */\ntype ValueKeys<F extends Fields> = {\n [K in keyof F]: MetaOf<F[K]>[\"kind\"] extends \"scalar\" | \"enum\" | \"json\" ? K : never;\n}[keyof F];\ntype NumKeys<F extends Fields> = {\n [K in keyof F]: IsNum<MetaOf<F[K]>> extends true ? (MetaOf<F[K]>[\"array\"] extends true ? never : K) : never;\n}[keyof F];\n/** What an empty select returns: id + every scalar field. */\nexport type Scalars<S, N extends keyof S> = Pick<Row<S, N>, (ScalarKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>>;\n/** The same, as the `{ field: true }` select shape a query starts with. */\nexport type ScalarSelect<S, N extends keyof S> = {\n [K in (ScalarKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>]: true;\n};\ntype FieldInsert<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Nullable<M, Id<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"many\" | \"list\" ? Id<S, ModelName<S, Fld>>[] : M[\"kind\"] extends \"struct\" ? Nullable<M, StructInsert<S, StructFieldsOf<Fld>>> : M[\"kind\"] extends \"file\" ? Nullable<M, Arr<M, File>> : Nullable<M, Arr<M, TsOf<Fld>>>;\ntype RequiredKeys<F extends Fields> = {\n [K in keyof F]: K extends IdKeys<F> ? never : MetaOf<F[K]>[\"optional\"] extends true ? never : MetaOf<F[K]>[\"hasDefault\"] extends true ? never : MetaOf<F[K]>[\"kind\"] extends \"many\" | \"list\" ? never : MetaOf<F[K]>[\"kind\"] extends \"file\" ? (MetaOf<F[K]>[\"array\"] extends true ? never : K) : K;\n}[keyof F];\ntype Simplify<T> = {\n [K in keyof T]: T[K];\n} & {};\ntype InsertOf<S, F extends Fields> = Simplify<{\n [K in RequiredKeys<F>]: FieldInsert<S, F[K]>;\n} & {\n [K in Exclude<keyof F, RequiredKeys<F>>]?: FieldInsert<S, F[K]>;\n}>;\nexport type Insert<S, N extends keyof S> = InsertOf<S, FieldsOf<S[N]>>;\ntype StructInsert<S, F extends Fields> = InsertOf<S, F>;\ntype FieldUpdate<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Nullable<M, RefUpdate<Id<S, ModelName<S, Fld>>>> : M[\"kind\"] extends \"many\" ? RefListUpdate<Id<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"list\" ? RefListUpdateOrdered<Id<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"struct\" ? RefUpdateStruct<StructInsert<S, StructFieldsOf<Fld>>, UpdateOf<S, StructFieldsOf<Fld>>> | null : M[\"kind\"] extends \"file\" ? Nullable<M, Arr<M, File | StoredFile>> : M[\"array\"] extends true ? TsOf<Fld>[] | PrimitiveListUpdate<TsOf<Fld>> : Nullable<M, TsOf<Fld> | (IsNum<M> extends true ? UpdateNumValue : never)>;\ntype UpdateOf<S, F extends Fields> = {\n [K in Exclude<keyof F, IdKeys<F>>]?: FieldUpdate<S, F[K]>;\n};\nexport type Update<S, N extends keyof S> = UpdateOf<S, FieldsOf<S[N]>>;\ntype FieldSelect<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Select<S, ModelName<S, Fld>> | boolean | Sub<ModelName<S, Fld>> : M[\"kind\"] extends \"many\" | \"list\" ? QueryObject<S, ModelName<S, Fld>> | AggregateQuery<S, ModelName<S, Fld>> | boolean | Sub<ModelName<S, Fld>> : M[\"kind\"] extends \"struct\" ? StructSelect<S, StructFieldsOf<Fld>> | boolean : boolean;\nexport type Select<S, N extends keyof S> = {\n [K in keyof Row<S, N>]?: K extends keyof FieldsOf<S[N]> ? FieldSelect<S, FieldsOf<S[N]>[K]> : boolean;\n};\ntype StructSelect<S, F extends Fields> = {\n [K in keyof F]?: FieldSelect<S, F[K]>;\n};\ntype ScalarWhere<T, M extends FieldMeta> = Nullable<M, CompareValue<T>> | (IsNum<M> extends true ? CompareNumValue<T> : M[\"scalar\"] extends \"string\" ? CompareStrValue<T> : never);\ntype FieldWhere<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? CompareRefValue<Where<S, ModelName<S, Fld>> | null> : M[\"kind\"] extends \"many\" | \"list\" ? CompareRefListValue<Where<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"struct\" ? CompareRefValue<WhereValue<StructWhereFields<S, StructFieldsOf<Fld>>> | null> : M[\"kind\"] extends \"json\" ? JsonPathWhere | JsonCondition : M[\"kind\"] extends \"file\" ? never : M[\"array\"] extends true ? TsOf<Fld>[] : ScalarWhere<TsOf<Fld>, M> | CustomSearchValue<FullTextSearch> | CustomSearchValue<VectorSearch>;\ntype WhereFieldsOf<S, F extends Fields> = {\n [K in keyof F]?: FieldWhere<S, F[K]>;\n};\ntype IdWhere<S, N extends keyof S> = {\n [K in keyof Id<S, N> as K extends keyof FieldsOf<S[N]> ? never : K]?: CompareValue<Id<S, N>[K]> | CompareNumValue<number>;\n};\nexport type Where<S, N extends keyof S> = WhereValue<WhereFieldsOf<S, FieldsOf<S[N]>> & IdWhere<S, N>>;\ntype StructWhereFields<S, F extends Fields> = WhereFieldsOf<S, F>;\ntype OrderKeys<S, N extends keyof S> = (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>;\n/** ONE field and its direction: the engine sorts by a single field, so a second key is a type error. */\nexport type Order<S, N extends keyof S> = {\n [K in OrderKeys<S, N>]: {\n [P in K]: \"asc\" | \"desc\";\n } & {\n [P in Exclude<OrderKeys<S, N>, K>]?: never;\n };\n}[OrderKeys<S, N>];\n/** The query object — marcidb's wire form: a select shape plus the `$`-clauses. */\nexport type QueryObject<S, N extends keyof S> = Select<S, N> & {\n $where?: Where<S, N>;\n $order?: Order<S, N>;\n $limit?: number;\n $skip?: number;\n $cursor?: Id<S, N>;\n};\nexport type AggregateQuery<S, N extends keyof S> = {\n $where?: Where<S, N>;\n $count?: true;\n $sum?: NumKeys<FieldsOf<S[N]>> & string;\n $avg?: NumKeys<FieldsOf<S[N]>> & string;\n $min?: (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & string;\n $max?: (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & string;\n};\n/** The per-model type bag marcidb's generic `Query<T>` is parametrised by (what its codegen emits as `UserTypes`). */\nexport type Types<S, N extends keyof S> = {\n name: N & string;\n model: Row<S, N>;\n id: Id<S, N>;\n scalars: ScalarSelect<S, N>;\n select: Select<S, N>;\n query: QueryObject<S, N>;\n where: Where<S, N>;\n order: Order<S, N>;\n insert: Insert<S, N>;\n update: Update<S, N>;\n aggregate: AggregateQuery<S, N>;\n reindex: false;\n};\n/**\n * `db.<model>` — marcidb's lazy, immutable query over one model: clauses (`where/order/limit/skip/after`)\n * return a new query, `select(shape)` sets the projection, `await` runs it, `first/count/aggregate` terminate,\n * `updateMany(data)`/`deleteMany()` write through the chain's `where`; a query placed in another query's\n * select is a sub-query. `Sel` is the projection: id + scalars until `select(...)` sets a shape.\n */\nexport type Query<S, N extends keyof S, Sel = ScalarSelect<S, N>> = MarciQuery<Types<S, N>, Sel>;\n/** The rows a query with projection `Q` resolves to (no field keys = id + scalars; sub-queries resolved). */\nexport type Result<S, N extends keyof S, Q> = Rows<Types<S, N>, Q>;\n/** `db.<model>` — the root query of a model. */\nexport type Collection<S, N extends keyof S> = Query<S, N>;\n/** The platform's models a project's own may point at (`t.one(\"Session\")`) — see ../auth/models.ts. */\ntype PlatformModels = {\n Session: Model<SessionPublicFields>;\n};\n/** What a db's queries are typed against: the project's models and what they may point at. */\ntype Full<S> = S & PlatformModels;\ntype DbBase<S extends Schema> = {\n [N in keyof S & string as Uncapitalize<N>]: Query<Full<S>, N>;\n} & {\n /** Atomic batch: all ops commit or none. `ref(\"0.id\")` feeds a generated id into a later op. */\n $transaction<P extends readonly Op<any>[]>(ops: [...P]): Promise<{\n [K in keyof P]: P[K] extends Op<infer T> ? T : never;\n }>;\n /** The `.marci` schema text this db syncs with. */\n readonly $schema: string;\n};\nexport type Db<S extends Schema> = DbBase<S> & {\n /**\n * Sign-in for this database: `model` is the project's model of a user. Adds the platform's `Session`\n * and `Identity` models beside it and gives the db its `auth`. Part of the definition — call it on\n * `defineDb(...)` itself, before the db is used. Every field of the user model must be optional or\n * have a default: the platform creates the row the first time someone signs in.\n */\n withAuth<N extends keyof S & string>(options: {\n model: N;\n }): DbWithAuth<S, N>;\n};\nexport type DbWithAuth<S extends Schema, N extends keyof S & string> = DbBase<S> & {\n readonly auth: Auth<S, N>;\n};\n/**\n * The user of the current request, as a query over the project's user model: `select(shape)` picks the\n * fields (id + scalars without it), `await` runs it. Nothing happens until it is awaited — a query that\n * is never awaited checks nothing, which is why the compiler refuses one.\n */\nexport interface UserQuery<S, N extends keyof S, Sel, Nil> extends PromiseLike<Result<S, N, Sel> | Nil> {\n select<Q extends Select<S, N>>(shape: Q): UserQuery<S, N, Q, Nil>;\n}\ntype AuthTables = {\n Session: Model<SessionPublicFields>;\n Identity: Model<IdentityPublicFields>;\n};\n/** `db.auth` — see ../auth/api.ts. */\nexport type Auth<S extends Schema, N extends keyof S & string> = {\n /** The signed-in user, or `null` for a guest. */\n user(): UserQuery<Full<S>, N, ScalarSelect<Full<S>, N>, null>;\n /**\n * The signed-in user; a guest is a 401. With `where` it is a check of access too: a user the filter\n * does not match is a 403 — `await db.auth.requireUser({ role: \"admin\" }).select({ id: true })`.\n */\n requireUser(where?: Where<Full<S>, N>): UserQuery<Full<S>, N, ScalarSelect<Full<S>, N>, never>;\n /** The device's session — there from the first request, before any sign-in (a guest's cart points at it). */\n readonly sessionId: number;\n /** A new account: `login` is an email or a name (3–32 letters, digits, `. _ -`), `data` the fields of the\n * user's row. 409 when the login is taken. Signs this device in. */\n signUpWithPassword(login: string, password: string, data?: Insert<Full<S>, N>): Promise<void>;\n /** Signs this device in; 401 on any failure (rate-limited per login and ip). */\n signInWithPassword(login: string, password: string): Promise<void>;\n /** Sets the current user's password; every other device is signed out. */\n setPassword(password: string): Promise<void>;\n /** Emails a 6-digit code (always resolves — no \"email exists\" oracle; rate-limited). */\n sendCode(email: string): Promise<void>;\n /** Checks the code sent to this device, finds or creates the user, signs this device in. */\n signInWithCode(email: string, code: string): Promise<void>;\n /** For a person the project verified itself (a provider's sign-in, Telegram initData, SSO): binds this device to the user. */\n signIn(userId: number): Promise<void>;\n /** The device stays, as a guest. */\n signOut(): Promise<void>;\n /** The current user's devices, as a query: `await`, `.select()`, `.where(...).updateMany({ revoked: true })`. */\n readonly sessions: Query<AuthTables, \"Session\">;\n /** How the current user signs in, as a query: provider (`\"email\"` | `\"login\"`), subject, verifiedAt. */\n readonly identities: Query<AuthTables, \"Identity\">;\n};\ntype RelKinds = \"one\" | \"many\" | \"list\";\ntype CheckField<S, Fld> = MetaOf<Fld>[\"kind\"] extends RelKinds ? MetaOf<Fld>[\"model\"] extends keyof S | keyof PlatformModels ? Fld : `Unknown model \"${MetaOf<Fld>[\"model\"]}\" — not a key of defineDb({...})` : Fld;\n/** Intersected with `S` in `defineDb`'s parameter: an unknown relation target fails to type-check on that field. */\nexport type ValidateRefs<S extends Schema> = {\n [N in keyof S]: {\n readonly fields: {\n [K in keyof FieldsOf<S[N]>]: CheckField<S, FieldsOf<S[N]>[K]>;\n };\n };\n};\nexport {};\n","types/server/errors.d.ts":"/**\n * `throw new ApiError(404, \"Not found\")` inside an endpoint → the client's promise rejects with the\n * same status + message. Any other throw is a 500 (message hidden, logged to the server console).\n */\nexport declare class ApiError extends Error {\n readonly status: number;\n constructor(status: number, message?: string);\n}\n","types/server/files/db.d.ts":"/**\n * The db layer's half of stored files (./models.ts): what turns a file FIELD — a value in a row — into\n * operations on the platform's `File` model, and back.\n *\n * read the field is selected as the reverse relation it is (the `File` rows that point at the\n * row, in order) and comes back as a `StoredFile`, or a list of them\n * insert the row is inserted without the field; each upload's `File` row is then pointed at it\n * (`ref` to the insert's id) — one transaction\n * update the row's files that are no longer listed are deleted, the uploads are pointed at it —\n * one transaction with the update itself\n *\n * An upload written to a `t.image()` field is first made a picture fit to show (the host's work,\n * ./host.ts): that is why a plan is awaited. What it became — its type, its size — goes to its row\n * in the operation that attaches it.\n *\n * A file is written from the FILE's side (its reference to the owner): that is the side the database\n * cascades over. Only an upload of the current request is ever attached: a `StoredFile` the app hands\n * back means \"keep this one\", and one of another row is not moved — a client that knows the url of\n * someone else's file cannot take it.\n */\nimport type { MarciOp } from \"../db/marci/query\";\nimport { type FileField } from \"./models\";\ntype Plan = {\n op: MarciOp;\n after: MarciOp[];\n};\nexport type FileLayer = {\n /** The operation as the database runs it, and the ones that follow it in the same transaction.\n * `index` is the operation's place in that transaction (what `ref` counts from). */\n plan(op: MarciOp, index: number): Promise<Plan>;\n /** The database's answer to a planned operation, as the project reads it. */\n result(op: MarciOp, value: any): any;\n};\n/**\n * `fields`: the schema's `t.file()` fields. `relations`: model → relation field → its target model.\n * `scalars`: model → what a query without a selection returns (file fields included).\n */\nexport declare const createFileLayer: (fields: FileField[], relations: Record<string, Record<string, string>>, scalars: Record<string, string[]>) => FileLayer;\nexport {};\n","types/server/files/models.d.ts":"/**\n * Stored files: `t.file()` on a model.\n *\n * A project never declares where a file lives. A model that has a `t.file()` field makes the db carry\n * one more model, the PLATFORM's `File` — a row per stored file: what it is (name, type, size, an\n * image's dimensions) and whose it is. The owner is a reference FROM the file TO its row, with\n * `onDelete(\"cascade\")`, one optional reference per `t.file()` field of the schema (`postImage`,\n * `userAvatar`): deleting a post — by name, or because its author was deleted — deletes its files in\n * the same transaction, by the database's own rule. The field on the owner is the reverse side of\n * that reference.\n *\n * The bytes are the host's (./host.ts): a file on disk named by the row's id. They go only because\n * the row went — the host reads the deletions from marcidb's journal of this model.\n *\n * What a project sees is a VALUE: it writes a `File` (an upload, an endpoint's parameter) and reads a\n * `StoredFile`. The url is computed when the row is read, never stored.\n */\nimport { type Field } from \"../db/fields\";\nexport declare const FILE_MODEL = \"File\";\n/** A stored file as a project reads it. */\nexport type StoredFile = {\n /** Where the bytes are served from. Public, not guessable; it never changes for this file. */\n url: string;\n name: string;\n /** The media type: `image/jpeg`, `video/mp4`, `application/pdf`. */\n type: string;\n /** Bytes. */\n size: number;\n /** An image's dimensions in pixels (absent for anything else). */\n width?: number;\n height?: number;\n};\n/** A stored picture (`t.image()`): its size is always known. */\nexport type StoredImage = StoredFile & {\n width: number;\n height: number;\n};\n/**\n * A file as an endpoint receives it — the app's `File` (a picked file, a photo), uploaded with the\n * call. Written to a `t.file()` field, it is stored; an endpoint that writes it nowhere drops it.\n */\nexport type UploadedFile = {\n readonly name: string;\n readonly size: number;\n readonly type: string;\n};\n/** One `t.file()` field of the schema; `image` = it is a `t.image()`, with its rule. */\nexport type FileField = {\n model: string;\n key: string;\n array: boolean;\n owner: string;\n image?: ImageRule;\n};\nexport type ImageRule = {\n max: number;\n};\n/** What a file became when it was made fit for an image field: the facts its row carries from then on. */\nexport type ImageFacts = {\n name: string;\n type: string;\n size: number;\n width: number;\n height: number;\n};\n/** The reference on `File` that says \"I am this field of that row\": `Post.image` → `postImage`. */\nexport declare const fileOwnerKey: (model: string, key: string) => string;\n/** What a data browser may show of a file (the rest is the platform's bookkeeping). */\nexport declare const filePublicFields: () => {\n name: Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n type: Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n size: Field<number, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"int\";\n }>>;\n width: Field<number, {\n kind: \"scalar\";\n scalar: \"int\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n height: Field<number, {\n kind: \"scalar\";\n scalar: \"int\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n createdAt: Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n};\n/** The whole `File` of a schema with these `t.file()` fields. */\nexport declare const fileFields: (fields: FileField[]) => Record<string, Field<any, any>>;\n/**\n * What the host (./host.ts) gives the db layer of a bundle — a global, because the bundle carries its\n * own copy of this module. Absent (a unit test without a host): nothing is an upload, urls are relative.\n */\nexport type FilesSeam = {\n /** The id of the `File` row behind an upload of the current request; undefined for anything else —\n * a value the app sent as JSON is never an upload, whatever it looks like. */\n uploaded(value: unknown): string | undefined;\n url(id: string, name: string): string;\n /** Make the upload `id` fit for a `t.image()` field (its bytes are rewritten in place) and say what\n * it is now. Throws an `ApiError` for what is no picture. */\n image(id: string, rule: ImageRule): Promise<ImageFacts>;\n /** A write that may have removed rows of `File` went through the db (a delete, a rewritten file field): their bytes are due. */\n dirty: boolean;\n};\nexport declare const filesSeam: () => FilesSeam | undefined;\nexport declare const setFilesSeam: (value: FilesSeam | null) => void;\n/** The row a `StoredFile` the app handed back stands for (by its url); undefined for anything else. */\nexport declare const storedFileId: (value: unknown) => string | undefined;\nexport declare const fileUrl: (id: string, name: string) => string;\n","types/server/inject.d.ts":"export { t, model, defineDb, ref } from \"./db\";\nexport { ApiError } from \"./errors\";\nexport { channel } from \"./channel\";\nexport { request } from \"./context\";\nexport type { StoredFile, StoredImage } from \"./files/models\";\n","types/ui/colorKeys.gen.d.ts":"/** The keys whose value IS a color — every color property with its aliases: normalize the value\n * to '#rrggbbaa'. Pass-throughs: null / undefined (a reset), any string containing \"var(\" (the\n * core resolves theme vars), rippleColor's \"default\" (a core keyword). */\nexport declare const COLOR_KEYS: ReadonlySet<string>;\n/** The shorthands that expand into a color property. A color is only ONE of their value forms:\n * never normalize the value whole — \"2px solid red\", a gradient or an image path go to the core\n * raw (its shorthand parsers read the colors inside with the same grammar), a number on\n * `border*` is a WIDTH; only a number / color array on `background` is a color. */\nexport declare const COLOR_SHORTHAND_KEYS: ReadonlySet<string>;\n","types/ui/fonts.d.ts":"type FontOptions = {\n weight?: number;\n style?: \"normal\" | \"italic\";\n};\n/** Register a font face from a URL at runtime under `fontFamily`; resolves once it's ready to\n * use in styles. For registry/project fonts prefer the compile-time `font()` macro — this is the\n * dynamic escape hatch. */\nexport declare function registerFont(fontFamily: string, url: string, options?: FontOptions): Promise<void>;\nexport {};\n","types/ui/NativeView.d.ts":"import { type UIWidgetContent } from \"./UILayer\";\nimport { type DismissOptions, type PresentOptions } from \"./presentable\";\nimport { type BaseStyle, type DrawableStyle, type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UINativeViewStyle = ElementStyle & DrawableStyle;\n/** An instance of a host-registered platform view (map, QR scanner, camera preview, …) —\n * embeddable among a screen's children AND fullscreen-presentable (`open()`); one instance lives\n * in one place at a time. Talk to it via the `call`/`on` channel. */\nexport interface NativeView extends UIElementBase<UINativeViewStyle, DrawableStyle & BaseStyle> {\n readonly type: \"native\";\n /** The registered view kind this instance resolves to (the `registerView` name). */\n readonly viewName: string;\n /** Creation params, passed to the host factory (JSON-serializable). */\n readonly params: any;\n /** Show fullscreen as the current destination (see Presentable). */\n open(options?: PresentOptions): void;\n /** Dismiss if this is the visible destination. */\n close(options?: DismissOptions): void;\n /** Became the visible destination. */\n onOpen(callback: () => void): this;\n /** Stopped being the visible destination. */\n onClose(callback: () => void): this;\n /** Hardware/system back while current. */\n onBack(callback: () => void): this;\n /** Invoke a method on the native view (`map.call(\"setCenter\", [lng, lat])`). Args and the\n * result are plain data (and Uint8Array). Rejects if the host has no such view/method. */\n call(method: string, ...args: any[]): Promise<any>;\n /** Subscribe to an event the native view emits (`map.on(\"markerTap\", cb)`). */\n on(event: string, callback: (data?: any) => void): this;\n off(event: string, callback: (data?: any) => void): this;\n /** The UI over the view when presented: widgets over it (`Presentable.setContent`). */\n setContent(content: UIWidgetContent): this;\n}\n/**\n * Create an instance of a host-registered platform view. `NativeView.isSupported(name)` reports\n * whether this host registered a factory for it. Style via the chained `.style()`.\n */\nexport declare const NativeView: {\n (name: string, params?: object): NativeView;\n /** Whether this host registered a `registerView` factory under `name`. */\n isSupported(name: string): boolean;\n /** The contract version of the host's view `name`: 0 when it has none, 1 for one written by hand. */\n version(name: string): number;\n};\n","types/ui/presentable.d.ts":"import type { EasingInput } from \"../animate/tween/easing\";\nimport type { UIWidget } from \"./UIWidget\";\n/** The built-in transitions (ui/transitions.ts holds what each one is). `push` / `pop` are the\n * stacked-navigation pair — the incoming screen slides over the other one, which drifts and dims;\n * the rest are two-screen moves. */\nexport type TransitionName = \"push\" | \"pop\" | \"slide-from-left\" | \"slide-from-right\" | \"slide-from-top\" | \"slide-from-bottom\" | \"zoom\" | \"zoom-in\" | \"zoom-out\" | \"fade\" | \"none\";\n/**\n * One screen's pose in a transition — the keys of an `animateTo` bag a transition can move, with\n * the side's own timing. An array is a list of keyframes, as there.\n */\nexport type TransitionPose = {\n /** A transform list, as in a style — and here a `%` in `translate` is a percent of the screen's\n * own box: `\"translateX(100%)\"` is one width to the right. */\n transform?: string | string[];\n opacity?: number | number[];\n /** Black over this screen, 0..1: how dark the screen UNDER the other one gets. */\n dim?: number | number[];\n /** A widget's overlay layer (its scrim) in the pose — a widget's enter / exit pose only\n * (`UIModal.transition`): `\"transparent\"` fades the scrim in with the dialog. */\n overlayColor?: string | string[];\n /** ms (default 300). */\n duration?: number;\n /** ms to wait; the screen holds its first pose through it. */\n delay?: number;\n /** Any curve `animateTo` takes (default `ease-in-out`). */\n easing?: EasingInput;\n};\n/**\n * A transition between two destinations, described by where each side is when it is NOT at rest:\n * the incoming one comes FROM `enter`, the outgoing one goes TO `exit`. A side left out stays put.\n *\n * ```ts\n * Router.push(page, { transition: { enter: { transform: \"translateY(100%)\", duration: 400 }, exit: { dim: 0.3 } } })\n * ```\n *\n * A screen's own `transform` / `opacity` are not seen while a transition moves it (put a lasting\n * effect on a child). A scene, a native view, a video never move: next to one of them only the\n * screen's side plays, above it.\n */\nexport interface TransitionSpec {\n /** The incoming destination's start: it moves from this pose to rest. */\n enter?: TransitionPose;\n /** The outgoing destination's end: it moves from rest to this pose. */\n exit?: TransitionPose;\n /** Which side is above the other while they move (default `\"enter\"`). */\n onTop?: \"enter\" | \"exit\";\n}\nexport type Transition = TransitionName | TransitionSpec;\nexport type PresentOptions = {\n /** Transition to play while this destination replaces the current one (default \"none\" for a\n * direct open(); the Router applies its own defaults — push/pop, and the theme's\n * `replaceTransition` for replace). */\n transition?: Transition;\n};\n/** `close()` / `Router.hide()`: the transition the destination leaves with (default \"none\"). */\nexport type DismissOptions = {\n transition?: Transition;\n};\n/**\n * Anything that can be shown as the app's current destination: a `UIScreen`, a `Scene` /\n * `ARScene`, a `Scene2D`, a `NativeView`, or a `UIVideo`. One Presentable is visible at a time;\n * open it directly (`p.open()` — replaces the current destination, suspending an active Router\n * until `Router.restore()`) or navigate with `Router.push/replace/pop`.\n *\n * `onOpen`/`onClose` are the presentation lifecycle (fired when the destination becomes / stops\n * being the visible one — including router pushes covering it and pops revealing it).\n */\nexport interface Presentable {\n open(options?: PresentOptions): void | this | Promise<void>;\n /** Close this destination if it is the one on screen (nothing takes its place). One that is not\n * on screen — already replaced by a `Router.init/push/replace` or another `open()` — is left as\n * it is, so `Router.init(home); scene.close()` keeps `home` visible. */\n close(options?: DismissOptions): void;\n onOpen(callback: () => void): this;\n onClose(callback: () => void): this;\n onBack(callback: () => void): this;\n /** The destination's widgets (docs/plans/widgets-plan.md): a dialog, a HUD, a sheet declared as\n * CONTENT of the place they belong to. A `UIScreen` takes them among its children; a surface — a\n * `Scene`, a `Scene2D`, a `NativeView`, a `UIVideo` — takes widgets alone, laid out over it while\n * it is presented (touches outside a widget's box reach the surface). A widget shows with its\n * destination unless its style says `display: \"none\"`; `show()` / `hide()` flip that. */\n setContent(content: (UIWidget | null | undefined | false)[] | (() => (UIWidget | null | undefined | false)[])): this;\n}\n/** Runtime companion of the `Presentable` interface (declaration merging): the navigation\n * state that isn't tied to the Router. */\nexport declare const Presentable: Readonly<{\n /** The destination visible right now (a `UIScreen`, `Scene`, `Scene2D`, `NativeView` or\n * `UIVideo`), or `null` before the first open. Distinct from `Router.current` — that is the\n * top of the router stack, which stays meaningful while the router is suspended by a direct\n * `open()`; this is what is actually on screen. `UIWidget.show()` attaches to it. */\n readonly current: Presentable | null;\n}>;\n","types/ui/router.d.ts":"import { Presentable, type DismissOptions, type PresentOptions, type Transition } from \"./presentable\";\ntype RouterOptions = {\n showDefaultBackButton?: boolean;\n};\nexport type NavigateOptions = {\n /** Transition to play. Defaults: `\"push\"` for push; replace follows the theme's\n * `replaceTransition` (`\"none\"` out of the box); a pop plays the way back the destination it\n * pops remembers. */\n transition?: Transition;\n /** The way BACK from the destination — what `Router.pop()` without a transition, the edge swipe\n * and the system's back play when they take it off the stack. Default: the transition it came\n * with, the other way round (a push goes back with a pop, a slide from the bottom leaves\n * downwards; a zoom goes back with a fade). A `replace` that names none keeps the way back of\n * the destination it replaces: it belongs to the place in the stack. */\n popTransition?: Transition;\n};\nexport type PopOptions = {\n /** Transition to play instead of the way back the popped destination remembers. */\n transition?: Transition;\n};\n/** Stack navigation over `Presentable` destinations. `init` once with the home page, then\n * `push`/`replace`/`pop`; the back gesture/button pops natively. A direct `page.open()` suspends\n * the router until `restore()`. */\ntype Router = {\n /** The top of the router stack (not necessarily what's on screen — see `Presentable.current`). */\n get current(): Presentable;\n /** Mount the router with `homePage` as the stack root — the app's navigation entry point. */\n init(homePage: Presentable, opts?: RouterOptions): void;\n /** Push a destination onto the stack — a `UIScreen`, a `Scene`, a `Scene2D`, a `NativeView`,\n * or a `UIVideo`. The back gesture/button pops it. Destinations with async preparation\n * (`ARScene`: camera permission + warm render) return a Promise — the current page stays\n * visible until they're ready, and a rejection (permission denied / superseded) leaves the\n * stack untouched. */\n push(page: Presentable, opts?: NavigateOptions): void | Promise<void>;\n /** Swap the top of the stack for `page` — no back entry to the replaced one. */\n replace(page: Presentable, opts?: NavigateOptions): void | Promise<void>;\n /** Pop the top destination (the programmatic twin of the back gesture); `to` unwinds to a\n * stack index in one step. */\n pop(to?: number, opts?: PopOptions): void;\n /** Blank the router's page, keeping the stack — `restore()` brings it back. A destination\n * opened directly stays visible. */\n hide(opts?: DismissOptions): void;\n /** Re-present the stack top after `hide()` or a direct `open()` suspended the router. */\n restore(opts?: PresentOptions): void;\n /** `\"change\"` fires on every stack change — pushes, pops, and native back gestures — with the\n * new top destination. */\n addEventListener(channel: \"change\", callback: (page: Presentable) => void): void;\n removeEventListener(channel: \"change\", callback: (page: Presentable) => void): void;\n};\nexport declare const Router: Router;\nexport {};\n","types/ui/styleColor.d.ts":"export {};\n","types/ui/theme.d.ts":"import type { Transition } from \"./presentable\";\nexport type ThemeValues = Record<string, string | number | null>;\n/** The keys the SDK itself reads — the ROLES of a theme. An app's own keys sit beside them in the\n * same call; kit components (`UITabs`) and the defaults of screens and text read these and nothing\n * else, so one palette colors the app and the kit alike. A color is a string, never a number. */\nexport type ThemeRoles = {\n /** The background of every screen. */\n bg?: string | null;\n /** A raised surface — cards, bars, sheets. The tab bar's background (without it: `bg`). */\n surface?: string | null;\n /** Hairlines and outlines. The tab bar's top line. */\n border?: string | null;\n /** Text that names no `color` of its own. */\n text?: string | null;\n /** Secondary text and inactive controls. The tab bar's inactive tabs. */\n textMuted?: string | null;\n /** The brand / active color. The tab bar's active tab. */\n accent?: string | null;\n /** The font of text that names no `fontFamily` of its own. */\n fontFamily?: string | null;\n};\n/** What only the app-wide `theme()` takes: the comfort knobs (logical px) and the Router's default\n * `replace` transition. */\nexport type ThemeAppKeys = {\n \"comfort-top\"?: number | string | null;\n \"comfort-bottom\"?: number | string | null;\n \"comfort-left\"?: number | string | null;\n \"comfort-right\"?: number | string | null;\n replaceTransition?: Transition | null;\n};\n/** The `var(--key)` strings of the keys a `theme()` call defined — plain strings, so a helper's\n * `(color = colors.accent)` parameter takes any color. */\nexport type ThemeAccessors<T> = {\n readonly [K in Exclude<keyof T, \"replaceTransition\">]: string;\n};\n/** App theme: callable to merge variables (`theme({...})` — re-calling re-styles the live UI, so\n * dark mode is just a second call), with the roles as static properties (`theme.accent`,\n * `theme[\"comfort-top\"]`, …) for code that has no tokens module to import. */\nexport declare const theme: (<T extends ThemeRoles & ThemeAppKeys & Record<string, string | number | Transition | null>>(values: T & { [K in Exclude<keyof T, \"replaceTransition\">]: string | number | null; }) => ThemeAccessors<T>) & {\n /** The background of every screen. */\n readonly bg: \"var(--bg)\";\n /** A raised surface — cards, bars, sheets. */\n readonly surface: \"var(--surface)\";\n /** Hairlines and outlines. */\n readonly border: \"var(--border)\";\n /** DEFAULT text color — text without a `color` of its own follows it (unset = the host's\n * default: white). Set it once for a light theme instead of a color on every label. */\n readonly text: \"var(--text)\";\n /** Secondary text and inactive controls. */\n readonly textMuted: \"var(--textMuted)\";\n /** The brand / active color. */\n readonly accent: \"var(--accent)\";\n /** DEFAULT text font — text without a `fontFamily` of its own follows it. */\n readonly fontFamily: \"var(--fontFamily)\";\n /** Raw comfort knobs (logical px). The bare `comfort-top` style TOKEN applies the safe-area\n * formula — these accessors read the knob value itself, for manual composition. */\n readonly \"comfort-top\": \"var(--comfort-top)\";\n readonly \"comfort-bottom\": \"var(--comfort-bottom)\";\n readonly \"comfort-left\": \"var(--comfort-left)\";\n readonly \"comfort-right\": \"var(--comfort-right)\";\n};\n","types/ui/transitions.d.ts":"import type { TransitionPose, TransitionSpec } from \"./presentable\";\n/** Wire ids: a registered transition is > 0. */\nexport declare const TRANSITION_NONE = 0;\n/** \"The caller names none\": the runtime plays what the stack entry remembers (a pop), or keeps\n * what the replaced entry remembered (a replace's way back). */\nexport declare const TRANSITION_UNSET = -1;\n/** Who a track moves. The ALONE roles play next to a destination that cannot move (a scene, a\n * native view, a video) or next to nothing (close(), the first open): only the screen plays, above. */\nexport declare const ROLE_ENTER = 0;\nexport declare const ROLE_EXIT = 1;\nexport declare const ROLE_ENTER_ALONE = 2;\nexport declare const ROLE_EXIT_ALONE = 3;\n/** `defineTransition` flags. */\nexport declare const TRANSITION_ENTER_ON_TOP = 1;\n/** The way back of a spec: the ROLES swap — the screen that came leaves into its `enter` pose, the\n * one that left comes back from its `exit` pose, the same screen stays on top — and the timing and\n * the curves stay as written. Not a rewind: that would turn an ease-out into a slow start. */\nexport declare const mirrored: (s: TransitionSpec) => TransitionSpec;\nexport declare const _widgetPoseId: (pose: TransitionPose | null) => number;\n","types/ui/tree.d.ts":"export declare const TREE_EVENT_LAYOUT = 1;\nexport declare const TREE_EVENT_TOUCH_START = 2;\nexport declare const TREE_EVENT_CLICK = 3;\nexport declare const TREE_EVENT_LONG_PRESS = 4;\nexport declare const TREE_EVENT_TOUCH_MOVE = 5;\nexport declare const TREE_EVENT_TOUCH_END = 6;\nexport declare const TREE_EVENT_TOUCH_CANCEL = 7;\nexport declare const TREE_EVENT_SCROLL = 8;\nexport declare const TREE_EVENT_OVERSCROLL = 9;\nexport declare const TREE_EVENT_SCROLL_RELEASE = 10;\nexport declare const TREE_EVENT_REFRESH = 11;\nexport declare const TREE_EVENT_CHANGE = 12;\nexport declare const TREE_EVENT_FOCUS = 13;\nexport declare const TREE_EVENT_BLUR = 14;\nexport declare const TREE_EVENT_SUBMIT = 15;\nexport declare const TREE_EVENT_OVERLAY_TAP = 16;\nexport declare const TREE_EVENT_DETENT = 17;\nexport declare const TREE_EVENT_OPEN = 18;\nexport declare const TREE_EVENT_CLOSE = 19;\nexport declare const TREE_EVENT_BACK = 20;\nexport declare const TREE_EVENT_PAGER_SELECT = 21;\nexport declare const TREE_EVENT_PAGER_POP = 22;\nexport declare const TREE_EVENT_VLIST_SYNC = 23;\nexport declare const TREE_EVENT_VLIST_EDGE = 24;\nexport declare const TREE_EVENT_VIEW_EVENT = 25;\nexport declare const TREE_EVENT_RESIZE = 26;\nexport declare const TREE_EVENT_ROUTER_CHANGE = 27;\nexport declare const TREE_EVENT_SCENE_TOUCH_START = 28;\nexport declare const TREE_EVENT_SCENE_CLICK = 29;\nexport declare const TREE_EVENT_DETACHED = 30;\nexport declare const TREE_EVENT_FREED = 31;\nexport declare const TREE_EVENT_HOVER_ENTER = 32;\nexport declare const TREE_EVENT_HOVER_MOVE = 33;\nexport declare const TREE_EVENT_HOVER_END = 34;\nexport declare const TREE_EVENT_HOVER_CANCEL = 35;\nexport declare const TREE_EVENT_WIDGET_VISIBLE = 36;\nexport declare const TREE_FLAG_INTERACTIVE: number;\nexport declare const TREE_FLAG_CLICK: number;\nexport declare const TREE_FLAG_LONG_PRESS: number;\nexport declare const TREE_FLAG_LAYOUT: number;\nexport declare const TREE_FLAG_SCROLL: number;\nexport declare const TREE_FLAG_OVERSCROLL: number;\nexport declare const TREE_FLAG_SCROLL_RELEASE: number;\nexport declare const TREE_FLAG_REFRESH: number;\nexport declare const TREE_FLAG_CHANGE: number;\nexport declare const TREE_FLAG_FOCUS: number;\nexport declare const TREE_FLAG_BLUR: number;\nexport declare const TREE_FLAG_SUBMIT: number;\nexport declare const TREE_FLAG_OVERLAY_TAP: number;\nexport declare const TREE_FLAG_DETENT: number;\nexport declare const TREE_FLAG_KEEP_ALIVE: number;\nexport declare const TREE_FLAG_BACK: number;\nexport declare const TREE_FLAG_VLIST_END: number;\nexport declare const TREE_FLAG_VLIST_START: number;\nexport declare const TREE_FLAG_HOVER: number;\nexport declare const TREE_TRACK_CLAIM_MASK = 255;\nexport declare const TREE_TRACK_TRACKED: number;\nexport declare const TREE_TRACK_MOVE: number;\nexport declare const TREE_TRACK_HANDLED: number;\nexport declare const TREE_DEST_SCREEN = 0;\nexport declare const TREE_DEST_SCENE3D = 1;\nexport declare const TREE_DEST_SCENE2D = 2;\nexport declare const TREE_DEST_NATIVE = 3;\nexport declare const TREE_DEST_VIDEO = 4;\nexport declare const TREE_DEST_NONE = 255;\nexport declare const OWNED_KIND_TREE = 0;\nexport declare const OWNED_KIND_FETCH = 1;\nexport declare const OWNED_KIND_GL_MATERIAL = 2;\nexport declare const OWNED_KIND_GL_TEXTURE = 3;\nexport declare const OWNED_KIND_GL_ENTITY = 4;\nexport declare const OWNED_KIND_ENTITY_2D = 5;\nexport declare const OWNED_KIND_MEDIA = 6;\nexport declare const OWNED_KIND_TWEEN = 7;\nexport declare const OWNED_KIND_CANVAS = 8;\nimport { DEAD_HANDLE } from \"../core/pins\";\nexport { DEAD_HANDLE };\n","types/ui/UI.d.ts":"export { UIButton, type UIButtonStyle } from './UIButton';\nexport { UIScreen, type UIScreenStyle } from './UIScreen';\nexport { UISpacer, type UISpacerStyle } from './UISpacer';\nexport { UIText, type UITextStyle } from './UIText';\nexport { registerFont } from './fonts';\nexport { UIImage, type UIImageStyle } from './UIImage';\nexport { UIVideo, type UIVideoStyle } from './UIVideo';\nexport { UIInput, UITextArea, type UIInputStyle } from './UIInput';\nexport { UIWidget, type UIWidgetStyle } from './UIWidget';\nexport { UIOverlay, type UIWidgetContent } from './UILayer';\nexport { UIModal, type UIModalStyle } from './UIModal';\nexport { UIBottomSheet, type UIBottomSheetStyle } from './UIBottomSheet';\nexport { UIPopover, type UIPopoverStyle, type UIPopoverAnchor } from './UIPopover';\nexport { UIRow, UIColumn, UIBox, type UIContainerStyle } from './UIContainer';\nexport { UIScrollable, type UIScrollableStyle } from './UIScrollable';\nexport { UIPager, type UIPagerStyle } from './UIPager';\nexport { UITabs, type UITabDef, defineTabs, type TabDef, type TabsHandle } from './UITabs';\nexport { UIVirtualizedList } from './UIVirtualizedList';\nexport { Router } from './router';\nexport { NativeView, type UINativeViewStyle } from './NativeView';\nexport { Presentable } from './presentable';\nexport type { DismissOptions, PresentOptions, Transition, TransitionName, TransitionPose, TransitionSpec } from './presentable';\nexport { __uiMap } from './UINode';\nexport { __UIColumn, __UIRow, __UIBox } from './UIContainer';\nexport { __UIButton } from './UIButton';\nexport { __UIScreen } from './UIScreen';\nexport { __UIScrollable } from './UIScrollable';\nexport { __UIWidget } from './UIWidget';\n","types/ui/UIBottomSheet.d.ts":"import { ModalElement, type UIModalStyle } from \"./UIModal\";\nimport type { UIWidget } from \"./UIWidget\";\nimport { type ChildrenFn, type UIChildArg, type UINodeChild } from \"./UINode\";\nexport type UIBottomSheetStyle = UIModalStyle;\n/**\n * A bottom sheet: a `UIWidget` pinned to the bottom edge. By default it is **content-sized** —\n * as tall as what's inside (capped at the screen), one position, drag down to dismiss (the\n * action-sheet shape). Call `detents()` for the multi-position map-app model instead: snap\n * positions the user drags between on native hosts. Ships as a widget node on the wire (no new\n * node type — docs/bottom-sheet-plan.md): hosts without sheet support show a static bottom panel.\n *\n * With detents, content lays out at the HIGHEST detent's size; lower detents show the top\n * slice. The scrim, `onOpen`/`onClose`, back-button and scrim-tap dismissal all come from the\n * modal machinery.\n *\n * ```ts\n * const actions = UIBottomSheet(rows).style({ bgColor: \"#1c1c1e\", borderRadius: 16 }) // content-sized\n *\n * const mapSheet = UIBottomSheet(results).style({ bgColor: \"#1c1c1e\", borderRadius: 16 })\n * .detents([0.3, 0.6, 1])\n * .onDetent(i => map.setPadding(...))\n * ```\n */\nexport interface UIBottomSheet extends UIWidget {\n /** Snap positions as fractions of screen height, ascending. Also sizes the sheet: its box is\n * the last (highest) detent; set this before `show()`. Without a `detents()` call the sheet\n * is CONTENT-SIZED instead — one position, as tall as its children (up to the screen). */\n detents(list: number[]): this;\n /** Snap to a detent (animated). Clamped to the detents range; fires `onDetent`. */\n setDetent(index: number): void;\n /** Current detent index. */\n readonly detent: number;\n /** Fires on every settle: a finger snap on native hosts, or a `setDetent()` call. */\n onDetent(callback: (index: number) => void): this;\n /** Mount and slide in to the current detent. No-op while already open. */\n show(): void;\n /** Slide out, fade the scrim, then unmount. No-op while closed. */\n hide(): void;\n /** True from `show()` until `hide()` starts. */\n readonly isOpen: boolean;\n /** Called when `show()` mounts the sheet. */\n onOpen(callback: () => void): this;\n /** Called when the sheet starts closing — scrim tap, back button, drag-dismiss, or `hide()`. */\n onClose(callback: () => void): this;\n /** `dismissible(false)`: scrim taps, the back button and dragging below the lowest detent no\n * longer close the sheet (a drag collapses to the lowest detent instead). Default `true`. */\n dismissible(enabled: boolean): this;\n}\nexport declare class BottomSheetElement extends ModalElement {\n _detents: number[];\n _detent: number;\n readonly _detentListeners: ((index: number) => void)[];\n constructor(style: UIBottomSheetStyle, children: UINodeChild[] | ChildrenFn);\n detents(list: number[]): this;\n get detent(): number;\n setDetent(index: number): void;\n onDetent(callback: (index: number) => void): this;\n show(): void;\n hide(): void;\n dismissible(enabled: boolean): this;\n}\n/** Create a bottom sheet (see {@link UIBottomSheet}) — content-sized by default; call\n * `.detents([...])` for snap positions. Same argument forms as `UIColumn`. */\nexport declare function UIBottomSheet(...children: UIChildArg[]): UIBottomSheet;\nexport declare function UIBottomSheet(children: UINodeChild[] | ChildrenFn): UIBottomSheet;\n","types/ui/UIButton.d.ts":"import type { ClickEvent as ClickEventType, TouchStartEvent as TouchStartEventType, LongPressEvent as LongPressEventType, MouseEnterEvent as MouseEnterEventType } from \"../runtime/touch\";\nimport { type ElementStyle, type ContainerStyle, type DrawableStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn, type BaseStyle, type Color } from \"./UINode\";\nexport type UIButtonStyle = ElementStyle & DrawableStyle & ContainerStyle & {\n rippleColor?: Color | \"default\";\n};\n/** A tappable container — row + centered children by default. Press feedback via the `$pressed`\n * class block or `rippleColor`. */\nexport interface UIButton extends UIContainerBase<UIButtonStyle, DrawableStyle & BaseStyle> {\n readonly type: \"button\";\n /** Fired on a completed tap/click. */\n onClick(callback: (ev: ClickEventType<UIButton>) => void): this;\n /** Fired when a touch begins; `ev.track(...)` takes over the rest of the gesture (dragging). */\n onTouchStart(callback: (ev: TouchStartEventType<UIButton>) => void): this;\n /** Fired when a finger is held on the button past the long-press threshold. The event can\n * `ev.track(...)` the rest of the gesture (like `onTouchStart`), so a hold can flow straight into\n * dragging the element. A handled long-press suppresses the click that would follow the release. */\n onLongPress(callback: (ev: LongPressEventType<UIButton>) => void): this;\n /** Fired when a mouse cursor (no button) enters the button — desktop / web; touch never fires it.\n * There is no leave event: `ev.track({ onMove, onEnd, onCancel })` follows the hover to its\n * end. The visual state is the reserved `$hovered` class (cascades like `$pressed`). */\n onMouseEnter(callback: (ev: MouseEnterEventType<UIButton>) => void): this;\n /** Is a finger currently down on the button? */\n readonly isPressed: boolean;\n /** Is a mouse cursor currently over the button (the topmost interactive node under it)? */\n readonly isHovered: boolean;\n}\n/** Create a button (row + centered by default — the icon+label shape). Same argument forms as\n * `UIColumn`; attach behavior with `.onClick(...)`. */\nexport declare function UIButton(...children: UIChildArg[]): UIButton;\nexport declare function UIButton(children: UINodeChild[] | ChildrenFn): UIButton;\n","types/ui/UIContainer.d.ts":"import { type ChildrenFn, type ContainerStyle, type DrawableStyle, type ElementStyle, type UIChildArg, type UIContainerBase, type UINodeChild } from \"./UINode\";\nexport type UIContainerStyle = ElementStyle & DrawableStyle & ContainerStyle;\n/** A vertical flex container — children stack top to bottom. */\nexport interface UIColumn extends UIContainerBase<UIContainerStyle> {\n readonly type: \"column\";\n}\nexport declare const __UIRow: (children: UINodeChild[] | ChildrenFn) => UIRow;\nexport declare const __UIBox: (children: UINodeChild[] | ChildrenFn) => UIBox;\n/** Create a vertical flex container. Children are variadic — arrays flatten one level, falsy\n * entries are skipped; a lone function makes the children reactive. */\nexport declare function UIColumn(...children: UIChildArg[]): UIColumn;\nexport declare function UIColumn(children: UINodeChild[] | ChildrenFn): UIColumn;\n/** A horizontal flex container — children flow left to right. */\nexport interface UIRow extends UIContainerBase<UIContainerStyle> {\n readonly type: \"row\";\n}\n/** Create a horizontal flex container (same argument forms as `UIColumn`). */\nexport declare function UIRow(...children: UIChildArg[]): UIRow;\nexport declare function UIRow(children: UINodeChild[] | ChildrenFn): UIRow;\n/** A centering container — `justifyContent`/`alignItems` default to center. */\nexport interface UIBox extends UIContainerBase<UIContainerStyle> {\n readonly type: \"box\";\n}\n/** Create a centering container — children are centered on both axes by default (icon badges,\n * avatars, empty states). Same argument forms as `UIColumn`. */\nexport declare function UIBox(...children: UIChildArg[]): UIBox;\nexport declare function UIBox(children: UINodeChild[] | ChildrenFn): UIBox;\n","types/ui/UIImage.d.ts":"import type { FetchResponse } from \"../runtime/fetch\";\nimport type { SvgSourceValue as SvgSource } from \"../runtime/misc\";\nimport type { File } from \"../runtime/fetch\";\nimport { Canvas } from \"../canvas/Canvas\";\nimport type { Scene2D } from \"../g2/Scene2D\";\nimport { type Color, type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UIImageStyle = ElementStyle & {\n borderRadius?: number;\n objectFit?: \"cover\" | \"contain\" | \"fill\";\n tintColor?: Color;\n};\n/** A baked Canvas surface as an image source. The UI backend resolves it to a UI texture. */\nexport type CanvasImageSource = {\n canvasSurface: number;\n};\n/** A live 2D scene as an image source: the host draws the scene into the node's box every frame\n * (the scene's camera, projected into the box). No intrinsic size — give the node a width and\n * height. */\nexport type Scene2DImageSource = {\n scene2d: number;\n};\n/** Accepted image sources. A Canvas is baked to a surface marker on assign; a Scene2D becomes a\n * live-scene marker. */\nexport type ImageSource = string | FetchResponse | File | SvgSource | Canvas | Scene2D;\n/** The stored/resolved image source (a Canvas is resolved to a surface marker, a Scene2D to a\n * live-scene marker). */\nexport type ResolvedImageSource = string | FetchResponse | File | SvgSource | CanvasImageSource | Scene2DImageSource;\n/** An image element. Sources: URL / `asset(...)`, fetch response / File, an SVG source\n * (`assetIcon`), a live Canvas (`canvas.update()` refreshes the node in place), or a live Scene2D\n * (drawn into the box every frame — a minimap). */\nexport interface UIImage extends UIElementBase<UIImageStyle> {\n readonly type: \"image\";\n /** The image source — writable to swap the picture in place. */\n get src(): ResolvedImageSource;\n set src(value: ImageSource);\n /** Render only a sub-rectangle of the source texture (texture pixels) — the atlas/spritesheet\n * primitive: crop once, then swap the rect per frame for sprite animation. The rect's w/h\n * become the node's intrinsic size and override `objectFit` — the cropped frame fills the box. */\n setSourceRect(x: number, y: number, w: number, h: number): this;\n}\n/** Create an image element from a source (see {@link ImageSource}). */\nexport declare function UIImage(src: ImageSource): UIImage;\n","types/ui/UIInput.d.ts":"import { type ElementStyle, type DrawableStyle, type TextStyle, type Color, type BaseStyle, type UIElementBase } from \"./UINode\";\ntype InputStyle = {\n placeholder?: string;\n placeholderColor?: Color;\n /**\n * Keyboard hint, NOT a validator — `number` does not block pasted letters; validate in your own\n * onChange. The phone-pad value is `phone` (LeCodes has no `tel`).\n *\n * `date` / `time` are PICKER kinds, not keyboards: the host opens its native picker in the\n * keyboard slot (iOS wheels / browser calendar) and free typing is disabled. `value` is always\n * canonical — `YYYY-MM-DD` for `date`, `HH:MM` (24h) for `time` — while the field displays a\n * localized string; set/compare values in the canonical form only.\n */\n type?: \"text\" | \"password\" | \"search\" | \"phone\" | \"email\" | \"number\" | \"decimal\" | \"url\" | \"date\" | \"time\";\n /**\n * What the layout does while the keyboard is up (decided by the FOCUSED input). `true` (default):\n * the layout viewport shrinks to the area above the keyboard — one relayout. `false`: the keyboard\n * overlays the UI with NO layout recalculation — for chat composers that manage their own inset\n * (pair with `app.keyboardHeight` / the app `\"keyboard\"` event) and full-screen canvases where a\n * reflow is worse than overlap.\n */\n keyboardShrink?: boolean;\n /**\n * Whether a tap on a non-interactive area dismisses the keyboard while THIS input is focused\n * (like `keyboardShrink`, the policy of the focused input). `true` (default): tapping dead\n * space blurs — but a tap on a button or another input NEVER dismisses; the control acts and\n * focus stays. `false`: taps never dismiss — the chat-composer policy. `blur()`, the return\n * key (per `enterKey`), and the platform's own gestures (iOS drag-down over the keyboard)\n * still work in both modes. Scrolling never dismisses the keyboard on any setting.\n */\n keyboardDismiss?: boolean;\n /** Hard cap on the text length — enforced by the host while typing/pasting. */\n maxLength?: number;\n /** Auto-capitalization hint; omitted = platform default. */\n autocapitalize?: \"none\" | \"words\" | \"sentences\" | \"characters\";\n /** Enable/disable the platform autocorrection & suggestions; omitted = platform default. */\n autocorrect?: boolean;\n};\nexport type UIInputStyle = ElementStyle & DrawableStyle & TextStyle & InputStyle;\n/** UIInput-only (a UITextArea's Enter is a newline, period): the return-key label. */\ntype SubmitStyle = {\n /**\n * Return-key label. On submit the keyboard dismisses UNLESS `enterKey` is `\"next\"` — then the\n * app is expected to call `otherInput.focus()` from `onSubmit`, so the keyboard never blinks.\n */\n enterKey?: \"done\" | \"go\" | \"next\" | \"search\" | \"send\";\n};\n/** A single-line text input. Keyboard/picker kind via the `type` style, return-key behavior via\n * `enterKey` + `onSubmit`; keyboard policy on `keyboardShrink`/`keyboardDismiss`. */\nexport interface UIInput extends UIElementBase<UIInputStyle & SubmitStyle, DrawableStyle & BaseStyle> {\n readonly type: \"input\";\n /** The field's text. Writable at any time; reads return the live text (the host owns the field\n * while the user types — IME composition, paste, the maxLength clamp, date/time canonicalization). */\n value: string;\n /** The text changed — fires on every user edit. */\n onChange(callback: (value: string) => void): UIInput;\n /** Gained focus (keyboard opens). */\n onFocus(callback: () => void): UIInput;\n /** Lost focus. */\n onBlur(callback: () => void): UIInput;\n /** The keyboard's return key was pressed. `value` is the current text. See `enterKey`. */\n onSubmit(callback: (value: string) => void): UIInput;\n /** Focus the input (opens the keyboard). */\n focus(): void;\n /** Release focus (dismisses the keyboard when this input held it). */\n blur(): void;\n}\n/** A multi-line text field — see the {@link UITextArea} factory for the auto-grow contract. */\nexport interface UITextArea extends UIElementBase<UIInputStyle, DrawableStyle & BaseStyle> {\n readonly type: \"textarea\";\n /** The field's text — same contract as {@link UIInput.value}. */\n value: string;\n /** The text changed — fires on every user edit. */\n onChange(callback: (value: string) => void): UITextArea;\n /** Gained focus (keyboard opens). */\n onFocus(callback: () => void): UITextArea;\n /** Lost focus. */\n onBlur(callback: () => void): UITextArea;\n /** Focus the text area (opens the keyboard). */\n focus(): void;\n /** Release focus (dismisses the keyboard when this text area held it). */\n blur(): void;\n}\n/** Create a single-line text input. Read/write the text via `.value`, listen with\n * `onChange`/`onSubmit`; style keys `placeholder`, `type`, `enterKey`, … configure it. */\nexport declare function UIInput(): UIInput;\nexport declare function UIInput(style: UIInputStyle): UIInput;\n/**\n * Multi-line text field. Enter is a newline (submit lives on UIInput / your own button).\n *\n * Auto-grow: with no explicit `height` the field measures its own content and grows line by\n * line — clamp the range with `minHeight` / `maxHeight` (past `maxHeight` the text scrolls\n * inside). A fixed `height` opts out and scrolls internally from the start. Chat composers are\n * the canonical use: a bare textarea in a padded pill, `maxHeight` at ~5 lines.\n */\nexport declare function UITextArea(): UITextArea;\nexport declare function UITextArea(style: UIInputStyle): UITextArea;\nexport {};\n","types/ui/UILayer.d.ts":"import type { UIWidget } from \"./UIWidget\";\nexport type UIWidgetContent = (UIWidget | null | undefined | false)[] | (() => (UIWidget | null | undefined | false)[]);\n/**\n * The app layer: the widgets above EVERY destination, always shown — a global loader, a mini-player\n * that follows the user across screens, a toast with actions. Widgets that belong to a place go in\n * that place instead: a dialog among its screen's children (`UIScreen(..., dialog)`), a HUD in\n * `scene.setContent([hud])`. A widget shown with `show()` while it has no parent lands here.\n *\n * ```ts\n * UIOverlay.append(miniPlayer)\n * miniPlayer.hide() // display: none — still here, ready for show()\n * ```\n */\nexport declare const UIOverlay: Readonly<{\n /** Add widgets at the end (on top). */\n append(...widgets: (UIWidget | null | undefined | false)[]): void;\n /** Insert widgets at `index` (0 = the bottom of the layer). */\n insert(index: number, ...widgets: (UIWidget | null | undefined | false)[]): void;\n /** Take widgets out of the layer (they stay valid; a dropped one is freed). */\n remove(...widgets: (UIWidget | null | undefined | false)[]): void;\n /** Replace the layer's widgets — a list, or a function for reactive content. */\n setContent(content: UIWidgetContent): void;\n /** The layer's widgets, bottom to top (a snapshot read from the runtime). */\n readonly children: UIWidget[];\n}>;\n","types/ui/UIModal.d.ts":"import { type UIWidget, type UIWidgetStyle, WidgetElement } from \"./UIWidget\";\nimport { type BaseStyle, type ChildrenFn, type Color, type DrawableStyle, type UIChildArg, type UINodeChild } from \"./UINode\";\nexport type UIModalStyle = UIWidgetStyle;\n/**\n * The modal's hidden pose: `show()` animates from it, `hide()` animates to it. `duration` (ms)\n * applies to both directions.\n */\nexport type UIModalTransition = DrawableStyle & BaseStyle & {\n overlayColor?: Color | null;\n duration?: number;\n};\n/**\n * A dialog: a `UIWidget` with the modal boilerplate built in. Comes with a scrim\n * (`overlayColor: \"rgba(0, 0, 0, 0.5)\"` unless overridden), animates on `show()`/`hide()` and on\n * a state block flipping its `display` (a 200 ms fade by default — swap the pose via\n * `transition()`; the runtime plays it as tracks that never touch the style), and closes itself\n * on a scrim tap or the Android back button (disable via `dismissible(false)`). Everything else\n * is a plain widget: declare it where it belongs — among its screen's children, hidden until a\n * tap (`display: \"none\"`), or shown with `show()` from anywhere, which puts a parentless modal in\n * the app layer. A dialog bound to data (its display from a binding) is declared\n * `dismissible(false)` and routes `onOverlayTap` / `onBack` into the data's dismiss, so the data\n * stays what the screen shows.\n */\nexport interface UIModal extends UIWidget {\n /** Show and play the entrance transition. No-op while already open. */\n show(): void;\n /** Play the exit transition, then hide. No-op while closed or already closing. */\n hide(): void;\n /** True from `show()` until `hide()` starts (already false during the exit animation). */\n readonly isOpen: boolean;\n /**\n * Replace the show/hide animation. `hidden` is the off-screen pose — `show()` animates from\n * it, `hide()` animates to it. Default `{ opacity: 0, duration: 200 }` (a fade); the pose\n * replaces it wholesale, so a slide without a fade is just the slide. The scrim keeps its own\n * fade unless the pose sets `overlayColor` itself.\n *\n * ```ts\n * sheet.transition({ transform: \"translateY(480px)\", duration: 250 }) // bottom sheet\n * ```\n */\n transition(hidden: UIModalTransition): this;\n /** Called when the modal opens — `show()`, or a state block flipping its display. */\n onOpen(callback: () => void): this;\n /** Called when the modal starts closing — scrim tap, back button, a `hide()` call, or a state\n * block flipping its display. */\n onClose(callback: () => void): this;\n /** `dismissible(false)` keeps scrim taps and the back button from closing the modal\n * (forced-choice dialogs, a dialog whose display is bound to data). Default `true`. */\n dismissible(enabled: boolean): this;\n}\nexport declare class ModalElement extends WidgetElement {\n _dismissible: boolean;\n _transition: UIModalTransition;\n readonly _openListeners: (() => void)[];\n readonly _closeListeners: (() => void)[];\n private _poseObj?;\n private _poseKey;\n constructor(style: UIModalStyle, children: UINodeChild[] | ChildrenFn);\n private _pose;\n transition(hidden: UIModalTransition): this;\n show(): void;\n hide(): void;\n get isOpen(): boolean;\n onOpen(callback: () => void): this;\n onClose(callback: () => void): this;\n dismissible(enabled: boolean): this;\n}\n/** Create a modal dialog (see {@link UIModal}): declare it among its screen's children with\n * `display: \"none\"` and `show()` it from a tap, or `show()` a parentless one from anywhere.\n * Same argument forms as `UIColumn`. */\nexport declare function UIModal(...children: UIChildArg[]): UIModal;\nexport declare function UIModal(children: UINodeChild[] | ChildrenFn): UIModal;\n","types/ui/UINode.d.ts":"import type { FetchResponse } from \"../runtime/fetch\";\nimport type { SvgSourceValue } from \"../runtime/misc\";\nimport type { ColorInput } from \"../core/color\";\nimport type { Animation } from \"../animate/tween/Animation\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport { type ThemeRoles } from \"./theme\";\nimport { type TreeElement } from \"./tree\";\nexport interface UINode {\n readonly type: string;\n /** Author-given semantic name (a stable selector for tests + AI review feedback). */\n name?: string;\n style: Style<this, any>;\n /** Style-class proxy — read/set/toggle/bind the `$`-classes declared in `.style()`. See {@link Classes}. */\n readonly class: Classes<this>;\n}\n/** A child slot value: a node, or falsy (conditional rendering — falsy entries are skipped). */\nexport type UINodeChild = UINode | null | undefined | false;\n/** A factory child argument: a node (or falsy for conditionals), or an array of them — arrays are\n * flattened one level at the argument position, so `UIColumn(header, items.map(row), footer)`\n * needs no spread. */\nexport type UIChildArg = UINodeChild | UINodeChild[];\n/** A color: any CSS color string (`\"#1c1c1e\"`, `\"rgba(0,0,0,0.5)\"`, `\"green\"`, `\"hsl(210 50% 40%)\"`),\n * a theme reference (`\"var(--accent)\"`), an opaque `0xRRGGBB` number or `[r, g, b(, a)]` in\n * 0..1; `null` clears. A string is the core's to parse (an unknown one is transparent, as in\n * CSS); a number or an array that is not a color throws at the write. */\nexport type Color = ColorInput | null;\n/** Style props every element accepts. */\nexport type BaseStyle = {\n opacity?: number | `${number}`;\n transform?: string | null;\n /** Pivot of `transform` (CSS `transform-origin` subset): one or two values, each a keyword\n * (`left`/`center`/`right`, `top`/`center`/`bottom`), a percentage of the box, or a px length\n * (bare numbers are px). One value sets x, y stays `50%`. Default `\"50% 50%\"` = the centre. */\n transformOrigin?: string | null;\n backgroundColor?: Color | null;\n bgColor?: Color | null;\n overflow?: \"visible\" | \"hidden\";\n boxSizing?: \"border-box\" | \"content-box\";\n};\n/** Painted-box props: background, gradient, border, radius. */\nexport type DrawableStyle = {\n backgroundImage?: FetchResponse | File | SvgSourceValue | string | null;\n bgGradient?: string;\n backgroundGradient?: string;\n bgImage?: FetchResponse | File | SvgSourceValue | string | null;\n /** How the image fills the box. \"tile\": repeated at its own size from the top-left corner. */\n backgroundSize?: \"cover\" | \"contain\" | \"fill\" | \"tile\";\n bgSize?: \"cover\" | \"contain\" | \"fill\" | \"tile\";\n border?: string | number | null;\n borderWidth?: number;\n borderColor?: Color;\n borderLeft?: string | number | null;\n borderLeftWidth?: number;\n borderLeftColor?: Color;\n borderTop?: string | number | null;\n borderTopWidth?: number;\n borderTopColor?: Color;\n borderRight?: string | number | null;\n borderRightWidth?: number;\n borderRightColor?: Color;\n borderBottom?: string | number | null;\n borderBottomWidth?: number;\n borderBottomColor?: Color;\n borderRadius?: UIValue | string;\n borderTopLeftRadius?: UIValue;\n borderTopRightRadius?: UIValue;\n borderBottomLeftRadius?: UIValue;\n borderBottomRightRadius?: UIValue;\n pointerEvents?: \"all\" | \"none\";\n};\n/** Flex-layout props of a container (how it lays out its children). */\nexport type ContainerStyle = {\n flexDirection?: \"row\" | \"column\";\n justifyContent?: \"flex-start\" | \"center\" | \"flex-end\" | \"space-between\" | \"space-evenly\";\n alignItems?: \"flex-start\" | \"center\" | \"flex-end\" | \"stretch\";\n gap?: UIValue;\n flexWrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n};\n/** A dimension: a number (logical px) or a CSS-style unit / function string. */\ntype UIValue = number | `${number}px` | `${number}vw` | `${number}vh` | `${number}vmin` | `${number}vmax` | `${number}em` | `calc(${string})` | `min(${string})` | `max(${string})` | `${string}%` | `clamp(${string})` | `var(--${string})`;\n/** Padding, with `p`/`px`/`pl`… shorthands. `safe-*` insets by the device safe area,\n * `comfort-*` by the theme's comfort knobs (max of both). */\nexport type PaddingStyle = {\n paddingLeft?: UIValue | \"safe-left\" | \"comfort-left\";\n paddingTop?: UIValue | \"safe-top\" | \"comfort-top\";\n paddingRight?: UIValue | \"safe-right\" | \"comfort-right\";\n paddingBottom?: UIValue | \"safe-bottom\" | \"comfort-bottom\";\n padding?: UIValue | \"safe-all\" | \"comfort-all\";\n paddingHorizontal?: UIValue | \"comfort-x\";\n paddingVertical?: UIValue | \"comfort-y\";\n pl?: UIValue | \"safe-left\" | \"comfort-left\";\n pt?: UIValue | \"safe-top\" | \"comfort-top\";\n pr?: UIValue | \"safe-right\" | \"comfort-right\";\n pb?: UIValue | \"safe-bottom\" | \"comfort-bottom\";\n p?: UIValue | \"safe-all\" | \"comfort-all\";\n px?: UIValue | \"comfort-x\";\n py?: UIValue | \"comfort-y\";\n};\n/** Margin, with `m`/`mx`/`ml`… shorthands; `\"auto\"` centers/pushes like CSS. */\nexport type MarginStyle = {\n marginLeft?: UIValue | \"auto\" | \"safe-left\" | \"comfort-left\";\n marginTop?: UIValue | \"auto\" | \"safe-top\" | \"comfort-top\";\n marginRight?: UIValue | \"auto\" | \"safe-right\" | \"comfort-right\";\n marginBottom?: UIValue | \"auto\" | \"safe-bottom\" | \"comfort-bottom\";\n margin?: UIValue | \"auto\" | \"safe-all\" | \"comfort-all\";\n marginHorizontal?: UIValue | \"auto\" | \"comfort-x\";\n marginVertical?: UIValue | \"auto\" | \"comfort-y\";\n ml?: UIValue | \"auto\" | \"safe-left\" | \"comfort-left\";\n mt?: UIValue | \"auto\" | \"safe-top\" | \"comfort-top\";\n mr?: UIValue | \"auto\" | \"safe-right\" | \"comfort-right\";\n mb?: UIValue | \"auto\" | \"safe-bottom\" | \"comfort-bottom\";\n m?: UIValue | \"auto\" | \"safe-all\" | \"comfort-all\";\n mx?: UIValue | \"auto\" | \"comfort-x\";\n my?: UIValue | \"auto\" | \"comfort-y\";\n};\n/** Box position (for `position: \"absolute\"`) and size constraints. */\nexport type PositionStyle = {\n top?: UIValue | `${number}%` | 'safe-top' | 'comfort-top';\n left?: UIValue | `${number}%` | 'safe-left' | 'comfort-left';\n bottom?: UIValue | `${number}%` | 'safe-bottom' | 'comfort-bottom';\n right?: UIValue | `${number}%` | 'safe-right' | 'comfort-right';\n /** Shorthand for all four edges at one value. A longhand (`top`, `left`, …) overrides it. */\n inset?: UIValue | `${number}%` | \"auto\";\n width?: UIValue | `${number}%` | \"auto\";\n height?: UIValue | `${number}%` | \"auto\";\n maxWidth?: UIValue | `${number}%` | \"auto\";\n maxHeight?: UIValue | `${number}%` | \"auto\";\n minWidth?: UIValue | `${number}%` | \"auto\";\n minHeight?: UIValue | `${number}%` | \"auto\";\n};\n/** The base style of every element: box + flex-child props. */\nexport type ElementStyle = PaddingStyle & MarginStyle & BaseStyle & PositionStyle & {\n position?: \"absolute\" | \"static\" | \"relative\";\n aspectRatio?: number;\n flex?: number | string;\n flexGrow?: number;\n flexShrink?: number;\n flexBase?: UIValue | `${number}%` | \"auto\";\n alignSelf?: \"flex-start\" | \"center\" | \"flex-end\" | \"stretch\";\n display?: \"none\" | \"flex\";\n};\n/** Typography props. */\nexport type TextStyle = {\n textAlign?: \"start\" | \"center\" | \"end\" | \"left\" | \"right\";\n fontFamily?: string;\n fontSize?: UIValue;\n lineHeight?: UIValue | \"normal\";\n fontWeight?: number | `${number}` | \"normal\" | \"bold\";\n fontStyle?: \"normal\" | \"italic\";\n color?: Color;\n textDecoration?: \"underline\" | \"line-through\" | \"none\";\n letterSpacing?: UIValue;\n /** Cap the text at N lines; the box is measured to the clamped height. 0 / omitted = unbounded. */\n lineClamp?: number;\n /** How a clamped line ends. Only meaningful together with `lineClamp`. Default \"ellipsis\". */\n textOverflow?: \"ellipsis\" | \"clip\";\n};\n/** Reactive style input: every primitive-valued prop also accepts a `() => value` binding that\n * re-applies when a signal it read changes. Nested `$class` blocks stay static — bindings are\n * extracted at the top level only. */\nexport type Reactive<T> = {\n [K in keyof T]: NonNullable<T[K]> extends object ? T[K] : T[K] | (() => T[K]);\n};\n/** The curve of a `$class` block's swap (with a `duration`): a curve name (`outCubic`,\n * `inOutSine`, `smoothstep` — the default — …), `cubic-bezier(x1,y1,x2,y2)` or `steps(n)`. A\n * function cannot ride a style block; use `animateTo` for those. */\nexport type LayerEasing = string;\n/** Style states: any `$`-prefixed key in `.style()` declares a state block; `duration`/`delay`/\n * `easing` animate its swap. User classes (`$checked`, `$selected`, …) are toggled from code via the\n * `el.class` proxy and INHERIT down the tree (CSS-`.dark`-on-body style): a class set on a node also\n * activates same-name `$` blocks on all descendants within the same root (sdk/docs/ui/classes.md).\n *\n * Five classes are reserved — the system toggles them, `el.class` cannot:\n * - `$hovered` / `$pressed` / `$focused` — the host's hover (mouse only) / press / focus. They\n * cascade from the node the host toggled and STOP at the nearest interactive descendant (a\n * button inside a pressed card is not pressed; it has its own scope).\n * - `$landscape` / `$portrait` — the display orientation, GLOBAL: active on every node at once.\n *\n * Precedence on the same prop: base < `$landscape`/`$portrait` < user `$classes` (later-declared\n * beats earlier) < `$hovered` < `$pressed` < `$focused`.\n *\n * Instantiated with the node's FULL style `T` — a class block accepts everything the node's\n * `.style()` does. Narrowing it wrongly rejects valid props such as `$active: { color }`; guarded\n * by tests/ui/types.test.ts. */\nexport type ClassStyles<T> = {\n [key: `$${string}`]: T & {\n duration?: number;\n delay?: number;\n easing?: LayerEasing;\n };\n};\n/** Value accepted by a `el.class` write: a boolean sets the class, a `() => boolean` binds it —\n * the class then tracks the signals the function reads (re-evaluated on change). Reads through\n * the proxy always return a plain boolean, never the bound function. */\nexport type ClassValue = boolean | (() => boolean);\n/** The `el.class` proxy — the runtime switch for `$`-class blocks declared in `.style()`\n * (see {@link ClassStyles}). One surface, mirroring `el.style`:\n *\n * ```ts\n * el.class.checked // read: is it active on THIS element? → boolean\n * el.class.checked = true // activate (false deactivates)\n * el.class.open = !el.class.open // toggle\n * el.class.done = () => todo.done.value // reactive binding (signals)\n * el.class({ checked: true, done: () => … }) // batch form — returns the element, chainable\n * ```\n *\n * Class names are accepted with or without the declaration-site `$` prefix. A write of a reserved\n * class (`hovered` `pressed` `focused` `landscape` `portrait`) throws — the system toggles those.\n * `R` is the concrete node type, so the batch form chains like `.style()`.\n *\n * Typing note: property access is `any` because an index signature can't give reads (`boolean`)\n * and writes ({@link ClassValue}) different types — the batch form is the fully typed path;\n * single-key writes are runtime-coerced with `!!`. */\nexport type Classes<R> = ((classes: Record<string, ClassValue>) => R) & {\n [key: string]: any;\n};\n/** Members every UI element shares — element interfaces extend this so docs and types live in one\n * place. `S` is the element's style object; `A` is the subset `animateTo` accepts (defaults to `S`). */\nexport interface UIElementBase<S extends object, A extends object = S> {\n /** Style: `.style({...})` merges (chainable); `el.style.key = v` writes one prop, a `() => v`\n * value binds it to signals — see {@link Style}. */\n style: Style<this, S>;\n /** Author-given semantic name — a stable selector for tests and for marking elements in the AI\n * code-review feedback loop; surfaced in the renderer's serialized output. Set it with `.named()`\n * (chainable) or assign it. */\n name?: string;\n /** Set the semantic name (chainable). */\n named(name: string): this;\n /** Theme variables for THIS element's subtree (chainable): the same keys as the app-wide\n * `theme()`, read by everything under the element — and by the kit components there — before\n * the app's table. `null` takes a key out of the scope. Reaches the element's descendants in\n * the tree (a pager's pages and a list's items included); a screen pushed over it and a widget\n * are roots of their own. Re-calling restyles the live subtree.\n * ```ts\n * promo.theme({ accent: \"#FF3B30\" }) // one card in another accent\n * sheet.theme({ bg: \"#000\", text: \"#FFF\" }) // a dark screen in a light app\n * ``` */\n theme(values: ThemeRoles & Record<string, string | number | null>): this;\n /** Tween to the target style — meta keys `duration`/`delay`/`loop`/…, see {@link AnimateStyle}. */\n animateTo: AnimateStyle<this, A>;\n /** Tween from the given style to the current one (entrance animations). */\n animateFrom: AnimateStyle<this, A>;\n /** Fires after every layout pass with the parent-relative box. */\n onLayout(onLayout: OnLayoutCallback): this;\n /** Absolute rect in device space, read live (includes scroll); `null` before layout. */\n getBoundingClientRect(): BoundingClientRect | null;\n /** The parent element, or `null` for a root (a screen, a widget, an unmounted subtree's top). */\n readonly parent: UINode | null;\n /** Free this element's subtree now (views, layout, native state). Only for a DETACHED subtree —\n * remove / hide / close it first; an attached one is left alone. After it the element is dead. */\n destroy(): void;\n /** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with\n * `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.\n * Classes cascade to descendants. See {@link Classes}. */\n readonly class: Classes<this>;\n}\n/** {@link UIElementBase} plus the child-management surface every container shares. */\nexport interface UIContainerBase<S extends object, A extends object = S> extends UIElementBase<S, A> {\n /** Append children. */\n append(...nodes: UINodeChild[]): this;\n /** Insert children at `index`. */\n insert(index: number, ...nodes: UINodeChild[]): this;\n /** Remove (unmount) the given children. */\n remove(...nodes: UINodeChild[]): this;\n /** Replace all children — an array, or a function for reactive children. */\n setContent(nodes: UINodeChild[] | ChildrenFn): this;\n /** The children — a SNAPSHOT read from the runtime; mutate via `append`/`insert`/`remove`/`setContent`. */\n readonly children: UINode[];\n}\nexport type StyleFn<R, T extends object> = ((style: Reactive<T> & ClassStyles<T>) => R);\n/** The `el.style` surface: callable — `.style({...})` merges and returns the element for\n * chaining — and per-key readable/writable (`el.style.opacity = 0.5`; a `() => value` write\n * installs a reactive binding). Reads answer what the app set. */\nexport type Style<R, T extends object> = StyleFn<R, T> & T & ClassStyles<T>;\n/** Style props of an animate bag: a single value (tween from the current value) or an array of\n * KEYFRAMES (`opacity: [1, 0.3, 1]`, offsets via `times`). */\nexport type AnimateProps<T extends object> = {\n [K in keyof T]?: T[K] | T[K][];\n};\n/** The `animateTo`/`animateFrom` surface: target style props (single values or keyframe arrays) plus\n * the flat meta keys — `duration` / `delay` / `easing` / `times` / `loop` / `loopMode` / `commit` /\n * `clock`, see {@link TweenMeta}. Returns the {@link Animation} handle (seek, rate, `finished`). */\nexport type AnimateStyle<R, T extends object> = ((style: AnimateProps<T> & TweenMeta) => Animation);\nexport type AppearStyle<R, T> = (arg: {\n from: T;\n duration?: number;\n delay?: number;\n}) => R;\nexport type DisappearStyle<R, T> = (arg: {\n to: T;\n duration?: number;\n delay?: number;\n}) => R;\n/** `onLayout` payload — the node's box in PARENT-relative coordinates. */\nexport type OnLayoutCallback = (layout: {\n left: number;\n top: number;\n width: number;\n height: number;\n}) => void;\n/** Web-DOMRect shape on purpose (getBoundingClientRect priors must hold): all eight fields, with\n * right/bottom/x/y derived SDK-side — hosts only report [left, top, width, height]. */\nexport type BoundingClientRect = {\n x: number;\n y: number;\n left: number;\n top: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n};\nexport declare class Element<T extends string> implements TreeElement {\n readonly type: T;\n private _name?;\n protected _styleProxy: any;\n constructor(type: T, style: any);\n get name(): string | undefined;\n set name(value: string | undefined);\n named(name: string): this;\n theme(values: Record<string, string | number | null>): this;\n get style(): any;\n /** Tween to the target style and commit it (unless `commit: false` or looping — a loop is an\n * effect, not a state change). A prop value may be an array of keyframes; meta keys\n * `duration`/`delay`/`easing`/`times`/`loop`/… — see {@link AnimateStyle}. Returns the\n * {@link Animation} handle. */\n animateTo(style: any): Animation;\n /** Tween FROM the given style to the element's current one (entrance animations): the element's\n * own style is the implicit last keyframe. Never modifies the stored style. */\n animateFrom(style: any): Animation;\n protected _classProxy?: any;\n /** Style-class control — flips the `$`-class blocks declared in `.style()`. One proxy, same\n * contract as `el.style`:\n *\n * - `el.class.checked` — read: is the class active on THIS element? → `boolean`\n * - `el.class.checked = true` / `= false` — activate / deactivate\n * - `el.class.open = !el.class.open` — toggle\n * - `el.class.done = () => todo.done.value` — reactive: the class tracks the signals the\n * function reads; a later write to the same class (plain or function) replaces the binding\n * - `el.class({ checked: true, done: () => … })` — batch form, returns the element (chainable)\n *\n * Names are accepted with or without the leading `$`. A class set on an element CASCADES: it is\n * also active on every descendant (their same-name `$` blocks light up), until the subtree's\n * root — hosted screens/widgets don't inherit. Reads reflect only this element's own classes;\n * there is no opt-out below an active ancestor. `Object.keys(el.class)` lists the active names.\n * The reserved classes (`$hovered` `$pressed` `$focused` `$landscape` `$portrait`) are the\n * system's: writing one throws. */\n get class(): any;\n protected ll?: OnLayoutCallback[];\n /** Observe layout: fires after every host layout pass with the parent-relative box. */\n onLayout(onLayout: OnLayoutCallback): this;\n /** Absolute rect in device space — the space `UIWidget` positions in and touch events report\n * `clientX`/`clientY` in — including scroll offsets, read live at call time (unlike `onLayout`,\n * whose coordinates are parent-relative and go stale when an ancestor scrolls). `null` before\n * the element is laid out and on hosts without the read. Anchor popovers position-once\n * at open; don't poll per frame. */\n getBoundingClientRect(): BoundingClientRect | null;\n /** The parent element, or `null`. Resolves while the parent is itself attached (mounted under a\n * presented / router-held screen, a shown widget, a pager page …); a loose subtree's root is\n * held only by its handle and is not findable from its children. */\n get parent(): any;\n destroy(): void;\n}\n/** Reactive children: re-runs when a signal it read changes; the result is reconciled against\n * the mounted children (kept nodes stay mounted, state intact). */\nexport type ChildrenFn = () => UINodeChild[];\n/**\n * Compiler-emitted memoized map for reactive children. The chisel `reactiveUi` pass rewrites\n * `list.map(fn)` inside a children binding to `__uiMap(list, fn, \"<file>:<offset>\")`, so unchanged\n * items keep their element identity across re-runs (the reconciler then leaves them mounted).\n * Cache: per (binding owner, call-site slot), keyed by item reference; duplicate items consume\n * cached nodes in order. Outside a children binding, for non-array inputs, or for non-element\n * results it behaves exactly like Array.prototype.map — a wrong rewrite can't change behavior.\n */\nexport declare function __uiMap(list: any, render: (item: any, index: number) => any, slot: string): any[];\nexport declare class ContainerElement<T extends string> extends Element<T> {\n constructor(type: T, style: any, children: any[] | ChildrenFn);\n /** The children — a snapshot read from the runtime (falsy entries were never mounted). */\n get children(): any[];\n private _insertAt;\n /** Append children (falsy entries are skipped). */\n append(...nodes: UINodeChild[]): this;\n /** Insert children at `index`. */\n insert(index: number, ...nodes: UINodeChild[]): this;\n /** Remove (unmount) the given children. The removed subtrees stay valid (re-appendable) as long\n * as you hold them; dropped ones are freed. */\n remove(...nodesToDelete: UINodeChild[]): this;\n /** Replace all children — a plain array, or a function for reactive children. */\n setContent(children: UINodeChild[] | ChildrenFn): this;\n}\nexport {};\n","types/ui/UIPager.d.ts":"import { ContainerElement, type BaseStyle, type ChildrenFn, type DrawableStyle, type ElementStyle, type UIElementBase, type UINodeChild } from \"./UINode\";\nimport type { UIScreen } from \"./UIScreen\";\nimport type { NavigateOptions, PopOptions } from \"./router\";\n/** Styles a pager accepts — layout box + drawable (background, borders, …). Pages style\n * themselves; the pager only owns its own slot. */\nexport type UIPagerStyle = ElementStyle & DrawableStyle;\n/**\n * The screen-navigation element: sibling **tabs** that swipe natively side to side, each with its\n * own navigation **stack**. `push` opens a screen on top of the current tab (within the pager);\n * `pop` / the native edge back-swipe unwinds it. A one-tab pager is a plain navigation stack.\n *\n * ```ts\n * const pager = UIPager([ HomeScreen(), ProfileScreen() ]) // two tabs, side by side\n * Router.init(UIScreen([ pager.style({ flexGrow: 1 }), tabBar ]))\n *\n * // from anywhere inside a hosted screen — no reference threading:\n * UIPager.push(PostScreen(id))\n * ```\n *\n * To open something over *everything* (above bars, above the pager), use `Router.push` instead.\n */\nexport interface UIPager extends UIElementBase<UIPagerStyle, DrawableStyle & BaseStyle> {\n readonly type: \"pager\";\n /** Replace the pager's tabs — one screen per tab, in order. Every tab becomes a fresh\n * one-screen stack (pushed screens are dropped) and the selection is clamped into range;\n * screens that were already tabs keep their state. Pass a function for reactive tabs. */\n setContent(tabs: UIScreen[] | (() => UIScreen[])): this;\n /** Switch to tab `index`. **Instant by default** — the tab-bar convention (tabs are parallel\n * modes, not neighbors); pass `animated: true` for the direction-aware slide of top-tab /\n * pager UIs. Out-of-range and same-index calls are no-ops. Tabs keep their stacks: selecting\n * away and back restores the tab exactly where it was, pushed screens included. */\n select(index: number, animated?: boolean): this;\n /** The selected tab index (0-based). */\n readonly index: number;\n /** Fires when the selected tab changes and has settled — a user swipe or `select()`. */\n onSelect(callback: (index: number) => void): this;\n /** Push `screen` on top of the **current tab**; the edge back-swipe (or `pop()`) removes it.\n * Other tabs are unaffected. Transitions as in `Router.push`: `\"push\"` unless one is named, and\n * the screen remembers its way back (`popTransition`, or the mirror of the way it came). */\n push(screen: UIScreen, opts?: NavigateOptions): this;\n /** Pop the current tab's top screen (no-op at the tab root — the root never pops). The\n * programmatic twin of the native edge back-swipe. Plays the way back the screen remembers\n * unless a transition is named. */\n pop(opts?: PopOptions): this;\n /** Unwind the current tab back to its root screen in one step: the top screen leaves with its\n * way back (or the named transition), the ones between are never shown. */\n popToRoot(opts?: PopOptions): this;\n /** Swap the current tab's top screen for `screen` without growing the stack (at depth 1 this\n * swaps the tab's root). `\"fade\"` unless a transition is named; the way back stays the one of\n * the place in the stack unless `popTransition` names another. */\n replace(screen: UIScreen, opts?: NavigateOptions): this;\n /** The current tab's screens, root → top (read-only snapshot). */\n readonly stack: UIScreen[];\n /** The current tab's stack depth — 1 means only the root. While `depth > 1`, swiping between\n * tabs is disabled (the horizontal gesture belongs to the back-swipe). */\n readonly depth: number;\n /** Fires when the current tab's depth changes — push, pop, replace, or a back-swipe. */\n onChange(callback: (depth: number) => void): this;\n /** The pages, tab-major (every tab's stack root → top). */\n readonly children: UIScreen[];\n}\nexport declare class PagerElement extends ContainerElement<\"pager\"> {\n _openCount: number;\n private scl;\n private ncl;\n constructor(style: UIPagerStyle | null, tabs: UIScreen[]);\n /** Start offset of tab `i`'s segment in the flat `_pages`. */\n private _offset;\n /** Push the whole picture to the runtime. */\n private _sync;\n get children(): any[];\n get index(): number;\n get stack(): UIScreen[];\n get depth(): number;\n onSelect(callback: (index: number) => void): this;\n onChange(callback: (depth: number) => void): this;\n select(index: number, animated?: boolean): this;\n push(screen: UIScreen, opts?: NavigateOptions): this;\n pop(opts?: PopOptions): this;\n popToRoot(opts?: PopOptions): this;\n replace(screen: UIScreen, opts?: NavigateOptions): this;\n private _rebuild;\n setContent(children: UINodeChild[] | ChildrenFn): this;\n append(...nodes: UINodeChild[]): this;\n insert(index: number, ...nodes: UINodeChild[]): this;\n remove(...nodesToDelete: UINodeChild[]): this;\n _reconcile(next: UINodeChild[]): void;\n private _emitSelect;\n private _emitChange;\n private _track;\n _activate(): void;\n _deactivate(): void;\n}\n/** Callable factory + ambient statics. The name `UIPager` is a value (this factory) and a type\n * (the instance interface above) — a standard value/type merge. */\ninterface UIPagerConstructor {\n /** Tabs — each argument is a screen or an array of screens (arrays flatten one level, falsy\n * entries are skipped). One screen → a plain navigation stack rooted at it (push/pop, no tab\n * swiping); several → swipeable sibling tabs, fixed at construction, each starting as its own\n * one-screen stack. */\n (...tabs: (UIScreen | UIScreen[] | false | null | undefined)[]): UIPager;\n /** The pager that owns the currently visible screen, or `null` when the visible screen isn't\n * hosted by one. With pagers nested inside pages, resolves to the **innermost** — so ambient\n * calls act on the pager the user is actually looking at. */\n readonly current: UIPager | null;\n /** `UIPager.current.push(screen)` — push onto the pager owning the visible screen, no\n * reference threading. No-op with a console warning when there is no current pager. */\n push(screen: UIScreen, opts?: NavigateOptions): void;\n /** `UIPager.current.pop()` — pop the visible pager's current tab (no-op at the tab root, or\n * with a warning when there is no current pager). */\n pop(opts?: PopOptions): void;\n /** `UIPager.current.popToRoot()` — unwind the visible pager's current tab to its root. */\n popToRoot(opts?: PopOptions): void;\n}\n/**\n * Create a pager — THE screen-navigation element: an array of screens becomes swipeable sibling\n * tabs, a single screen becomes a plain stack. Navigate within it via `pager.push/pop/replace`\n * (per-tab) and `pager.select(i)` (between tabs), or from any child screen via the ambient\n * `UIPager.push` / `UIPager.pop` / `UIPager.current`. Pages are full `UIScreen`s (own\n * `onOpen`/`onClose`); give the pager `flexGrow: 1` or a size so it doesn't\n * collapse. `Router` stays the way to open a destination ON TOP of the pager.\n */\nexport declare const UIPager: UIPagerConstructor;\nexport {};\n","types/ui/UIPopover.d.ts":"import { ModalElement, type UIModal, type UIModalStyle } from \"./UIModal\";\nimport { type BoundingClientRect, type ChildrenFn, type UIChildArg, type UINodeChild } from \"./UINode\";\nexport type UIPopoverStyle = UIModalStyle;\n/** What a popover can anchor to: any element (it reads `getBoundingClientRect()`), or a raw\n * `{x, y}` point — a long-press context menu anchors to the touch position. */\nexport type UIPopoverAnchor = {\n getBoundingClientRect(): BoundingClientRect | null;\n} | {\n x: number;\n y: number;\n};\n/**\n * An anchored menu: a `UIModal` whose scrim is transparent (invisible but still intercepting —\n * an outside tap dismisses, and nothing underneath can scroll while it's open) and whose\n * position comes from the anchor passed to `show(anchor)`: below the anchor's left edge,\n * flipped above when there's no room, clamped into the viewport. Position is computed once per\n * show — anchored popovers don't follow their anchor. Backs dropdowns, context menus, and\n * tooltips; create it **once** at module scope and reuse it.\n */\nexport interface UIPopover extends UIModal {\n /** Position next to `anchor` (an element or an `{x, y}` point), put the popover where the\n * anchor is — the anchor's screen, page or surface content, found through the tree, so the\n * menu lands where it was opened and goes with it — and play the entrance transition. A\n * popover with no anchor and no parent goes to the app layer; without an anchor it shows\n * wherever its own style puts it. */\n show(anchor?: UIPopoverAnchor): void;\n}\nexport declare class PopoverElement extends ModalElement {\n private _anchorRect?;\n private _placedLeft?;\n private _placedTop?;\n constructor(style: UIPopoverStyle, children: UINodeChild[] | ChildrenFn);\n show(anchor?: UIPopoverAnchor): void;\n private _place;\n}\n/** Create an anchored popover (see {@link UIPopover}) — create once at module scope, then\n * `show(anchor)` next to an element or `{x, y}` point. Same argument forms as `UIColumn`. */\nexport declare function UIPopover(...children: UIChildArg[]): UIPopover;\nexport declare function UIPopover(children: UINodeChild[] | ChildrenFn): UIPopover;\n","types/ui/UIScreen.d.ts":"import { TouchStartEvent } from \"../runtime/touch\";\nimport { type DismissOptions, type PresentOptions } from \"./presentable\";\nimport { ContainerElement, type BaseStyle, type ContainerStyle, type DrawableStyle, type PaddingStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn } from \"./UINode\";\nexport type UIScreenStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle;\n/** A screen — the root the router/host mounts, sized to its slot. A screen NEVER scrolls: it is\n * fixed chrome (header, tab bar) plus, when the content overflows, one `UIScrollable` body child\n * (`flexGrow: 1`). Scroll events and pull-to-refresh live on the scroll containers\n * (`UIScrollable`, `UIVirtualizedList`). */\nexport interface UIScreen extends UIContainerBase<UIScreenStyle, DrawableStyle & BaseStyle> {\n readonly type: \"screen\";\n /** Show this screen as the current destination (replaces whatever is visible — a screen, a\n * scene, a native view — suspending an active Router until `Router.restore()`). */\n open(options?: PresentOptions): void;\n /** Dismiss if this screen is the visible destination. */\n close(options?: DismissOptions): void;\n /** Hardware/system back while this screen is current. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n /** The screen became the visible destination (first open, or revealed by a pop). */\n onOpen(callback: () => void): this;\n /** The screen stopped being visible — closed, replaced, or covered by a push. */\n onClose(callback: () => void): this;\n /**\n * Keep this screen's native state when a pager releases it: instead of dropping its view, the\n * host keeps it (scroll position, input text), so re-pushing the SAME screen object restores it\n * in place. `onClose`/`onOpen` still fire on detach/re-attach. Free it with `destroy()`.\n */\n keepAlive(enabled?: boolean): this;\n /**\n * The screen's ADDRESS on the web: while the screen is the one shown, the browser's address\n * bar shows it, and a link copied from there opens the app with it (`app.launchUrl`). A route,\n * not a page's address: `\"/product/42\"`, `\"/search?q=shoes\"` — the app never sees where the\n * page is served from. Call it again to change the address of a screen that is shown (a\n * filter, a search): the entry of the browser's history is replaced, not added to. `null`\n * takes the address away; a screen with none keeps the address of the one under it.\n *\n * The way in is the app's: read `app.launchUrl` at start and listen to the `\"url\"` event, as\n * for a deep link on a phone. No-op on hosts without an address bar.\n *\n * ```ts\n * const ProductScreen = (id: string) => UIScreen(...).url(`/product/${id}`)\n * ```\n */\n url(route: string | null): this;\n /** Touch began on the screen; `ev.track(...)` takes over the rest of the gesture. */\n onTouchStart(callback: (ev: TouchStartEvent<UIScreen>) => void): this;\n}\nexport declare class ScreenElement extends ContainerElement<\"screen\"> {\n constructor(type: \"screen\", style: any, children: any);\n open(options?: PresentOptions): void;\n close(options?: DismissOptions): void;\n protected ol: (() => void)[];\n onOpen(callback: () => void): this;\n protected cl: (() => void)[];\n onClose(callback: () => void): this;\n keepAlive(enabled?: boolean): this;\n url(route: string | null): this;\n readonly touchStartListeners: any[];\n onTouchStart(callback: any): this;\n private _backButtonCallback?;\n onBack(callback: any): this;\n /** @deprecated see the interface */\n onBackPressed(callback: any): this;\n}\n/** Create a screen. Present it with `.open()`, or via `Router` / `UIPager`. Same argument forms\n * as `UIColumn`. */\nexport declare function UIScreen(...children: UIChildArg[]): UIScreen;\nexport declare function UIScreen(children: UINodeChild[] | ChildrenFn): UIScreen;\n","types/ui/UIScrollable.d.ts":"import type { UIContainerStyle } from \"./UIContainer\";\nimport { type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn, type Color } from \"./UINode\";\nexport type ScrollStyle = {\n showScrollbar?: boolean;\n overscrollMode?: \"none\" | \"absorb\" | \"default\";\n /** Tint of the native pull-to-refresh spinner (pairs with `onRefresh`). */\n refreshControlColor?: Color;\n /** How a scroll gesture in THIS scrollable dismisses the keyboard: `\"interactive\"` (default) —\n * dragging over the keyboard slides it away (chat feel); `\"scroll\"` — any drag dismisses\n * immediately; `\"none\"` — never (tap-outside policy still applies). */\n keyboardDismissMode?: \"interactive\" | \"scroll\" | \"none\";\n /** Paging: when the drag ends, rest on a direct child's boundary along the scroll axis — the\n * value picks where the child sits in the viewport; `\"none\"` (default) is free scrolling. Snap\n * targets are the children themselves, so item widths can differ (card-carousel-with-peek); a\n * carousel is a horizontal scrollable of full-width children + `snap: \"start\"`. */\n snap?: \"none\" | \"start\" | \"center\" | \"end\";\n};\nexport type UIScrollableStyle = UIContainerStyle & ScrollStyle & {\n scrollDirection?: \"horizontal\" | \"vertical\";\n};\n/** A scroll container — vertical by default, `scrollDirection: \"horizontal\"` for carousels/chip\n * rows. The scrolling body of a screen (screens themselves never scroll). */\nexport interface UIScrollable extends UIContainerBase<UIScrollableStyle> {\n readonly type: \"scrollable\";\n /** Scroll position changed (px from the start edge). */\n onScroll(callback: (scrollPosition: number) => void): UIScrollable;\n /** The scroll gesture ended (finger lifted). */\n onScrollRelease(callback: () => void): UIScrollable;\n /** Pulled past the content edge by `delta` px. */\n onOverscroll(callback: (delta: number) => void): UIScrollable;\n /** Pull-to-refresh: the spinner stays until the returned promise settles. Vertical only. */\n onRefresh(callback: () => void | Promise<void>): UIScrollable;\n}\n/** Create a scroll container (same argument forms as `UIColumn`). As a screen body, pair with\n * `flexGrow: 1`. */\nexport declare function UIScrollable(...children: UIChildArg[]): UIScrollable;\nexport declare function UIScrollable(children: UINodeChild[] | ChildrenFn): UIScrollable;\n","types/ui/UISpacer.d.ts":"import { type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UISpacerStyle = ElementStyle;\n/** A flexible gap — `flexGrow: 1` by default, pushes its siblings apart. */\nexport interface UISpacer extends UIElementBase<UISpacerStyle> {\n readonly type: \"spacer\";\n}\n/** Create a flexible gap (`flexGrow: 1`) — e.g. between a header's title and its actions. */\nexport declare function UISpacer(): UISpacer;\nexport declare function UISpacer(style: UISpacerStyle): UISpacer;\n","types/ui/UITabs.d.ts":"import { type UIPager } from \"./UIPager\";\nimport { ScreenElement, UIScreen } from \"./UIScreen\";\nimport { type UIRow as UIRowType } from \"./UIContainer\";\nimport { type ImageSource } from \"./UIImage\";\nimport type { UIChildArg } from \"./UINode\";\nexport type UITabDef = {\n label: string;\n /** Tab icon — typically `assetIcon(\"lucide:…\")`. Tinted active/inactive by the bar. */\n icon?: ImageSource;\n /** The tab's root screen. Tabs are fixed at construction (like UIPager's). */\n screen: UIScreen;\n};\n/**\n * A bottom-tab app shell: swipeable tabs (a `UIPager`) plus a themed tab bar, as one\n * `UIScreen` — present it directly (`Router.init(tabs)`). Keys are tab ids, in tab order:\n *\n * ```ts\n * const tabs = UITabs({\n * home: { label: \"Home\", icon: assetIcon(\"lucide:house\"), screen: homeScreen },\n * profile: { label: \"Profile\", icon: assetIcon(\"lucide:user\"), screen: profileScreen },\n * })\n * Router.init(tabs)\n * ```\n *\n * In-tab navigation stays the pager's: `UIPager.push(detail)` from any screen (bar stays);\n * `Router.push` opens above the shell (bar covered). The bar is colored by the theme's roles\n * (`accent`, `textMuted`, `surface`, `border`); `tabs.bar.theme({...})` overrides them for this\n * bar alone, the `bar` handle restyles its box; for a fully custom bar build on `UIPager`.\n */\nexport interface UITabs extends UIScreen {\n /** The active tab id. */\n readonly tab: string;\n /** Switch tabs (instant, the tab-bar convention; `animated: true` slides). */\n select(id: string, animated?: boolean): this;\n /** Fires when the active tab changes and has settled — a bar tap, swipe, or `select()`. */\n onSelect(callback: (id: string, index: number) => void): this;\n /** Show a badge on a tab: `true` = dot, a number/string = count pill, `false`/`null`/`0` clears. */\n badge(id: string, value: number | string | boolean | null): this;\n /** The pager under the bar — in-tab stacks (`push`/`pop`/`depth`). */\n readonly pager: UIPager;\n /** The bar row (named \"tabbar\") — `bar.theme({ accent, textMuted, surface, border })` for this\n * bar's own colors, `bar.style({...})` for its box. */\n readonly bar: UIRowType;\n}\nexport declare class TabsElement extends ScreenElement {\n private readonly ids;\n private readonly _pagerEl;\n private readonly _bar;\n private readonly _icons;\n private readonly _labels;\n private readonly _badges;\n private readonly _badgeTexts;\n private readonly _buttons;\n private readonly _selectListeners;\n constructor(defs: Record<string, UITabDef>);\n private _applyActive;\n get tab(): string;\n get pager(): any;\n get bar(): any;\n select(id: string, animated?: boolean): this;\n onSelect(callback: (id: string, index: number) => void): this;\n badge(id: string, value: number | string | boolean | null | undefined): this;\n}\n/** Create the standard bottom-tab shell — see {@link UITabs}. Keys are tab ids in tab order;\n * each tab needs a `label` and its root `screen` (plus an optional `icon`). */\nexport declare function UITabs(tabs: Record<string, UITabDef>): UITabs;\n/** A `defineTabs` tab: `label` + optional `icon` (an `assetIcon(\"lucide:…\")` call — never a\n * hand-written source object). `UITabDef` is this plus the tab's root `screen`. */\nexport type TabDef = Omit<UITabDef, \"screen\">;\n/** What `defineTabs` returns: the bar (mount it yourself when the screen owns its whole layout)\n * and the standard screen shell around it. `active` must be a declared tab id, as a literal. */\nexport type TabsHandle<T extends Record<string, TabDef>> = {\n /** Tab ids in declaration order. */\n ids: (keyof T & string)[];\n /** The bar alone — one button per tab, the `active` one highlighted. */\n bar(active: keyof T & string): UIRowType;\n /** A screen sitting ON the bar: `[ padded content column, bar ]`. */\n screen(active: keyof T & string, ...children: UIChildArg[]): UIScreen;\n};\n/**\n * Declare a tab bar WITHOUT screens — the design-stage twin of {@link UITabs} (same keys, same\n * `tab-<id>` button names, same theme variables), for mockups where every screen is its own file\n * and mounts the bar with a literal tab id:\n *\n * ```ts\n * export const mainTabs = defineTabs({\n * home: { label: \"Home\", icon: assetIcon(\"lucide:house\") },\n * profile: { label: \"Profile\", icon: assetIcon(\"lucide:user\") },\n * })\n * // in a screen file:\n * export default () => mainTabs.screen(\"home\", [ ...content ])\n * ```\n *\n * The bar reads the theme's roles (`accent`, `textMuted`, `surface`, `border`), the screen its\n * `bg` — one `theme({...})` colors every bar at once. The built app passes the same keys (plus\n * each tab's root screen) to `UITabs`, which renders the identical bar interactively.\n */\nexport declare function defineTabs<T extends Record<string, TabDef>>(tabs: T): TabsHandle<T>;\n","types/ui/UIText.d.ts":"import { Element, type BaseStyle, type DrawableStyle, type ElementStyle, type TextStyle, type UIElementBase } from \"./UINode\";\nexport type UITextStyle = ElementStyle & TextStyle & DrawableStyle;\n/** A text label. */\nexport interface UIText extends UIElementBase<UITextStyle, DrawableStyle & BaseStyle & TextStyle> {\n readonly type: \"text\";\n /** The displayed string — writable at any time. */\n text: string;\n}\nexport declare class TextElement extends Element<\"text\"> {\n private _text;\n constructor(style: any, text: string | (() => string));\n get text(): string;\n set text(value: string);\n}\n/** Create a text label — a string, or `() => string` for reactive text that re-renders when a\n * signal it read changes. */\nexport declare function UIText(text: string | (() => string)): UIText;\n","types/ui/UIVideo.d.ts":"import type { VideoPlayer } from \"../runtime/media\";\nimport { type UIWidgetContent } from \"./UILayer\";\nimport { type DismissOptions, type PresentOptions } from \"./presentable\";\nimport { type BaseStyle, type DrawableStyle, type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UIVideoStyle = ElementStyle & DrawableStyle & {\n objectFit?: \"cover\" | \"contain\" | \"fill\";\n};\n/** A video surface showing a `VideoPlayer`'s output — embeddable in a screen AND\n * fullscreen-presentable (`open()`), with seamless promotion between the two. */\nexport interface UIVideo extends UIElementBase<UIVideoStyle, DrawableStyle & BaseStyle> {\n readonly type: \"video\";\n /** The player driving this surface (playback control lives on it). */\n player: VideoPlayer;\n /** Show fullscreen as the current destination. Promotion: if this video is mounted in a screen,\n * the SAME native player moves fullscreen — playback uninterrupted; a pop moves it back. */\n open(options?: PresentOptions): void;\n /** Dismiss if this is the visible destination. */\n close(options?: DismissOptions): void;\n /** Became the visible destination. */\n onOpen(callback: () => void): this;\n /** Stopped being the visible destination. */\n onClose(callback: () => void): this;\n /** Hardware/system back while current. */\n onBack(callback: () => void): this;\n /** The UI over the video when presented: widgets over it (`Presentable.setContent`). */\n setContent(content: UIWidgetContent): this;\n}\n/** Create a video node showing `player`'s output. */\nexport declare function UIVideo(player: VideoPlayer): UIVideo;\n","types/ui/UIVirtualizedList.d.ts":"import { Element, type Color, type DrawableStyle, type ElementStyle, type UIElementBase, type UINodeChild } from \"./UINode\";\nexport type UIVirtualizedListStyle = DrawableStyle & ElementStyle & {\n /** Tint of the native pull-to-refresh spinner (pairs with `onRefresh`). */\n refreshControlColor?: Color;\n /** Same key and semantics as UIScrollable's; `\"none\"` keeps a chat composer's keyboard up no\n * matter how the history is scrolled. */\n keyboardDismissMode?: \"interactive\" | \"scroll\" | \"none\";\n};\nexport interface VListConfig<T> {\n /** Stable unique key of an item. */\n keyOf: (item: T) => string;\n /** Subtree factory — called when the item enters the window; the subtree lives until it\n * leaves. */\n render: (item: T) => UINodeChild;\n /** Height estimate (px) used before the first measurement — a number, or a per-item function\n * (chat: `msg => 40 + Math.ceil(msg.text.length / 35) * 20`). Computed once when the item is\n * added. */\n estimatedHeight: number | ((item: T) => number);\n /** Extra px around the viewport kept mounted. Default: one viewport height. */\n overscan?: number;\n /** Chat mode: the first layout starts scrolled to the end, and appends auto-scroll while the\n * list sits at the bottom. */\n inverted?: boolean;\n}\n/** A windowed (virtualized) list: only the items near the viewport are mounted — for long feeds\n * and chats. Items are keyed; feed it via `setData`/`append`/`prepend`. */\nexport interface UIVirtualizedList<T = unknown> extends UIElementBase<UIVirtualizedListStyle> {\n readonly type: \"vlist\";\n /** Replace the data wholesale — vanished keys are unmounted by the window sync. */\n setData(items: T[]): this;\n /** Append items to the end (auto-scrolls when `inverted` and resting at the bottom). */\n append(...items: T[]): this;\n /** Insert at the start WITHOUT a scroll jump (the runtime compensates the offset). */\n prepend(...items: T[]): this;\n /** Update items with the same keys: mounted ones re-render; the cached height persists until\n * re-measured. */\n update(...items: T[]): this;\n /** Remove items by key. */\n removeByKey(...keys: string[]): this;\n /** Number of data items (mounted or not). */\n readonly itemCount: number;\n /** The data item under `key`, if any. */\n getItem(key: string): T | undefined;\n /** Scroll to `offset` px. */\n scrollTo(offset: number, animated?: boolean): void;\n /** Scroll to the item with `key`. */\n scrollToKey(key: string, animated?: boolean): void;\n /** Scroll to the end of the content. */\n scrollToEnd(animated?: boolean): void;\n /** Scroll position changed (px from the start edge). */\n onScroll(callback: (scrollPosition: number) => void): this;\n /** Pull-to-refresh: the spinner stays until the returned promise settles. */\n onRefresh(callback: () => void | Promise<void>): this;\n /** Fires within `thresholdPx` of the content's bottom edge — once, re-armed after leaving the\n * edge (a runtime-side latch). Infinite-scroll loading. */\n onEndReached(thresholdPx: number, callback: () => void): this;\n /** Same, for the top edge — chat history loading. */\n onStartReached(thresholdPx: number, callback: () => void): this;\n}\nexport declare class VListElement<T> extends Element<\"vlist\"> implements UIVirtualizedList<T> {\n private readonly sl;\n private readonly erl;\n private readonly strl;\n private _refreshCallback?;\n private items;\n private mounted;\n private keyOf;\n private renderItem;\n private estimate;\n private readonly _overscan;\n private readonly _inverted;\n private _endThreshold;\n private _startThreshold;\n private _inited;\n constructor(config: VListConfig<T>);\n private _ensure;\n private register;\n setData(items: T[]): this;\n append(...items: T[]): this;\n prepend(...items: T[]): this;\n update(...items: T[]): this;\n removeByKey(...keys: string[]): this;\n get itemCount(): number;\n getItem(key: string): T | undefined;\n scrollTo(offset: number, animated?: boolean): void;\n scrollToKey(key: string, animated?: boolean): void;\n scrollToEnd(animated?: boolean): void;\n onScroll(callback: (scrollPosition: number) => void): this;\n onRefresh(callback: () => void | Promise<void>): this;\n onEndReached(thresholdPx: number, callback: () => void): this;\n onStartReached(thresholdPx: number, callback: () => void): this;\n}\n/** Create a virtualized list from a config (`keyOf` + `render` + `estimatedHeight` required),\n * then feed it via `setData`/`append`/`prepend`. Give it a size (`flexGrow: 1` as a screen body). */\nexport declare function UIVirtualizedList<T>(config: VListConfig<T>): UIVirtualizedList<T>;\n","types/ui/UIWidget.d.ts":"import { TouchStartEvent } from \"../runtime/touch\";\nimport { ContainerElement, type BaseStyle, type Color, type ContainerStyle, type DrawableStyle, type PaddingStyle, type PositionStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn } from \"./UINode\";\nexport type UIWidgetStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle & PositionStyle & {\n /** Shown (`\"flex\"`, the default) or not: what `show()` / `hide()` write, what a state block may\n * flip (`$open: { display: \"flex\" }`). */\n display?: \"none\" | \"flex\";\n /** A layer behind the widget that intercepts clicks — `\"transparent\"` still intercepts, `null`\n * removes the layer. A tap on it fires `onOverlayTap`. */\n overlayColor?: Color | null;\n};\n/** A floating overlay that belongs to a WINDOW, not to a box (docs/plans/widgets-plan.md): a dialog,\n * a sheet, a HUD, a mini-player. A widget is a CHILD of the place it belongs to — a `UIScreen`\n * (among its children), a surface's content (`scene.setContent([hud])`) or the app layer\n * (`UIOverlay`) — and is laid out and painted in the box of the outermost presented destination\n * that contains it: absolutely positioned in that box, above everything else in it. A widget on a\n * tab page covers the tab bar and rides the shell's push and pop. A widget inside a `UIColumn` or\n * any other box is an error: a floating element of a box is an absolute child, not a widget.\n *\n * It shows with its place unless its style says `display: \"none\"`; `show()` / `hide()` flip that,\n * and so does a state block (`$class: { display: \"flex\" }`). `UIModal` / `UIPopover` /\n * `UIBottomSheet` build on it. */\nexport interface UIWidget extends UIContainerBase<UIWidgetStyle, DrawableStyle & BaseStyle & {\n overlayColor?: Color | null;\n}> {\n readonly type: \"widget\";\n /** Show the widget: `display: \"flex\"`, on top of its root — it moves to the end of its parent's\n * children, so a dialog opened later covers an earlier one and a HUD declared after it. A widget\n * with no parent is appended to the app layer first (`UIOverlay`) — a global overlay above every\n * destination, up until `hide()`. */\n show(): void;\n /** Hide the widget: `display: \"none\"`. It stays where it is (its place, the app layer), ready\n * for the next `show()`. */\n hide(): void;\n /** Shown right now by its own display (`show()` ran, `hide()` hasn't, no state block hides\n * it). True for a widget hidden WITH its page or its covered screen: that is its place's\n * visibility, not the widget's. */\n readonly isShown: boolean;\n /** Touch began on the widget; `ev.track(...)` takes over the rest of the gesture. */\n onTouchStart(callback: (ev: TouchStartEvent<UIWidget>) => void): this;\n /** Tap on the overlay layer (requires an `overlayColor`). */\n onOverlayTap(callback: () => void): this;\n /** Hardware/system back while the widget is shown. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n}\nexport declare class WidgetElement extends ContainerElement<\"widget\"> {\n scrollable: false;\n constructor(type: \"widget\", style: UIWidgetStyle, children: UINodeChild[] | ChildrenFn);\n show(): void;\n hide(): void;\n get isShown(): boolean;\n readonly touchStartListeners: any[];\n onTouchStart(callback: any): this;\n readonly otl: (() => void)[];\n onOverlayTap(callback: () => void): this;\n private _backButtonCallback?;\n onBack(callback: any): this;\n /** @deprecated see the interface */\n onBackPressed(callback: any): this;\n}\n/** Create a widget (same argument forms as `UIColumn`). Put it where it belongs — among a screen's\n * children, in `scene.setContent([...])`, or `UIOverlay` — position it with absolute-style props\n * (`top`/`left`/`bottom`/`right`), then `show()`/`hide()`. */\nexport declare function UIWidget(...children: UIChildArg[]): UIWidget;\nexport declare function UIWidget(children: UINodeChild[] | ChildrenFn): UIWidget;\n","types/version.d.ts":"export declare const SDK_VERSION = \"2.0.9\";\n/** The major of a semver string, or null when it is not one. */\nexport declare const sdkMajor: (version: string | null | undefined) => number | null;\n/** The `// sdk: <version>` line of a compiled bundle's header (sdk/src/compile/header.ts), read from\n * its first bytes; null for a bundle compiled before the line existed (SDK 0.x / 1.x — the\n * pre-tree contract, which no 2.x host runs). */\nexport declare const bundleSdkVersion: (head: string) => string | null;\n/** Whether a host embedding `hostVersion` can run a bundle whose header carries `bundleVersion`\n * (null = no line = pre-2.0 contract): the majors must match. */\nexport declare const bundleRunsOn: (bundleVersion: string | null, hostVersion: string) => boolean;\n"}
|
|
1
|
+
{"global.d.ts":"// AUTO-GENERATED by build-types.ts. The import-free type surface for le.codes projects:\n// every SDK global declared ambiently, so user code uses Scene / Sprite / UIScreen / … \n// with no imports and full editor autocomplete.\n\nimport type * as SDK from \"./types/inject\"\nimport type * as SERVER from \"./types/server/inject\"\n\ndeclare global {\n const ARScene: typeof SDK.ARScene\n const AnimationClip: typeof SDK.AnimationClip\n const Animator: typeof SDK.Animator\n const Aspect: typeof SDK.Aspect\n const AudioPlayer: typeof SDK.AudioPlayer\n const AudioSource: typeof SDK.AudioSource\n const AudioZone: typeof SDK.AudioZone\n const Autotile2D: typeof SDK.Autotile2D\n const Bitmap: typeof SDK.Bitmap\n const Bus: typeof SDK.Bus\n const Camera: typeof SDK.Camera\n const Camera2D: typeof SDK.Camera2D\n const CameraFollow: typeof SDK.CameraFollow\n const CameraPlace: typeof SDK.CameraPlace\n const CameraView: typeof SDK.CameraView\n const Canvas: typeof SDK.Canvas\n const CharacterController: typeof SDK.CharacterController\n const CharacterController2D: typeof SDK.CharacterController2D\n const ClickEvent: typeof SDK.ClickEvent\n const Color: typeof SDK.Color\n const DateValue: typeof SDK.DateValue\n const DecalSet: typeof SDK.DecalSet\n const DecalTrail: typeof SDK.DecalTrail\n const DynamicBone: typeof SDK.DynamicBone\n const DynamicBoneCollider: typeof SDK.DynamicBoneCollider\n const Feet: typeof SDK.Feet\n const File: typeof SDK.File\n const Foliage: typeof SDK.Foliage\n const FollowPath: typeof SDK.FollowPath\n const FormData: typeof SDK.FormData\n const Geolocation: typeof SDK.Geolocation\n const Geometry: typeof SDK.Geometry\n const Gizmos: typeof SDK.Gizmos\n const IK: typeof SDK.IK\n const Input: typeof SDK.Input\n const InputChannel: typeof SDK.InputChannel\n const InspectorUI: typeof SDK.InspectorUI\n const InstancedMesh: typeof SDK.InstancedMesh\n const Layer: typeof SDK.Layer\n const Level: typeof SDK.Level\n const Light: typeof SDK.Light\n const Lightmap: typeof SDK.Lightmap\n const Locomotion: typeof SDK.Locomotion\n const LongPressEvent: typeof SDK.LongPressEvent\n const LookAt: typeof SDK.LookAt\n const Loop: typeof SDK.Loop\n const MapView: typeof SDK.MapView\n const Mat4: typeof SDK.Mat4\n const Material: typeof SDK.Material\n const MaterialHandle: typeof SDK.MaterialHandle\n const Mathf: typeof SDK.Mathf\n const Mesh: typeof SDK.Mesh\n const Model: typeof SDK.Model\n const MouseEnterEvent: typeof SDK.MouseEnterEvent\n const MoveTo: typeof SDK.MoveTo\n const NativeView: typeof SDK.NativeView\n const NavAgent: typeof SDK.NavAgent\n const NavCrowd: typeof SDK.NavCrowd\n const NavMesh: typeof SDK.NavMesh\n const Net: typeof SDK.Net\n const NetEntity: typeof SDK.NetEntity\n const NetPlayer: typeof SDK.NetPlayer\n const Node: typeof SDK.Node\n const Node2D: typeof SDK.Node2D\n const Noise: typeof SDK.Noise\n const OneWay2D: typeof SDK.OneWay2D\n const Particles: typeof SDK.Particles\n const Physics: typeof SDK.Physics\n const Physics2D: typeof SDK.Physics2D\n const PhysicsGroup2D: typeof SDK.PhysicsGroup2D\n const Plane: typeof SDK.Plane\n const PlayAnimation: typeof SDK.PlayAnimation\n const Playback: typeof SDK.Playback\n const Presentable: typeof SDK.Presentable\n const Push: typeof SDK.Push\n const QRScanner: typeof SDK.QRScanner\n const Quat: typeof SDK.Quat\n const REVERB_PRESETS: typeof SDK.REVERB_PRESETS\n const Ragdoll: typeof SDK.Ragdoll\n const Ray: typeof SDK.Ray\n const Replicated: typeof SDK.Replicated\n const Router: typeof SDK.Router\n const RpcError: typeof SDK.RpcError\n const Scene: typeof SDK.Scene\n const Scene2D: typeof SDK.Scene2D\n const Scene2dHandle: typeof SDK.Scene2dHandle\n const SceneAudio: typeof SDK.SceneAudio\n const SceneHandle: typeof SDK.SceneHandle\n const Service: typeof SDK.Service\n const Shape: typeof SDK.Shape\n const Shape2D: typeof SDK.Shape2D\n const Sound: typeof SDK.Sound\n const Spin: typeof SDK.Spin\n const Sprite: typeof SDK.Sprite\n const SpriteAnimation: typeof SDK.SpriteAnimation\n const SpriteSheet: typeof SDK.SpriteSheet\n const StateMachine: typeof SDK.StateMachine\n const SvgSource: typeof SDK.SvgSource\n const System: typeof SDK.System\n const Terrain: typeof SDK.Terrain\n const Texture: typeof SDK.Texture\n const Texture2D: typeof SDK.Texture2D\n const Tilemap: typeof SDK.Tilemap\n const Tileset: typeof SDK.Tileset\n const Time: typeof SDK.Time\n const Timeline: typeof SDK.Timeline\n const Tire: typeof SDK.Tire\n const TouchStartEvent: typeof SDK.TouchStartEvent\n const Trail: typeof SDK.Trail\n const Trigger: typeof SDK.Trigger\n const Trigger2D: typeof SDK.Trigger2D\n const UIBottomSheet: typeof SDK.UIBottomSheet\n const UIBox: typeof SDK.UIBox\n const UIButton: typeof SDK.UIButton\n const UIColumn: typeof SDK.UIColumn\n const UIImage: typeof SDK.UIImage\n const UIInput: typeof SDK.UIInput\n const UIModal: typeof SDK.UIModal\n const UIOverlay: typeof SDK.UIOverlay\n const UIPager: typeof SDK.UIPager\n const UIPopover: typeof SDK.UIPopover\n const UIRow: typeof SDK.UIRow\n const UIScreen: typeof SDK.UIScreen\n const UIScrollable: typeof SDK.UIScrollable\n const UISpacer: typeof SDK.UISpacer\n const UITabs: typeof SDK.UITabs\n const UIText: typeof SDK.UIText\n const UITextArea: typeof SDK.UITextArea\n const UIVideo: typeof SDK.UIVideo\n const UIVirtualizedList: typeof SDK.UIVirtualizedList\n const UIWidget: typeof SDK.UIWidget\n const VRScene: typeof SDK.VRScene\n const Vec2: typeof SDK.Vec2\n const Vec3: typeof SDK.Vec3\n const Vehicle: typeof SDK.Vehicle\n const VideoPlayer: typeof SDK.VideoPlayer\n const Voice: typeof SDK.Voice\n const Warp: typeof SDK.Warp\n const WebSocket: typeof SDK.WebSocket\n const Wheel: typeof SDK.Wheel\n const __UIBox: typeof SDK.__UIBox\n const __UIButton: typeof SDK.__UIButton\n const __UIColumn: typeof SDK.__UIColumn\n const __UIRow: typeof SDK.__UIRow\n const __UIScreen: typeof SDK.__UIScreen\n const __UIScrollable: typeof SDK.__UIScrollable\n const __UIWidget: typeof SDK.__UIWidget\n const __channel: typeof SDK.__channel\n const __compOp: typeof SDK.__compOp\n const __compWrite: typeof SDK.__compWrite\n const __rpc: typeof SDK.__rpc\n const __serverOnly: typeof SDK.__serverOnly\n const __uiMap: typeof SDK.__uiMap\n const animate: typeof SDK.animate\n const app: typeof SDK.app\n const audio: typeof SDK.audio\n const cells: typeof SDK.cells\n const clipboard: typeof SDK.clipboard\n const colorCurve: typeof SDK.colorCurve\n const computed: typeof SDK.computed\n const cubicBezier: typeof SDK.cubicBezier\n const curve: typeof SDK.curve\n const date: typeof SDK.date\n const defineMaterial: typeof SDK.defineMaterial\n const defineScene: typeof SDK.defineScene\n const defineScene2d: typeof SDK.defineScene2d\n const defineSpriteSheet: typeof SDK.defineSpriteSheet\n const defineStates: typeof SDK.defineStates\n const defineTabs: typeof SDK.defineTabs\n const defineTileset: typeof SDK.defineTileset\n const device: typeof SDK.device\n const easeIn: typeof SDK.easeIn\n const easeInOut: typeof SDK.easeInOut\n const easeOut: typeof SDK.easeOut\n const effect: typeof SDK.effect\n const encodeCells: typeof SDK.encodeCells\n const fetch: typeof SDK.fetch\n const fetchLocal: typeof SDK.fetchLocal\n const files: typeof SDK.files\n const flipX: typeof SDK.flipX\n const isRawCell: typeof SDK.isRawCell\n const localStorage: typeof SDK.localStorage\n const make: typeof SDK.make\n const openFilePicker: typeof SDK.openFilePicker\n const openURL: typeof SDK.openURL\n const packTile: typeof SDK.packTile\n const rawCell: typeof SDK.rawCell\n const rawIndex: typeof SDK.rawIndex\n const ref: typeof SDK.ref\n const registerEditorTool: typeof SDK.registerEditorTool\n const registerEditorWindow: typeof SDK.registerEditorWindow\n const registerFont: typeof SDK.registerFont\n const resolveTire: typeof SDK.resolveTire\n const rot180: typeof SDK.rot180\n const rot270: typeof SDK.rot270\n const rot90: typeof SDK.rot90\n const share: typeof SDK.share\n const signal: typeof SDK.signal\n const theme: typeof SDK.theme\n const tileFlip: typeof SDK.tileFlip\n const tileIndex: typeof SDK.tileIndex\n const tileOriented: typeof SDK.tileOriented\n const tileTurns: typeof SDK.tileTurns\n const toast: typeof SDK.toast\n const use: typeof SDK.use\n type ARScene<T extends ARMode = \"default\"> = SDK.ARScene<T>\n type ActiveClip = SDK.ActiveClip\n type AeroConfig = SDK.AeroConfig\n type AnimateOptions<T extends AnimateValue> = SDK.AnimateOptions<T>\n type AnimateOut<T> = SDK.AnimateOut<T>\n type AnimateValue = SDK.AnimateValue\n type Animation = SDK.Animation\n type AnimationClip = SDK.AnimationClip\n type Animator = SDK.Animator\n type AppState = SDK.AppState\n type Aspect<K extends string, P = Node, E extends EventMap = {}> = SDK.Aspect<K, P, E>\n type AspectEntry<A extends Aspect<any, any> = Aspect<any, any>> = SDK.AspectEntry<A>\n type AudioCone = SDK.AudioCone\n type AudioPlayer = SDK.AudioPlayer\n type AudioSource = SDK.AudioSource\n type AudioStats = SDK.AudioStats\n type AudioZone = SDK.AudioZone\n type AutoPaintRules = SDK.AutoPaintRules\n type Autotile2D = SDK.Autotile2D\n type Bitmap = SDK.Bitmap\n type BlendMember = SDK.BlendMember\n type BlendPosition = SDK.BlendPosition\n type BlockEntry = SDK.BlockEntry\n type Bus = SDK.Bus\n type Camera = SDK.Camera\n type Camera2D = SDK.Camera2D\n type Camera2dNodeDef = SDK.Camera2dNodeDef\n type CameraFacing = SDK.CameraFacing\n type CameraFollow = SDK.CameraFollow\n type CameraMove = SDK.CameraMove\n type CameraNodeDef = SDK.CameraNodeDef\n type CameraPlace = SDK.CameraPlace\n type CameraView = SDK.CameraView\n type Canvas = SDK.Canvas\n type CellsData = SDK.CellsData\n type ChannelSubscription = SDK.ChannelSubscription\n type CharacterController = SDK.CharacterController\n type CharacterController2D = SDK.CharacterController2D\n type ClickEvent<T = any> = SDK.ClickEvent<T>\n type ClipAlign = SDK.ClipAlign\n type ClipCycle = SDK.ClipCycle\n type ClipDef = SDK.ClipDef\n type ClipEventHandler = SDK.ClipEventHandler\n type ClipInfo = SDK.ClipInfo\n type ClipKey<V> = SDK.ClipKey<V>\n type ClipTrackDef = SDK.ClipTrackDef\n type CompAxis = SDK.CompAxis\n type CompWriter = SDK.CompWriter\n type Computed<T> = SDK.Computed<T>\n type ConformOptions = SDK.ConformOptions\n type DateInput = SDK.DateInput\n type DateValue = SDK.DateValue\n type DecalOptions = SDK.DecalOptions\n type DecalPlacement = SDK.DecalPlacement\n type DecalSet = SDK.DecalSet\n type DecalSetOptions = SDK.DecalSetOptions\n type DecalSpawnOptions = SDK.DecalSpawnOptions\n type DecalTrail = SDK.DecalTrail\n type DecalTrailOptions = SDK.DecalTrailOptions\n type DifferentialMode = SDK.DifferentialMode\n type DismissOptions = SDK.DismissOptions\n type Displacement = SDK.Displacement\n type DriveLayout = SDK.DriveLayout\n type DynamicBone = SDK.DynamicBone\n type DynamicBoneCollider = SDK.DynamicBoneCollider\n type DynamicBoneColliders = SDK.DynamicBoneColliders\n type DynamicBoneCurve = SDK.DynamicBoneCurve\n type DynamicBoneFloor = SDK.DynamicBoneFloor\n type EasingInput = SDK.EasingInput\n type EchoParams = SDK.EchoParams\n type EdgeSlot = SDK.EdgeSlot\n type EditorApi = SDK.EditorApi\n type EditorRayHit = SDK.EditorRayHit\n type EditorToolHooks = SDK.EditorToolHooks\n type EditorWindowFn = SDK.EditorWindowFn\n type EngineConfig = SDK.EngineConfig\n type EventMap = SDK.EventMap\n type Feet = SDK.Feet\n type FeetOptions = SDK.FeetOptions\n type FetchResponse = SDK.FetchResponse\n type FieldMeta<T = unknown> = SDK.FieldMeta<T>\n type File = SDK.File\n type FileData = SDK.FileData\n type FillBlock = SDK.FillBlock\n type FitOptions = SDK.FitOptions\n type FoliageOptions = SDK.FoliageOptions\n type FoliageWind = SDK.FoliageWind\n type FollowPath = SDK.FollowPath\n type FootState = SDK.FootState\n type FormData = SDK.FormData\n type Gait = SDK.Gait\n type GamepadAxisName = SDK.GamepadAxisName\n type GamepadState = SDK.GamepadState\n type GeoOptions = SDK.GeoOptions\n type GeoPosition = SDK.GeoPosition\n type GeoWatch = SDK.GeoWatch\n type Geometry = SDK.Geometry\n type GizmoAnchor = SDK.GizmoAnchor\n type GizmoStyle = SDK.GizmoStyle\n type HapticStyle = SDK.HapticStyle\n type IKLookAt = SDK.IKLookAt\n type IKTwoBone = SDK.IKTwoBone\n type InputEventName = SDK.InputEventName\n type InputGamepadEvent = SDK.InputGamepadEvent\n type InputKeyEvent = SDK.InputKeyEvent\n type InspectorUI = SDK.InspectorUI\n type InstanceTransform = SDK.InstanceTransform\n type InstancedMesh = SDK.InstancedMesh\n type KneeAxisReport = SDK.KneeAxisReport\n type Layer = SDK.Layer\n type LayerOptions = SDK.LayerOptions\n type LevelBuild = SDK.LevelBuild\n type LevelCollider = SDK.LevelCollider\n type LevelGridOptions = SDK.LevelGridOptions\n type LevelLineOptions = SDK.LevelLineOptions\n type LevelPlaceOptions = SDK.LevelPlaceOptions\n type LevelRingOptions = SDK.LevelRingOptions\n type LevelScatterOptions = SDK.LevelScatterOptions\n type LevelSpot = SDK.LevelSpot\n type Light = SDK.Light\n type LightDef = SDK.LightDef\n type Lightmap = SDK.Lightmap\n type LineLayer = SDK.LineLayer\n type LineLayerOptions = SDK.LineLayerOptions\n type LitMaterialDef = SDK.LitMaterialDef\n type LngLat = SDK.LngLat\n type LoadedScene<D extends SceneDef> = SDK.LoadedScene<D>\n type LoadedScene2d<D extends Scene2dDef> = SDK.LoadedScene2d<D>\n type Locale = SDK.Locale\n type Locomotion = SDK.Locomotion\n type LocomotionClip = SDK.LocomotionClip\n type LocomotionEvents = SDK.LocomotionEvents\n type LocomotionSet = SDK.LocomotionSet\n type LocomotionState = SDK.LocomotionState\n type LocomotionTuning = SDK.LocomotionTuning\n type LodMode = SDK.LodMode\n type LongPressEvent<T = any> = SDK.LongPressEvent<T>\n type LookAt = SDK.LookAt\n type Loop = SDK.Loop\n type LoopDef = SDK.LoopDef\n type LoopOptions = SDK.LoopOptions\n type MakeEntry<A extends Record<string, unknown> = Record<string, unknown>> = SDK.MakeEntry<A>\n type MapCamera = SDK.MapCamera\n type MapOptions = SDK.MapOptions\n type MapPaddingValues = SDK.MapPaddingValues\n type MapStyle = SDK.MapStyle\n type MapStyleName = SDK.MapStyleName\n type MapTap = SDK.MapTap\n type MapView = SDK.MapView\n type MarkerItem = SDK.MarkerItem\n type MarkerLayer = SDK.MarkerLayer\n type MarkerLayerOptions = SDK.MarkerLayerOptions\n type MarkerTap = SDK.MarkerTap\n type Mat4 = SDK.Mat4\n type Material = SDK.Material\n type MaterialData = SDK.MaterialData\n type MaterialDef = SDK.MaterialDef\n type MaterialHandle = SDK.MaterialHandle\n type MaterialParamValue = SDK.MaterialParamValue\n type Mesh = SDK.Mesh\n type MeshDef = SDK.MeshDef\n type Model = SDK.Model\n type MotionOptions = SDK.MotionOptions\n type MouseEnterEvent<T = any> = SDK.MouseEnterEvent<T>\n type MoveTo = SDK.MoveTo\n type NativeView = SDK.NativeView\n type NavAgent = SDK.NavAgent\n type NavAgentAvoidance = SDK.NavAgentAvoidance\n type NavAgentDrive = SDK.NavAgentDrive\n type NavAgentEvents = SDK.NavAgentEvents\n type NavAgentSize = SDK.NavAgentSize\n type NavAgentState = SDK.NavAgentState\n type NavCrowd = SDK.NavCrowd\n type NavMesh = SDK.NavMesh\n type NavMeshInfo = SDK.NavMeshInfo\n type NavMeshLoadOptions = SDK.NavMeshLoadOptions\n type NavPath = SDK.NavPath\n type NavQueryOptions = SDK.NavQueryOptions\n type NavRaycastHit = SDK.NavRaycastHit\n type NetCorrection = SDK.NetCorrection\n type NetEntity<S extends object = any> = SDK.NetEntity<S>\n type NetEvents = SDK.NetEvents\n type NetInput<T extends object = any> = SDK.NetInput<T>\n type NetKind<S extends object = any> = SDK.NetKind<S>\n type NetLaunch = SDK.NetLaunch\n type NetMessage<T = unknown> = SDK.NetMessage<T>\n type NetPlayer = SDK.NetPlayer\n type NetRole = SDK.NetRole\n type NetStatus = SDK.NetStatus\n type NetTransform = SDK.NetTransform\n type Node = SDK.Node\n type Node2D = SDK.Node2D\n type Noise = SDK.Noise\n type OneWay2D = SDK.OneWay2D\n type OrientationLock = SDK.OrientationLock\n type Particles = SDK.Particles\n type PatchMaterial = SDK.PatchMaterial\n type PatchSlots = SDK.PatchSlots\n type PathMaterial = SDK.PathMaterial\n type Physics = SDK.Physics\n type Physics2D = SDK.Physics2D\n type PhysicsGroup2D = SDK.PhysicsGroup2D\n type Plane = SDK.Plane\n type PlayAnimation = SDK.PlayAnimation\n type PlayOptions = SDK.PlayOptions\n type PlaySoundOptions = SDK.PlaySoundOptions\n type Playback = SDK.Playback\n type Point = SDK.Point\n type PresentOptions = SDK.PresentOptions\n type Presentable = SDK.Presentable\n type PushEvent = SDK.PushEvent\n type PushPayload = SDK.PushPayload\n type PushRegisterOptions = SDK.PushRegisterOptions\n type PushStatus = SDK.PushStatus\n type QRScanner = SDK.QRScanner\n type Quat = SDK.Quat\n type Ragdoll = SDK.Ragdoll\n type RagdollActivateOptions = SDK.RagdollActivateOptions\n type RagdollDeactivateOptions = SDK.RagdollDeactivateOptions\n type RagdollFacing = SDK.RagdollFacing\n type RagdollHinge = SDK.RagdollHinge\n type RagdollHitOptions = SDK.RagdollHitOptions\n type RagdollPart = SDK.RagdollPart\n type Ray = SDK.Ray\n type Replicated = SDK.Replicated\n type ReverbParams = SDK.ReverbParams\n type ReverbPreset = SDK.ReverbPreset\n type RibbonOptions = SDK.RibbonOptions\n type Rolloff = SDK.Rolloff\n type RpcError = SDK.RpcError\n type Scene = SDK.Scene\n type Scene2D = SDK.Scene2D\n type Scene2dDef = SDK.Scene2dDef\n type Scene2dEnv = SDK.Scene2dEnv\n type Scene2dHandle<D extends Scene2dDef = Scene2dDef> = SDK.Scene2dHandle<D>\n type Scene2dNodeDef = SDK.Scene2dNodeDef\n type SceneAudio = SDK.SceneAudio\n type SceneDef = SDK.SceneDef\n type SceneHandle<D extends SceneDef = SceneDef> = SDK.SceneHandle<D>\n type SceneInstance<D extends SceneDef> = SDK.SceneInstance<D>\n type SceneNodeDef = SDK.SceneNodeDef\n type SculptOptions = SDK.SculptOptions\n type Service = SDK.Service\n type ShaderMaterialDef = SDK.ShaderMaterialDef\n type Shape = SDK.Shape\n type Shape2D = SDK.Shape2D\n type SheetSprite = SDK.SheetSprite\n type Signal<T> = SDK.Signal<T>\n type Sound = SDK.Sound\n type SoundOptions = SDK.SoundOptions\n type SpatialOptions = SDK.SpatialOptions\n type Spin = SDK.Spin\n type Sprite = SDK.Sprite\n type SpriteAnimation = SDK.SpriteAnimation\n type SpriteMakeOptions = SDK.SpriteMakeOptions\n type SpriteSheet = SDK.SpriteSheet\n type SpriteSheetDef = SDK.SpriteSheetDef\n type SpriteSourceDef = SDK.SpriteSourceDef\n type StateDef<C> = SDK.StateDef<C>\n type StateGuard<C> = SDK.StateGuard<C>\n type StateHandler<C> = SDK.StateHandler<C>\n type StateMachine<C> = SDK.StateMachine<C>\n type StateMachineEvents = SDK.StateMachineEvents\n type StatesDef<C> = SDK.StatesDef<C>\n type SteeringConfig = SDK.SteeringConfig\n type SteeringDriver = SDK.SteeringDriver\n type SteeringFeedback = SDK.SteeringFeedback\n type StepHandler = SDK.StepHandler\n type StepWarpOptions = SDK.StepWarpOptions\n type StopOptions = SDK.StopOptions\n type StoredFile = SDK.StoredFile\n type StoredImage = SDK.StoredImage\n type SvgSource = SDK.SvgSource\n type System<K extends string, S extends SystemHost = Scene, E extends EventMap = {}> = SDK.System<K, S, E>\n type SystemHost = SDK.SystemHost\n type TabDef = SDK.TabDef\n type TabsHandle<T extends Record<string, TabDef>> = SDK.TabsHandle<T>\n type Terrain = SDK.Terrain\n type TerrainHit = SDK.TerrainHit\n type TerrainLayer = SDK.TerrainLayer\n type TerrainOptions = SDK.TerrainOptions\n type TerrainRegion = SDK.TerrainRegion\n type TerrainSnapshot = SDK.TerrainSnapshot\n type Texture = SDK.Texture\n type Texture2D = SDK.Texture2D\n type TextureLoadOptions = SDK.TextureLoadOptions\n type ThemeAccessors<T> = SDK.ThemeAccessors<T>\n type ThemeRoles = SDK.ThemeRoles\n type ThemeValues = SDK.ThemeValues\n type TileBlock = SDK.TileBlock\n type TileMaterial = SDK.TileMaterial\n type TilePart = SDK.TilePart\n type Tilemap = SDK.Tilemap\n type TilemapSourceDef = SDK.TilemapSourceDef\n type Tileset = SDK.Tileset\n type TilesetDef = SDK.TilesetDef\n type Timeline = SDK.Timeline\n type TimelineAddOptions = SDK.TimelineAddOptions\n type TimelineOptions = SDK.TimelineOptions\n type TimelinePosition = SDK.TimelinePosition\n type Tire = SDK.Tire\n type TouchStartEvent<T = any> = SDK.TouchStartEvent<T>\n type Trail = SDK.Trail\n type Transition = SDK.Transition\n type TransitionName = SDK.TransitionName\n type TransitionPose = SDK.TransitionPose\n type TransitionSpec = SDK.TransitionSpec\n type TrianglePick = SDK.TrianglePick\n type Trigger = SDK.Trigger\n type Trigger2D = SDK.Trigger2D\n type TweenMeta = SDK.TweenMeta\n type UIBottomSheet = SDK.UIBottomSheet\n type UIBottomSheetStyle = SDK.UIBottomSheetStyle\n type UIBox = SDK.UIBox\n type UIButton = SDK.UIButton\n type UIButtonStyle = SDK.UIButtonStyle\n type UIColumn = SDK.UIColumn\n type UIContainerStyle = SDK.UIContainerStyle\n type UIImage = SDK.UIImage\n type UIImageStyle = SDK.UIImageStyle\n type UIInput = SDK.UIInput\n type UIInputStyle = SDK.UIInputStyle\n type UIModal = SDK.UIModal\n type UIModalStyle = SDK.UIModalStyle\n type UINativeViewStyle = SDK.UINativeViewStyle\n type UINode = SDK.UINode\n type UINodeChild = SDK.UINodeChild\n type UIPager = SDK.UIPager\n type UIPagerStyle = SDK.UIPagerStyle\n type UIPopover = SDK.UIPopover\n type UIPopoverStyle = SDK.UIPopoverStyle\n type UIRow = SDK.UIRow\n type UIScreen = SDK.UIScreen\n type UIScreenStyle = SDK.UIScreenStyle\n type UIScrollable = SDK.UIScrollable\n type UIScrollableStyle = SDK.UIScrollableStyle\n type UISpacer = SDK.UISpacer\n type UISpacerStyle = SDK.UISpacerStyle\n type UITabDef = SDK.UITabDef\n type UITabs = SDK.UITabs\n type UIText = SDK.UIText\n type UITextArea = SDK.UITextArea\n type UITextStyle = SDK.UITextStyle\n type UIVideo = SDK.UIVideo\n type UIVideoStyle = SDK.UIVideoStyle\n type UIVirtualizedList<T = unknown> = SDK.UIVirtualizedList<T>\n type UIWidget = SDK.UIWidget\n type UIWidgetContent = SDK.UIWidgetContent\n type UIWidgetStyle = SDK.UIWidgetStyle\n type Unit = SDK.Unit\n type UnlitMaterialDef = SDK.UnlitMaterialDef\n type UserLocationOptions = SDK.UserLocationOptions\n type VRScene = SDK.VRScene\n type Vec2 = SDK.Vec2\n type Vec3 = SDK.Vec3\n type Vehicle = SDK.Vehicle\n type VideoPlayer = SDK.VideoPlayer\n type Voice = SDK.Voice\n type VoiceEvents = SDK.VoiceEvents\n type Warp = SDK.Warp\n type WarpOptions = SDK.WarpOptions\n type WebSocket = SDK.WebSocket\n type Wheel = SDK.Wheel\n type WheelSuspension = SDK.WheelSuspension\n type With<N, A extends Aspect<any, any, any>> = SDK.With<N, A>\n // ---- server globals (available in *.server.ts; using them in client code is a build error) ----\n const ApiError: typeof SERVER.ApiError\n const channel: typeof SERVER.channel\n const defineDb: typeof SERVER.defineDb\n const model: typeof SERVER.model\n const ref: typeof SERVER.ref\n const request: typeof SERVER.request\n const t: typeof SERVER.t\n type ApiError = SERVER.ApiError\n type StoredFile = SERVER.StoredFile\n type StoredImage = SERVER.StoredImage\n}\n\nexport {}\n","host.d.ts":"// JS-runtime globals provided by the host engine (web viewer / desktop / iOS), NOT by the SDK.\n// Declared only so SDK and user code type-check — never bundled or injected.\n\n// The one SDK type the macros return: an SVG image source, the same `SvgSource` a project has as\n// a global (build-types.ts points this import into dist/types when it copies the file).\nimport type { SvgSource } from \"./types/runtime/misc\"\n\ndeclare global {\n function setTimeout(handler: (...args: any[]) => void, timeout?: number): number\n function setInterval(handler: (...args: any[]) => void, timeout?: number): number\n function clearTimeout(id: number): void\n function clearInterval(id: number): void\n /** Per-frame loop, driven by the host (viewer RAF / desktop runTick). `dt` is **seconds** since\n * the previous frame. */\n function setLoop(handler: (dt: number) => void): number\n function clearLoop(id: number): void\n\n /** π/180 — substituted at compile time (bundler `define`). */\n var DEG2RAD: number\n /** 180/π — substituted at compile time (bundler `define`). */\n var RAD2DEG: number\n\n /** Compile-time boolean: `true` in scene-editor bundles, `false` (const-folded + DCE'd) in\n * shipped ones — `if (EDITOR) { … }` costs zero bytes in production. `*.editor.ts` files are\n * the file-level form. */\n var EDITOR: boolean\n\n var console: {\n log(...data: any[]): void\n warn(...data: any[]): void\n info(...data: any[]): void\n error(...data: any[]): void\n }\n\n /** Compile-time macro: `asset('./data.json')` yields the file's PARSED data (a .json file is\n * data, not code — it ships inside the bundle). See the `string` overload for everything else. */\n function asset(path: `${string}.json`): any\n /** Compile-time macro: `asset('./logo.svg')` yields the file as an SVG image source — for\n * `UIImage(...)` and `bgImage`. */\n function asset(path: `${string}.svg`): SvgSource\n /** Compile-time macro: `asset('./hero.png')` is desugared by the bundler into the module import\n * for that resource. The file must exist — a path that resolves to nothing fails the compile\n * (`asset not found: ./hero.png (main.ts:3)`); there is no runtime fallback. Calls inside\n * comments and string literals are text, not macros. */\n function asset(path: string): string\n\n /** Compile-time macro: installs a font and returns its family name — using a font IS declaring\n * it. A registry id (`font(\"manrope\")`) resolves against the font registry; a project path\n * (`font(\"./fonts/Brand.ttf\")`) reads family/weight/italic from the file itself. `opts`\n * narrows/extends the face set (default: the family's standard weights). String-literal\n * argument only. No awaiting — faces load with app boot and the host holds first paint for\n * them. */\n function font(id: string, opts?: { weights?: number[], italic?: boolean }): string\n\n /** Compile-time macro: resolves one icon from the icon registry at build time and inlines it as\n * an image source for `UIImage(...)` — offline, identical on every host. `id` is `\"pack:name\"`\n * (e.g. `\"lucide:bell\"`), string literal only. Recolor via `{ color }`: a hex LITERAL is baked\n * into the SVG at compile time, a token/expression is applied as a tint (as is the `tintColor`\n * style prop). */\n function assetIcon(id: string, opts?: { color?: string }): SvgSource\n\n /** Type-only editor convenience: the style object type of a UI element. `Style<UIButton>` (or\n * `Style<typeof myButton>`) is what you'd pass to `el.style(...)` — for typing reusable style\n * presets. Deliberately no `Partial<>` wrapper: every style prop is already optional, and\n * Partial over ClassStyles' `$`-index signature adds `| undefined`, breaking assignability back\n * into `.style(...)`. Round-trip guarded by sdk/tests/ui/types.test.ts. */\n type Style<T> = T extends { style: (s: infer S) => any } ? S : never\n}\n\nexport {}\n","types/animate/bezier.d.ts":"import type { Easing } from \"./easings\";\nexport declare function cubicBezier(mX1: number, mY1: number, mX2: number, mY2: number): Easing;\n","types/animate/easings.d.ts":"export type Easing = (v: number) => number;\nexport type EasingModifier = (easing: Easing) => Easing;\nexport declare function linear(p: number): number;\nexport declare function bounceOut(p: number): number;\nexport declare function bounceInOut(p: number): number;\nexport declare function reverseEasing(easing: Easing): Easing;\nexport declare function mirrorEasing(easing: Easing): Easing;\nexport declare function createExpoIn(power: number): Easing;\nexport declare function createBackIn(power: number): Easing;\nexport declare function createAnticipate(power: number): Easing;\nexport declare function bounceIn(p: number): number;\nexport declare function easeIn(p: number): number;\nexport declare function easeOut(p: number): number;\nexport declare function easeInOut(p: number): number;\nexport declare function circIn(p: number): number;\nexport declare function circOut(p: number): number;\nexport declare function circInOut(p: number): number;\nexport declare function backIn(p: number): number;\nexport declare function backOut(p: number): number;\nexport declare function backInOut(p: number): number;\nexport declare function anticipate(p: number): number;\n","types/animate/tween/animateValue.d.ts":"import { type Animation } from \"./Animation\";\nimport type { Vec2Like, Vec3Like } from \"../../math/vec\";\nimport type { QuatLike } from \"../../math/quat\";\nimport type { Mat4Like } from \"../../math/mat4\";\nimport type { ColorInput } from \"../../core/color\";\nimport { type TweenMeta } from \"./spec\";\n/** What `animate()` tweens: a number (a FLOAT, never a packed color), a color (any CSS color string,\n * through `Color` — delivered as rgba 0..1; a string that is not a color throws), a 2 / 3-vector (a\n * 3-array is a vector, not a color), a quaternion (slerp), or a 4x4 matrix (position / rotation /\n * scale). */\nexport type AnimateValue = number | string | Vec2Like | Vec3Like | QuatLike | Mat4Like | ColorInput;\n/** `onUpdate` receives a number for a number; every other kind arrives as the SAME `Float32Array`\n * every frame (overwritten in place — copy it if you keep it). A matrix is the 16 floats. */\nexport type AnimateOut<T> = T extends number ? number : Float32Array;\nexport type AnimateOptions<T extends AnimateValue> = Omit<TweenMeta, \"commit\" | \"layer\"> & {\n /** Start value (required unless `values` is given). */\n from?: T;\n /** End value. */\n to?: T;\n /** Keyframes instead of from/to (offsets via `times`). */\n values?: T[];\n onUpdate(value: AnimateOut<T>): void;\n /** After the last frame of a run that reached its end (not on cancel). */\n onComplete?(): void;\n};\n/** Tween a free value and apply it yourself in `onUpdate` — the primitive for anything without a\n * native channel (material params, volumes, numbers a Canvas draws). Same easing / keyframes /\n * `loop` / `clock` as `animateTo`; returns the {@link Animation} handle. Default clock: `'ui'`. */\nexport declare const animate: <T extends AnimateValue>(options: AnimateOptions<T>) => Animation;\n","types/animate/tween/Animation.d.ts":"import { CLOCK_GAME, CLOCK_UI, type TweenSpec } from \"./spec\";\n/** Playback control shared by element tweens and timelines. Times are **milliseconds**. */\nexport interface Animation {\n /** One iteration, ms. */\n readonly duration: number;\n /** Position inside the current iteration, ms. Writable = seek. */\n time: number;\n /** 0..1 of the whole animation (iterations included). Writable = seek. */\n progress: number;\n /** Playback rate; negative runs backwards, 0 freezes. */\n rate: number;\n readonly playing: boolean;\n /** Resolves `true` when the animation reaches its end, `false` when cancelled, replaced or replayed. Never rejects. */\n readonly finished: Promise<boolean>;\n /** Start from t = 0 (a running animation restarts). */\n play(): this;\n pause(): this;\n resume(): this;\n /** Jump to `ms`; playback state is unchanged. */\n seek(ms: number): this;\n /** Jump to the end: values land, commits apply, `finished` resolves `true`. */\n finish(): this;\n /** Stop where it is — no commit, `finished` resolves `false`. */\n cancel(): this;\n onFinish(fn: (done: boolean) => void): this;\n}\n/** The concrete handle — what the SDK instantiates behind `animateTo` / `animateFrom` / `Timeline`.\n * User code sees the {@link Animation} interface; the class itself must stay in the public\n * declarations because `TimelineImpl` extends it — marking it internal (even mentioning the tag in\n * this comment: the strip is a substring match) drops the timeline's playback members. */\nexport declare class TweenAnimation implements Animation {\n private _started;\n private _endTime;\n private _playing;\n private _rate;\n private _finished;\n private _resolve;\n private _settled;\n private _listeners;\n constructor(spec: TweenSpec);\n private _newPromise;\n private _settle;\n get duration(): number;\n get playing(): boolean;\n get finished(): Promise<boolean>;\n get rate(): number;\n set rate(r: number);\n get time(): number;\n set time(ms: number);\n get progress(): number;\n set progress(p: number);\n private _totalMs;\n private _elapsedMs;\n private _seekTotal;\n /** Create the host animation (paused at t = 0) if it doesn't exist. */\n private _ensure;\n private _destroy;\n play(): this;\n pause(): this;\n resume(): this;\n seek(ms: number): this;\n finish(): this;\n cancel(): this;\n onFinish(fn: (done: boolean) => void): this;\n}\nexport { CLOCK_UI, CLOCK_GAME };\n","types/animate/tween/easing.d.ts":"import type { Easing } from \"../easings\";\nexport declare const EASE_LINEAR = 0;\nexport declare const EASE_NAMED = 1;\nexport declare const EASE_BEZIER = 2;\nexport declare const EASE_STEPS = 3;\nexport declare const EASE_TABLE = 4;\n/** Samples per table (t = i / 64). Interpolation error for the smooth built-ins is < 1e-3. */\nexport declare const EASE_TABLE_SIZE = 65;\nexport type EasingSpec = {\n kind: number;\n /** kind-specific parameters: NAMED [id], BEZIER [x1, y1, x2, y2], STEPS [n, jumpAtStart], TABLE [tableIndex] */\n p: [number, number, number, number];\n /** TABLE only — the samples, appended to the blob's table section by the builder. */\n table?: Float32Array;\n};\n/** A curve in the options bag: a name, `\"cubic-bezier(x1,y1,x2,y2)\"`, `\"steps(n)\"`, a bezier tuple,\n * or any `Easing` function. */\nexport type EasingInput = string | readonly [number, number, number, number] | Easing;\n/** id → (name, formula). The formulas are the standard easings.net set; creator-tween's\n * `ctweenEaseNamed` implements the same list by id. */\nexport declare const NAMED_EASINGS: ReadonlyArray<readonly [string, Easing]>;\n/** The CSS `ease-in-out` curve — also UIKit's default animation curve, and web-lite's transition\n * default: what every host tweened with before the keyframe core. */\nexport declare const CSS_EASE_IN_OUT: [number, number, number, number];\nexport declare const LINEAR: EasingSpec;\n/** The default of every track with a TARGET (`animateTo` / `animateFrom` / `Timeline.add` on an\n * element, a 3D / 2D object): `ease-in-out` (2026-09-27; linear before). `animate()` — a raw\n * progress the app maps itself — stays linear. Write `easing: \"linear\"` for uniform motion. */\nexport declare const DEFAULT_EASING: EasingSpec;\n/** Sample an `Easing` function into a table. Endpoints are forced exact so a curve that is\n * numerically 0.9999 at 1 still lands on the keyframe. */\nexport declare const sampleEasing: (fn: Easing) => Float32Array;\n/** Normalize one easing input. Unknown strings fall back to linear with a console warning (a typo\n * should be visible, not a silent snap). */\nexport declare const parseEasing: (input: EasingInput | undefined) => EasingSpec;\n/** Evaluate an `EasingSpec` at `u` ∈ [0, 1] — the JS twin of `ctweenEase`. */\nexport declare const evalEasing: (e: EasingSpec, u: number) => number;\n","types/animate/tween/spec.d.ts":"import { type EasingInput, type EasingSpec } from \"./easing\";\nexport declare const BLOB_VERSION = 1;\nexport declare const DOM_UI = 0;\nexport declare const DOM_GL_NODE = 1;\nexport declare const DOM_GL_LIGHT = 2;\nexport declare const DOM_GL_CAMERA = 3;\nexport declare const DOM_NODE2D = 4;\nexport declare const DOM_SPRITE2D = 5;\nexport declare const DOM_VALUE = 6;\nexport declare const KIND_FLOAT = 0;\nexport declare const KIND_FLOAT_UNIT = 1;\nexport declare const KIND_COLOR = 2;\nexport declare const KIND_TRANSFORM = 3;\nexport declare const KIND_TRANSFORM_MATRIX = 4;\nexport declare const KIND_VEC3 = 5;\nexport declare const KIND_QUAT = 6;\nexport declare const KIND_EULER = 7;\nexport declare const KIND_DISCRETE = 8;\nexport declare const KIND_STRING = 9;\nexport declare const KIND_VEC2 = 10;\nexport declare const KIND_MAT4 = 11;\nexport declare const CLOCK_UI = 0;\nexport declare const CLOCK_GAME = 1;\nexport declare const lanesOf: (kind: number) => number;\n/** One normalized value: numeric lanes, or a string (string-lane kinds). */\nexport type TweenValue = {\n lanes: number[];\n} | {\n str: string;\n};\n/** A target's answer to \"can you animate `prop`?\": the writer domain, the id resolver, the value\n * normalizer, and the commit hook (UI writes the last key into its stored style). */\nexport type TweenChannel = {\n domain: number;\n /** Host handle at play time — a number (entity, web node id) or the host's opaque node object\n * (creator-pkg hands `_id` out as one); falsy = not addressable right now (unmounted), the\n * track is skipped. Handed to the host in the blob's `targets` list, never in the float data. */\n id: () => unknown;\n /** Normalize one keyframe value; `null` = not animatable (a warning, the value is committed only). */\n value: (v: unknown) => ({\n kind: number;\n sig?: string;\n } & TweenValue) | null;\n commit?: (v: unknown) => void;\n};\n/** Implemented by every animatable class (Element, Node, Node2D, Sprite, Light, Camera). */\nexport interface TweenTarget {\n}\nexport type Keyframe = {\n /** 0..1 within the track. */\n t: number;\n easing: EasingSpec;\n /** `undefined` = capture at play. */\n value?: TweenValue;\n /** The bag value as written — what the old-host path forwards verbatim. */\n raw?: unknown;\n};\nexport type Track = {\n target: TweenTarget;\n prop: string;\n channel: TweenChannel;\n kind: number;\n lanes: number;\n sig?: string;\n atMs: number;\n durMs: number;\n commit: boolean;\n keys: Keyframe[];\n};\nexport type TweenSpec = {\n clock: number;\n /** One iteration, ms — the last track's end (holds included). */\n durationMs: number;\n delayMs: number;\n /** -1 = forever. */\n iterations: number;\n pingPong: boolean;\n rate: number;\n tracks: Track[];\n /** Time-callbacks, ms; index = the event index the host reports. */\n calls: number[];\n};\n/** Meta keys of an `animateTo` / `Timeline.add` bag — everything that is not a prop target. */\nexport declare const TWEEN_META: Set<string>;\nexport type TweenMeta = {\n /** Tween length in **milliseconds** (default 225). */\n duration?: number;\n /** Wait before starting, **milliseconds**. The first keyframe holds through the wait. A loop delays once. */\n delay?: number;\n /** A curve for every prop, or a per-prop map (`{ width: 'outExpo', opacity: 'linear' }`). Names\n * (`outCubic`, `inOutSine`, `outBack`, …), `cubic-bezier(…)` / a `[x1, y1, x2, y2]` tuple,\n * `steps(n)`, or any `Easing` function. Default `ease-in-out` (cubic-bezier(0.42, 0, 0.58, 1),\n * the curve UIKit and CSS transitions ease with); `\"linear\"` for uniform motion. */\n easing?: EasingInput | Record<string, EasingInput>;\n /** Keyframe offsets 0..1 for array-valued props (default: evenly spaced). */\n times?: number[];\n /** `true` = forever, a number = that many cycles. A loop never commits. */\n loop?: boolean | number;\n /** `\"ping-pong\"` (default) there and back each cycle; `\"restart\"` snaps back and replays. */\n loopMode?: \"restart\" | \"ping-pong\";\n /** `false` = animate without writing the last keyframe into the element's style. */\n commit?: boolean;\n /** `'ui'` = wall time (menus animate while the game is paused); `'game'` follows `Time.scale`.\n * Default: `'ui'` on UI elements, `'game'` on 3D / 2D nodes. */\n clock?: \"ui\" | \"game\";\n /** Legacy escape hatch (old hosts only). */\n layer?: number;\n};\nexport declare const DEFAULT_DURATION_MS = 225;\nexport declare const warnOnce: (key: string, msg: string) => void;\n/** Resolve the per-prop easing from the bag; nothing given (or no entry for `prop` in a per-prop\n * map) = `fallback` — the tracks' DEFAULT_EASING, linear for a value tween. */\nexport declare const easingFor: (easing: TweenMeta[\"easing\"], prop: string, fallback?: EasingSpec) => EasingSpec;\n/** Iteration count from `loop`: 1 = one-shot, -1 = forever, n = cycles. */\nexport declare const iterationsOf: (loop: TweenMeta[\"loop\"]) => number;\n/** A UI style value: number → FLOAT; \"12px\" / \"50%\" → FLOAT_UNIT; other strings → STRING (the host\n * decides color vs discrete); booleans → DISCRETE. The element hands over the WIRE value\n * (UINode._tweenChannel): a color key arrives as a string, never a packed number. */\nexport declare const uiValue: (v: unknown) => ({\n kind: number;\n sig?: string;\n} & TweenValue) | null;\n/** Parse `\"translate(10px, 20px) rotate(45deg) scale(1.2)\"` into a signature + lanes, or null when a\n * function is unknown (the caller falls back to matrix decomposition on the host). `scale(2)` and\n * `translate(5px)` complete their second argument like CSS.\n *\n * `percent`: a `%` in a translate is a percent of the target's box (`translateX(100%)` →\n * `translateX%` [100]; a translate mixing the units splits into its two axes). Without it a `%`\n * reads as px, as the style's own parser reads it — with a warning: only a screen transition\n * measures a translate in percents. */\nexport declare const parseTransformList: (s: string, percent?: boolean) => {\n sig: string;\n lanes: number[];\n} | null;\nexport declare const transformLanes: (sig: string) => number;\nexport declare const vec3Value: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const quatValue: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const eulerValue: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const vec2Value: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const floatValue: (v: unknown) => {\n kind: number;\n lanes: number[];\n} | null;\nexport declare const colorValue: (v: unknown, toRgba: (c: any) => [number, number, number, number]) => {\n kind: number;\n lanes: [number, number, number, number];\n} | null;\n/** A free value for animate(): number → FLOAT, a color string → COLOR, arrays / vectors by length\n * (2 → VEC2, 3 → VEC3, 4 → QUAT, 16 → MAT4 decomposed into position · quaternion · scale). */\nexport declare const valueValue: (v: unknown) => ({\n kind: number;\n} & TweenValue) | null;\n/** Is this bag value a KEYFRAME ARRAY for a vector prop, as opposed to one vector? A vector value\n * is an array of NUMBERS (`[0, 2, 0]`); anything else in the array is a list of keyframes —\n * `[[0,0,0], [0,2,0]]`, `[new Vec3(), …]`, and the UI's `color: ['#fff', '#e29a22']`. */\nexport declare const isVectorKeyframes: (v: unknown) => boolean;\n/** Build one track's keyframes from a bag value: a single value = one explicit key (the other end\n * captured), an array = explicit keys spaced by `times` or evenly. `fromCurrent` says which end is\n * implicit (animateTo: the first; animateFrom: the last). Returns null when a value can't be\n * animated (already warned). */\nexport declare const makeTrack: (target: TweenTarget, prop: string, raw: unknown, meta: TweenMeta, atMs: number, fromCurrent: boolean, vectorProp: boolean) => Track | null;\n/** Every (prop → value) entry of a bag, meta keys stripped. */\nexport declare const bagProps: (bag: Record<string, unknown>) => [string, unknown][];\n/** The value of a numeric track at local time `ms` (the C evaluator's rule: first key holds before,\n * last after; eased segment between). `out` receives `track.lanes` numbers. */\nexport declare const evaluateTrack: (track: Track, ms: number, out: number[]) => void;\nexport type TweenBlob = {\n data: Float32Array;\n strings: string[];\n targets: unknown[];\n};\n/** Flatten a spec for `_creatorTree.tweenCreate`. Tracks whose target has no host id right now are\n * dropped (the animation still runs its clock, calls and finish). */\nexport declare const buildBlob: (spec: TweenSpec) => TweenBlob;\n","types/animate/tween/Timeline.d.ts":"import { TweenAnimation } from \"./Animation\";\nimport { type AnimateOptions, type AnimateValue } from \"./animateValue\";\nimport { type TweenMeta, type TweenTarget } from \"./spec\";\nexport type TimelineOptions = {\n /** `'ui'` (default) = wall time; `'game'` follows `Time.scale` and pauses with the game. */\n clock?: \"ui\" | \"game\";\n /** Repeat the whole timeline: `true` = forever, a number = cycles. */\n loop?: boolean | number;\n loopMode?: \"restart\" | \"ping-pong\";\n /** Wait before the first play, ms. */\n delay?: number;\n};\n/** Where a track goes: ms, a label, or `[label, offsetMs]`. Default = the current end (sequencing). */\nexport type TimelinePosition = number | string | [string, number];\nexport type TimelineAddOptions = {\n at?: TimelinePosition;\n /** With several targets: each starts this many ms after the previous one. */\n stagger?: number;\n};\n/** A choreography: tracks on many targets at absolute times, JS calls, labels and holds, driven by\n * one clock. Build it once, `play()` on every entrance — `play()` restarts from t = 0 and the pose\n * at any time is fully defined by the tracks (the first keyframe of a track holds before it\n * starts, the last one after it ends). */\nexport declare class TimelineImpl extends TweenAnimation {\n private _labels;\n private _end;\n constructor(options?: TimelineOptions);\n private _at;\n private _grow;\n /** Animate `props` on one target or several (staggered), like `animateTo` — arrays are keyframes,\n * `duration` / `easing` / `times` / `commit` apply. The bag's `delay` shifts the track after `at`. */\n add(target: TweenTarget | TweenTarget[], props: Record<string, unknown> & TweenMeta, options?: TimelineAddOptions): this;\n /** Like `add` with the `animateFrom` shape: the target's own state is the implicit last keyframe. */\n addFrom(target: TweenTarget | TweenTarget[], props: Record<string, unknown> & TweenMeta, options?: TimelineAddOptions): this;\n /** A free-value track (see the `animate()` global): the host evaluates it and calls `onUpdate`\n * every frame with the value. */\n animate<T extends AnimateValue>(options: AnimateOptions<T>, at?: TimelinePosition): this;\n /** Call `fn` when playback crosses `at` (forward or backward), in time order, always before\n * finish, never from a previous run. */\n call(at: TimelinePosition, fn: () => void): this;\n /** Name a time — for `at`, `seek` and callers (`tl.labels.landed`). Default = the current end. */\n label(name: string, at?: TimelinePosition): this;\n /** Named times, ms. */\n get labels(): Record<string, number>;\n /** Extend the timeline with stillness after its current end. */\n hold(ms: number): this;\n /** The current end, ms (tracks, calls and holds). */\n get end(): number;\n /** `seek` also accepts a label. */\n seek(at: number | string): this;\n}\n/** The timeline handle type (see {@link TimelineImpl} for the members). */\nexport type Timeline = TimelineImpl;\n/** Create a timeline — `Timeline()` / `Timeline({ clock: 'game', loop: true })`. */\nexport declare function Timeline(options?: TimelineOptions): Timeline;\n","types/audio/audio.d.ts":"import { type Vec3Like } from \"../math/vec\";\nimport { Bus } from \"./Bus\";\nimport type { Sound } from \"./Sound\";\nimport { Voice } from \"./Voice\";\nexport type PlaySoundOptions = {\n /** 0 … 1 (and above, at your own risk). Default 1. */\n volume?: number;\n /** Playback rate, 1 = unchanged. Default 1. */\n pitch?: number;\n loop?: boolean;\n /** Bus name; default: the source's bus, `sfx` for 2D. */\n bus?: string;\n /** Higher survives voice stealing when the pool is full. Default 0. */\n priority?: number;\n /** Fade-in seconds. Default 0. */\n fade?: number;\n /** Seconds into the clip to start from. */\n startAt?: number;\n /** 2D only: -1 left … 1 right. */\n pan?: number;\n};\nexport type Rolloff = \"none\" | \"inverse\" | \"linear\" | \"exponential\";\n/** Distance model of an AudioSource / playAt. */\nexport type SpatialOptions = {\n /** Metres of full volume around the source. Default 1. */\n minDistance?: number;\n /** Metres beyond which the source no longer gets quieter. Default 50. */\n maxDistance?: number;\n /** How volume falls between the two: `inverse` (default, physical), `linear`, `exponential`, `none`. */\n rolloff?: Rolloff;\n};\nexport declare const ROLLOFF: Record<Rolloff, number>;\nexport type AudioStats = {\n voicesPlaying: number;\n voicesMono: number;\n voicesStereo: number;\n /** Voices displaced (or dropped) by a fuller pool since start. */\n stolen: number;\n clips: number;\n clipBytes: number;\n /** Master peak since the previous read, linear (1 = full scale). */\n peak: number;\n sampleRate: number;\n /** The reverb zone the listener is in (0 = none) and how far inside (0 … 1). */\n listenerZone: number;\n zoneBlend: number;\n /** Voices rendered binaurally right now (see `audio.hrtf`). */\n hrtfVoices: number;\n};\ndeclare class AudioSystem {\n private readonly _buses;\n private _hrtf;\n private _hrtfVoices;\n private _timeScalePitch;\n /** True when this host mixes sound. Everything below is a silent no-op otherwise. */\n get supported(): boolean;\n /** HRTF binaural rendering (MIT KEMAR filters on the CPU): sounds get a real up / down / behind in\n * HEADPHONES. Off by default — on speakers it only smears the image. Applies to the `hrtfVoices`\n * nearest 3D voices; the rest keep plain panning. A host built without the filters (an iOS App\n * Clip: they are 184 KB) keeps every voice on the panner — `stats.hrtfVoices` stays 0. */\n get hrtf(): boolean;\n set hrtf(v: boolean);\n /** `Time.scale` also pitches the sfx bus: slow motion drops every effect's tone, like a film. Default\n * false — a pause only mutes sfx, the menu click keeps its pitch. */\n get timeScalePitch(): boolean;\n set timeScalePitch(v: boolean);\n /** How many voices get the (CPU-heavier) binaural path. Default 16. */\n get hrtfVoices(): number;\n set hrtfVoices(n: number);\n /** A bus by name — the five built-ins, or an app-defined one created on first use. */\n bus(name: string): Bus;\n get master(): Bus;\n /** 2D playback (UI, stingers, music one-shots). */\n play(sound: Sound, options?: PlaySoundOptions): Voice;\n /** A one-shot at a world position with its own transient source — impacts, ricochets, debris.\n * The source is freed when the voice ends. */\n playAt(sound: Sound, position: Vec3Like, options?: PlaySoundOptions & SpatialOptions): Voice;\n /** Stop every voice on every bus (fade in seconds). */\n stopAll(fade?: number): void;\n /** Engine counters for a debug overlay or a perf log. */\n get stats(): AudioStats;\n}\nexport declare const audio: AudioSystem;\nexport type { AudioSystem };\n","types/audio/Bus.d.ts":"export type ReverbPreset = \"room\" | \"hall\" | \"cave\" | \"arena\" | \"bathroom\" | \"outdoor\";\nexport type ReverbParams = {\n /** 0 (a closet) … 1 (a cathedral). */\n roomSize?: number;\n /** High-frequency loss per reflection, 0 … 1. */\n damping?: number;\n /** Stereo width of the tail, 0 … 1. */\n width?: number;\n /** Wet amount, 0 … 1. */\n mix?: number;\n /** Seconds before the tail starts (a big hall: 0.02 … 0.05). */\n preDelay?: number;\n};\nexport type EchoParams = {\n /** Seconds between repeats (up to 2). */\n delay?: number;\n /** Feedback, 0 … 0.95 — how many repeats survive. */\n decay?: number;\n /** Wet amount, 0 … 1. */\n mix?: number;\n};\nexport declare const REVERB_PRESETS: Record<ReverbPreset, Required<ReverbParams>>;\nexport declare class Bus {\n readonly name: string;\n private _volume;\n private _muted;\n private _reverb;\n private _echo;\n private _lowpass;\n private get _live();\n get volume(): number;\n set volume(v: number);\n get muted(): boolean;\n set muted(v: boolean);\n /** A preset name, explicit params, or null (off). */\n get reverb(): ReverbPreset | ReverbParams | null;\n set reverb(v: ReverbPreset | ReverbParams | null);\n get echo(): EchoParams | null;\n set echo(v: EchoParams | null);\n /** Low-pass cutoff in Hz (20 … 20000), null = off. */\n get lowpass(): number | null;\n set lowpass(v: number | null);\n /** Stop every voice on this bus (fade in seconds). */\n stopAll(fade?: number): void;\n}\n","types/audio/Sound.d.ts":"export type SoundOptions = {\n /** Keep two channels (2D playback of stereo material — music beds, ambiences). Default: the clip\n * is decoded MONO, which is what 3D spatialization needs and what SFX are anyway. */\n stereo?: boolean;\n};\nexport declare class Sound {\n /** The urls this clip was loaded from (one per variant). */\n readonly urls: readonly string[];\n private readonly _durations;\n private _channels;\n private _disposed;\n private _last;\n private constructor();\n /** Fetch + decode. An array = variants: `play` picks a random one (never the same twice in a row\n * when there are 3 or more). Rejects with the failing url when a file cannot be decoded. */\n static load(src: string | string[], options?: SoundOptions): Promise<Sound>;\n /** Seconds (the first variant's). 0 for a silent clip. */\n get duration(): number;\n /** Decoded channel count: 1, or 2 with `{ stereo: true }`. */\n get channels(): number;\n /** How many variants this clip carries. */\n get variants(): number;\n /** True when the engine has this clip (false on hosts without audio, or after dispose). */\n get ready(): boolean;\n get disposed(): boolean;\n /** Free the engine's PCM. Voices playing it stop at once. Idempotent. */\n dispose(): void;\n}\n","types/audio/support.d.ts":"export declare const audioSupported: boolean;\n","types/audio/Voice.d.ts":"import { Emitter } from \"../core/events\";\nexport type VoiceEvents = {\n /** The voice is over: the clip ended, `stop` completed, or the pool reused the slot. */\n ended: () => void;\n};\nexport declare class Voice extends Emitter<VoiceEvents> {\n private _volume;\n private _pitch;\n private _pan;\n private _over;\n addEventListener<K extends keyof VoiceEvents>(channel: K, callback: VoiceEvents[K]): void;\n /** True while the engine plays this voice. */\n get playing(): boolean;\n /** Seconds into the clip. */\n get time(): number;\n get volume(): number;\n set volume(v: number);\n get pitch(): number;\n set pitch(v: number);\n /** 2D voices only: -1 left … 1 right. */\n get pan(): number;\n set pan(v: number);\n /** Stop now, or fade out over `fade` seconds. `ended` fires from the engine afterwards. */\n stop(options?: {\n fade?: number;\n }): void;\n}\n","types/canvas/Canvas.d.ts":"import { Texture2D } from \"../g2/Texture2D\";\nimport { File, type FetchResponse } from \"../runtime/fetch\";\nimport type { SvgSourceValue } from \"../runtime/misc\";\nimport { Recorder, Gradient, type ImageRef, type TextAlignName, type TextBaselineName, type LineJoinName, type LineCapName, type FillRuleName } from \"./gen/recorder\";\nexport { Gradient };\nexport type TextAlign = TextAlignName;\nexport type TextBaseline = TextBaselineName;\nexport type LineJoin = LineJoinName;\nexport type LineCap = LineCapName;\nexport type FillRule = FillRuleName;\nexport interface CanvasTextMetrics {\n width: number;\n ascent: number;\n descent: number;\n}\nexport declare class Canvas extends Recorder {\n /** Brand so `Sprite`/`UIImage`/`Material` can accept a Canvas anywhere a texture source is expected. */\n readonly __canvas: true;\n width: number;\n height: number;\n /** Device-pixel multiplier (draw at 2 for crisp retina text). Applied by the backend. */\n pixelRatio: number;\n private _drawn?;\n private _tex2d?;\n private _uiBound;\n private _lastBakeLen;\n private _warnedGrowth;\n constructor(width: number, height: number, opts?: {\n pixelRatio?: number;\n });\n /** Change the surface size; takes effect on the next bake. */\n resize(width: number, height: number): this;\n /** Blit a `Bitmap` (a snapshot from `toBitmap()` or `loadImage()`) onto this canvas. All coordinates\n * are LOGICAL — including the source sub-rect in the 9-arg form (it's scaled by the bitmap's\n * pixelRatio here). Records a DRAW_IMAGE op, so the blit runs at bake time; the canvas keeps the\n * Bitmap alive until `reset()` removes the op. Three browser-style forms:\n * drawImage(bmp, dx, dy) — whole bitmap at its natural size\n * drawImage(bmp, dx, dy, dw, dh) — whole bitmap, scaled into dw×dh\n * drawImage(bmp, sx, sy, sw, sh, dx, dy, dw, dh) — a sub-rect of the bitmap, scaled into dw×dh */\n drawImage(img: Bitmap | ImageRef, dx: number, dy: number): this;\n drawImage(img: Bitmap | ImageRef, dx: number, dy: number, dw: number, dh: number): this;\n drawImage(img: Bitmap | ImageRef, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): this;\n /** Decode an image source into a standalone `Bitmap` you can blit with `drawImage()` — either an\n * `SvgSource(...)` (drawn by the core, painted by the host) or a `FetchResponse` holding already-fetched\n * image bytes (decoded; an SVG file is detected). This is async because the web host decodes with the\n * browser; `await` it ONCE, then `drawImage(bitmap, …)` is synchronous and the Bitmap is reusable. The\n * returned Bitmap owns a native surface at the image's natural pixel size (`pixelRatio` 1), freed\n * once nothing references the Bitmap (`destroy()` frees it early). Typical use:\n * const logo = await canvas.loadImage(SvgSource(svg)) // or: await fetch(url) → the response\n * canvas.drawImage(logo, 0, 0) // sync, blit as often as you like */\n loadImage(source: SvgSourceValue | FetchResponse): Promise<Bitmap>;\n /** Measure `text` in the current font and letterSpacing on THIS platform. The one synchronous\n * round-trip. */\n measureText(text: string): CanvasTextMetrics;\n /** Discard the recording (and the Bitmaps its drawImage ops kept alive). */\n reset(): this;\n /** Bake and return the 2D texture (created once, then cached). */\n texture(): Texture2D;\n /** Re-rasterize and re-upload to every texture this canvas produced (call after redrawing) — the\n * cached 2D and/or 3D texture, whichever engines this canvas was baked into. */\n update(): this;\n /** Copy the current pixels into a standalone, immutable `Bitmap` — independent of this canvas, so\n * later drawing/`reset()` never touches it. Draw it back with `drawImage()`, export it with\n * `toFile()`, or use it to \"flatten\" an ever-growing drawing so re-bakes stay O(1):\n * const next = canvas.toBitmap() // bakes with the previous snapshot still alive\n * canvas.reset(); canvas.drawImage(next, 0, 0) // one op replaces the whole history\n * The canvas keeps a drawn Bitmap alive while its drawImage is recorded, and the old snapshot goes\n * on its own once reset() dropped it — no destroy() needed. */\n toBitmap(): Bitmap;\n /** Encode the current pixels to an image `File` — 'image/png' (default) or 'image/jpeg'. The File\n * is an opaque host buffer handle (`name`/`size` only): append it to a FormData to upload, load it\n * as a texture (`Texture2D.load(file)`), or hand it to a share/save sheet. */\n toFile(name?: string, type?: string): Promise<File>;\n /** Free the surface now instead of when the canvas is dropped (an image still showing it goes blank).\n * The recording stays: a later bake makes a new surface. */\n destroy(): void;\n}\n/** Duck-type guard so consumers can accept a Canvas anywhere a texture source is expected. */\nexport declare const isCanvas: (v: unknown) => v is Canvas;\n/** An immutable RGBA8 snapshot of a canvas, produced by `Canvas.toBitmap()` / `loadImage()`. It owns its\n * own baked surface (a copy), so the source canvas can keep drawing or `reset()` without affecting it.\n * Use it to stamp/blit back (`canvas.drawImage(bitmap, …)`), to export (`bitmap.toFile()`), or as a\n * cheap \"layer\" you composite. Its surface is freed once nothing references the Bitmap (a canvas that\n * drew it keeps it until `reset()`); `destroy()` frees it early. */\nexport declare class Bitmap {\n readonly __bitmap: true;\n /** Logical width, matching the Canvas it was captured from (pixelRatio is crispness, not size). */\n readonly width: number;\n readonly height: number;\n readonly pixelRatio: number;\n constructor(surface: Handle | number | null, width: number, height: number, pixelRatio: number);\n /** Device-pixel dimensions of the stored bitmap (`width * pixelRatio`, rounded). */\n get pixelWidth(): number;\n get pixelHeight(): number;\n /** Encode to an image `File` — 'image/png' (default) or 'image/jpeg'. See `Canvas.toFile`. */\n toFile(name?: string, type?: string): Promise<File>;\n /** Free the native surface now instead of when the bitmap is dropped. It must not be drawn or encoded\n * afterwards (a canvas whose recording still draws it blits nothing). */\n destroy(): void;\n}\n/** Duck-type guard for a Bitmap (see `isCanvas`). */\nexport declare const isBitmap: (v: unknown) => v is Bitmap;\n","types/canvas/gen/cssColor.d.ts":"/** A color: straight float32 RGBA, 0..1. */\nexport interface CssRgba {\n r: number;\n g: number;\n b: number;\n a: number;\n}\n/** The named colors as 0xRRGGBBAA: the 148 CSS Color 4 names, transparent and clear (= transparent). */\nexport declare const CSS_COLOR_NAMES: Readonly<Record<string, number>>;\n/** A CSS color → straight float32 RGBA, or null when `input` is not a color. */\nexport declare const parseCssColor: (input: string) => CssRgba | null;\n/** A float channel → a byte, as the header's toByte: float32, clamp (NaN → 0), round half up (0.5 → 128). */\nexport declare const cssToByte: (v: number) => number;\n/** 0xRRGGBBAA (unsigned). */\nexport declare const cssRgba8: (c: CssRgba) => number;\n/** '#rrggbbaa', lower-case. */\nexport declare const cssHex8: (c: CssRgba) => string;\n","types/canvas/gen/recorder.d.ts":"export type FillRuleName = \"nonzero\" | \"evenodd\";\nexport type LineJoinName = \"miter\" | \"round\" | \"bevel\";\nexport type LineCapName = \"butt\" | \"round\" | \"square\";\nexport type TextAlignName = \"left\" | \"center\" | \"right\" | \"start\" | \"end\";\nexport type TextBaselineName = \"alphabetic\" | \"top\" | \"middle\" | \"bottom\" | \"hanging\" | \"ideographic\";\n/** A gradient built by createLinearGradient / createRadialGradient; assign it to fillStyle / strokeStyle. */\nexport declare class Gradient {\n readonly stops: {\n offset: number;\n color: string;\n }[];\n readonly kind: number;\n readonly coords: [number, number, number, number, number, number];\n addColorStop(offset: number, color: string): this;\n}\n/** The recorded stream: the f32 words and the string table the core reads. */\nexport interface Stream {\n cmd: Float32Array;\n refs: string[];\n}\n/** A surface with its device size, for the short drawImage forms. */\nexport interface ImageRef {\n surface: number;\n width: number;\n height: number;\n}\nexport declare class Recorder {\n private cmd;\n private refs;\n private refIndex;\n private _globalAlpha;\n private _fillStyle;\n private _strokeStyle;\n private _lineWidth;\n private _lineJoin;\n private _lineCap;\n private _miterLimit;\n private _lineDash;\n private _lineDashOffset;\n private _font;\n private _textAlign;\n private _textBaseline;\n private _letterSpacing;\n private _saved;\n /** The words recorded so far (a copy) + the string table. */\n stream(): Stream;\n /** Plain arrays, for a JSON file (the golden tests' input). */\n toJSON(): {\n cmd: number[];\n refs: string[];\n };\n /** The number of words recorded. */\n get length(): number;\n /** Discard the recording; the shadowed state is reset too (a fresh replay starts from defaults). */\n reset(): this;\n private ref;\n private push;\n save(): this;\n restore(): this;\n translate(x: number, y: number): this;\n scale(sx: number, sy: number): this;\n rotate(rad: number): this;\n transform(a: number, b: number, c: number, d: number, e: number, f: number): this;\n setTransform(a: number, b: number, c: number, d: number, e: number, f: number): this;\n resetTransform(): this;\n get globalAlpha(): number;\n set globalAlpha(a: number);\n get fillStyle(): string | Gradient;\n set fillStyle(v: string | Gradient);\n get strokeStyle(): string | Gradient;\n set strokeStyle(v: string | Gradient);\n private style;\n createLinearGradient(x0: number, y0: number, x1: number, y1: number): Gradient;\n createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): Gradient;\n get lineWidth(): number;\n set lineWidth(w: number);\n get lineJoin(): LineJoinName;\n set lineJoin(j: LineJoinName);\n get lineCap(): LineCapName;\n set lineCap(c: LineCapName);\n get miterLimit(): number;\n set miterLimit(m: number);\n setLineDash(segments: number[]): this;\n getLineDash(): number[];\n get lineDashOffset(): number;\n set lineDashOffset(o: number);\n get font(): string;\n set font(f: string);\n get textAlign(): TextAlignName;\n set textAlign(a: TextAlignName);\n get textBaseline(): TextBaselineName;\n set textBaseline(b: TextBaselineName);\n get letterSpacing(): number;\n set letterSpacing(px: number);\n beginPath(): this;\n closePath(): this;\n moveTo(x: number, y: number): this;\n lineTo(x: number, y: number): this;\n quadraticCurveTo(cx: number, cy: number, x: number, y: number): this;\n bezierCurveTo(c1x: number, c1y: number, c2x: number, c2y: number, x: number, y: number): this;\n arc(x: number, y: number, r: number, a0: number, a1: number, ccw?: boolean): this;\n arcTo(x1: number, y1: number, x2: number, y2: number, r: number): this;\n ellipse(x: number, y: number, rx: number, ry: number, rotation: number, a0: number, a1: number, ccw?: boolean): this;\n rect(x: number, y: number, w: number, h: number): this;\n roundRect(x: number, y: number, w: number, h: number, r: number): this;\n fill(rule?: FillRuleName): this;\n stroke(): this;\n clip(rule?: FillRuleName): this;\n fillRect(x: number, y: number, w: number, h: number): this;\n strokeRect(x: number, y: number, w: number, h: number): this;\n clearRect(x: number, y: number, w: number, h: number): this;\n fillText(text: string, x: number, y: number, maxWidth?: number): this;\n strokeText(text: string, x: number, y: number, maxWidth?: number): this;\n /** Blit a surface. Three browser-style forms; the source rect is in the surface's device px. */\n drawImage(img: ImageRef, dx: number, dy: number): this;\n drawImage(img: ImageRef, dx: number, dy: number, dw: number, dh: number): this;\n drawImage(img: ImageRef, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): this;\n}\n","types/canvas/gen/spec.d.ts":"export declare const SPEC_VERSION = 1;\nexport declare const LineJoin: {\n readonly MITER: 0;\n readonly ROUND: 1;\n readonly BEVEL: 2;\n};\nexport type LineJoin = (typeof LineJoin)[keyof typeof LineJoin];\nexport declare const LineJoinName: readonly string[];\nexport declare const LineCap: {\n readonly BUTT: 0;\n readonly ROUND: 1;\n readonly SQUARE: 2;\n};\nexport type LineCap = (typeof LineCap)[keyof typeof LineCap];\nexport declare const LineCapName: readonly string[];\nexport declare const TextAlign: {\n readonly LEFT: 0;\n readonly CENTER: 1;\n readonly RIGHT: 2;\n readonly START: 3;\n readonly END: 4;\n};\nexport type TextAlign = (typeof TextAlign)[keyof typeof TextAlign];\nexport declare const TextAlignName: readonly string[];\nexport declare const TextBaseline: {\n readonly ALPHABETIC: 0;\n readonly TOP: 1;\n readonly MIDDLE: 2;\n readonly BOTTOM: 3;\n readonly HANGING: 4;\n readonly IDEOGRAPHIC: 5;\n};\nexport type TextBaseline = (typeof TextBaseline)[keyof typeof TextBaseline];\nexport declare const TextBaselineName: readonly string[];\nexport declare const FillRule: {\n readonly NONZERO: 0;\n readonly EVENODD: 1;\n};\nexport type FillRule = (typeof FillRule)[keyof typeof FillRule];\nexport declare const FillRuleName: readonly string[];\nexport declare const Spread: {\n readonly PAD: 0;\n readonly REFLECT: 1;\n readonly REPEAT: 2;\n};\nexport type Spread = (typeof Spread)[keyof typeof Spread];\nexport declare const SpreadName: readonly string[];\nexport declare const Gradient: {\n readonly LINEAR: 0;\n readonly RADIAL: 1;\n};\nexport type Gradient = (typeof Gradient)[keyof typeof Gradient];\nexport declare const GradientName: readonly string[];\nexport declare const Paint: {\n readonly COLOR: 0;\n readonly LINEAR: 1;\n readonly RADIAL: 2;\n};\nexport type Paint = (typeof Paint)[keyof typeof Paint];\nexport declare const PaintName: readonly string[];\nexport declare const PathVerb: {\n readonly MOVE: 0;\n readonly LINE: 1;\n readonly QUAD: 2;\n readonly CUBIC: 3;\n readonly CLOSE: 4;\n};\nexport type PathVerb = (typeof PathVerb)[keyof typeof PathVerb];\nexport declare const PathVerbName: readonly string[];\nexport declare const ImageFormat: {\n readonly PNG: 0;\n readonly JPEG: 1;\n};\nexport type ImageFormat = (typeof ImageFormat)[keyof typeof ImageFormat];\nexport declare const ImageFormatName: readonly string[];\n/** The opcode stream: op id → the word after it. */\nexport declare const OP: {\n readonly SAVE: 0;\n readonly RESTORE: 1;\n readonly TRANSLATE: 2;\n readonly SCALE: 3;\n readonly ROTATE: 4;\n readonly TRANSFORM: 5;\n readonly SET_TRANSFORM: 6;\n readonly RESET_TRANSFORM: 7;\n readonly GLOBAL_ALPHA: 8;\n readonly FILL_STYLE: 9;\n readonly STROKE_STYLE: 10;\n readonly FILL_GRADIENT: 11;\n readonly STROKE_GRADIENT: 12;\n readonly LINE_WIDTH: 13;\n readonly LINE_JOIN: 14;\n readonly LINE_CAP: 15;\n readonly MITER_LIMIT: 16;\n readonly LINE_DASH: 17;\n readonly LINE_DASH_OFFSET: 18;\n readonly FONT: 19;\n readonly TEXT_ALIGN: 20;\n readonly TEXT_BASELINE: 21;\n readonly LETTER_SPACING: 22;\n readonly PATH_BEGIN: 23;\n readonly PATH_CLOSE: 24;\n readonly MOVE_TO: 25;\n readonly LINE_TO: 26;\n readonly QUADRATIC_TO: 27;\n readonly BEZIER_TO: 28;\n readonly ARC: 29;\n readonly ARC_TO: 30;\n readonly ELLIPSE: 31;\n readonly RECT: 32;\n readonly ROUND_RECT: 33;\n readonly FILL: 34;\n readonly STROKE: 35;\n readonly CLIP: 36;\n readonly FILL_RECT: 37;\n readonly STROKE_RECT: 38;\n readonly CLEAR_RECT: 39;\n readonly FILL_TEXT: 40;\n readonly STROKE_TEXT: 41;\n readonly DRAW_IMAGE: 42;\n};\nexport type OP = (typeof OP)[keyof typeof OP];\n/** Operand layout per op: `args` is one letter per fixed word (f float, i int, r string ref);\n * `repeat` is the group that follows the trailing count. */\nexport declare const OP_ARGS: Record<number, {\n args: string;\n repeat: string;\n}>;\nexport declare const OP_NAME: readonly string[];\n/** The draw list: command id → the word after it. */\nexport declare const DRAW: {\n readonly SET_TRANSFORM: 0;\n readonly SAVE: 1;\n readonly RESTORE: 2;\n readonly CLIP: 3;\n readonly FILL_PATH: 4;\n readonly STROKE_PATH: 5;\n readonly FILL_TEXT: 6;\n readonly STROKE_TEXT: 7;\n readonly DRAW_IMAGE: 8;\n readonly CLEAR_RECT: 9;\n};\nexport type DRAW = (typeof DRAW)[keyof typeof DRAW];\nexport declare const DRAW_NAME: readonly string[];\n","types/core/Aspect.d.ts":"import type { Scene } from \"../gl/Scene\";\nimport { Emitter, type EventMap } from \"./events\";\nimport type { InspectorUI } from \"./InspectorUI\";\nimport type { Node } from \"../gl/Node\";\n/** The class object of an aspect — accepted even when its constructor is protected/abstract. */\nexport type AspectCtor<A extends Aspect<any, any, any>> = abstract new () => A;\n/** The accessor name carried in the aspect's generic. */\nexport type KeyOf<A> = A extends Aspect<infer K, any, any> ? K : never;\n/** The node kind an aspect targets (the scene kind for a System). */\nexport type TargetOf<A> = A extends Aspect<any, infer P, any> ? P : never;\n/** `{ name: Aspect }` — the field an aspect contributes to its node. */\nexport type FieldOf<A extends Aspect<any, any, any>> = {\n [P in KeyOf<A>]: A;\n};\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n/**\n * A variable typed as a node KNOWN to carry the given aspect(s). Union, not a tuple — reads as\n * English and mirrors the runtime guard `node.has(Health)`:\n * let boss: With<Sprite, Health | Physics>\n */\nexport type With<N, A extends Aspect<any, any, any>> = N & UnionToIntersection<A extends any ? FieldOf<A> : never>;\n/**\n * Base for anything that can carry aspects. Extends Emitter, so node kinds get events too. Provides\n * the four verbs; the named accessor (node.physics, node.health, …) is set as an own property at\n * attach time, keyed by the aspect class's runtime `aspect` name.\n */\nexport declare abstract class AspectHost<E extends EventMap = EventMap> extends Emitter<E> {\n /** Attach (and configure) an aspect, or reconfigure it if already present. Returns the node typed\n * as now-having that aspect (so no guard/`?.` is needed afterwards). Rejects a wrong target node. */\n aspect<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;\n /** Safe access — undefined if the aspect isn't attached. */\n get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;\n /** Existence check AND type guard: inside `if (node.has(Physics))`, `node.physics` is present. */\n has<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this is this & FieldOf<A>;\n /** Detach an aspect (runs its onDetach). Named `removeAspect` so it never collides with the\n * child-management `add`/`remove` semantics some node kinds expose. */\n removeAspect<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this;\n}\n/**\n * Base for everything you attach. `K` = accessor name (extracted by chisel for the runtime). `P` =\n * the target node kind: `this.node` is typed to it, AND attaching to a wrong node is a compile error.\n * `E` = the events this aspect emits (`{ explode: (b: Barrel) => void }`): `this.emit('explode', …)`\n * inside, `node.barrel.on('explode', fn)` outside.\n * Initialize in `onAttach` (the node is set by then) — not a constructor; aspects are created by the\n * engine via `node.aspect()`, never `new`.\n */\nexport declare abstract class Aspect<K extends string, P = Node, E extends EventMap = {}> {\n /**\n * Opt this aspect class into EDITOR-RUN mode (generators): while a scene is edited, the scene\n * loader constructs the instance (refs resolved, `node`/`generated` set — never `onAttach`) and\n * calls `rebuild()` — again on inspector prop edits and when a `ref()`-referenced node moves.\n * `static editor = { rebuild: true }`.\n */\n static editor?: {\n rebuild?: boolean;\n };\n /**\n * Custom inspector card for this aspect in the scene editor (immediate-mode — see\n * core/InspectorUI.ts): re-runs on every edit/event and emits a widget list. Without it, the\n * editor shows the inferred fields; `ui.auto()` emits those same fields, so a custom inspector\n * usually starts with `ui.auto()` and appends status lines / buttons / dynamic dropdowns:\n *\n * static inspector(ui: InspectorUI, self: MyAspect) {\n * ui.auto()\n * if (ui.button('Randomize')) self.rebuild()\n * }\n */\n static inspector?: (ui: InspectorUI, aspect: any) => void;\n /** Tick AFTER these classes within the same phase (`static after = [Controls]`). A constraint\n * always beats the numeric `updateOrder`. Classes absent from the phase are ignored. */\n static after?: Function[];\n /** Tick BEFORE these classes within the same phase (`static before = [Camera]`). */\n static before?: Function[];\n /** Every live instance of an aspect/system class, in attach order — the registry a game used to\n * hand-roll as `static all[]`. Live, read-only: copy it (`[...Aspect.all(Barrel)]`) before a loop\n * that detaches. Empty in the scene editor (aspects are inert data there). */\n static all<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): readonly A[];\n /** The node this aspect is attached to (set at attach time). For a System: the scene. */\n readonly node: P;\n /**\n * GENERATOR aspects (`static editor = { rebuild: true }`, attached through a scene file): a\n * scene-added container child for the aspect's generated output — `rebuild()` clears and refills\n * it. Provided by the scene loader before `onAttach`/`rebuild` run; nodes `add()`ed to it join\n * the scene's draw set automatically (membership is separate from parenting). Undefined for\n * aspects attached by hand outside scene files. See docs/3d/scene-files.md.\n */\n readonly generated: Node & {\n clear(): void;\n readonly version: number;\n };\n /**\n * GENERATOR aspects attached through a scene file: the `Scene` the host node was built into —\n * what `handle.instantiate({ scene })` / `scene.add()` need inside `rebuild()`. Set by the scene\n * loader (edit AND play mode); undefined for aspects attached by hand. 3D only (2D aspects own\n * their `scene` field). For a System: always set — the scene it is attached to.\n */\n readonly scene: P extends Node ? Scene : P extends SystemHost ? P : unknown;\n protected readonly __key__?: K;\n protected readonly __events__?: E;\n private _listeners?;\n /** The node (or scene) is set — initialize here, not in a constructor. */\n protected onAttach?(): void;\n /** Release what onAttach acquired. */\n protected onDetach?(): void;\n /** Called after `node.aspect(Ctor, opts)` re-assigns options on an ALREADY attached aspect (a\n * pre-attached one like `model.anim`): rebuild whatever was derived from the options at attach. */\n protected onReconfigure?(): void;\n /**\n * GENERATOR aspects: (re)build the derived output under `this.generated` — must be idempotent\n * (clear, then create). Call it from `onAttach()` for play mode; a class opting in with\n * `static editor = { rebuild: true }` ALSO runs it while a scene is being edited: once at load,\n * and again whenever an inspector prop changes or a `ref()`-referenced node moves.\n */\n rebuild?(): void;\n /**\n * LATE phase — every frame while attached, after the physics step + transform sync + animators,\n * right before the frame draws: reads of `node.worldPosition` are the final drawn position\n * (cameras/followers have no 1-frame lag) and what you write to a plain node is what this frame\n * shows. The default home for game logic. `dt` = GAME seconds since the last frame (`Time.scale`\n * applied; 0 while paused — see `updateWhilePaused`).\n */\n protected update?(dt: number): void;\n /**\n * EARLY phase — every frame BEFORE the physics step, so what you feed the simulation (velocity,\n * `controller.move()`, forces, kinematic transforms) is consumed by this same frame's step: zero\n * input latency. Use it only when you FEED the simulation. Reads here see last frame's settled\n * state. A class rarely needs both phases — that is two aspects on one node.\n */\n protected updateBefore?(dt: number): void;\n /**\n * FIXED phase - once per physics substep, BEFORE that substep's Jolt step, with `dt = Time.fixedDt`\n * (1/60) exactly, on every machine: under `Time.scale` the NUMBER of steps per frame changes, never\n * the dt (0-4 calls per frame). The home of simulation that must match another machine's - a\n * multiplayer player sim, dt-dependent motion that may not drift with the frame rate. `controller.move()`\n * / velocity writes here feed the same step; between steps the world is consistent, so `Physics.raycast`\n * is fine. Anything that looks at the screen (cameras, HUD, FX) stays in `updateBefore` / `update`.\n */\n protected updateFixed?(dt: number): void;\n /** Tick order within a phase and rank — ascending; default 0, ties keep attach order. A declared\n * `static after` / `static before` constraint always beats this number. Read once, at attach —\n * set it as a class field. */\n protected updateOrder: number;\n /** Keep ticking while `Time.paused` (a HUD fade, the pause menu). `dt` is still 0 then — read\n * `Time.unscaledDt` for wall-clock motion. Checked every frame; may be toggled at any time. */\n protected updateWhilePaused: boolean;\n /** Opt-in: only run update(dt) while the node is on-screen. NOOP for now — visibility culling isn't\n * wired yet, so every updater ticks regardless; declared so aspects can opt in ahead of it. */\n protected updateWhenVisible: boolean;\n /** Listen to one of this aspect's events. Chainable. Cleared on detach. */\n on<C extends keyof E & string>(channel: C, callback: E[C]): this;\n /** Remove a listener added with `on` (same function reference). */\n off<C extends keyof E & string>(channel: C, callback: E[C]): this;\n /** Fire one of this aspect's events. Protected: only the aspect itself emits. */\n protected emit<C extends keyof E & string>(channel: C, ...args: Parameters<E[C]>): void;\n}\n/**\n * An aspect of a SCENE: game logic with no single node to live on — input mapping, the FX pools, the\n * HUD, the game mode. Same lifecycle (`onAttach`/`onDetach`), same phases (`updateFixed` / `updateBefore` /\n * `update`), same ordering (`updateOrder`, `static after`) and events as a node aspect; `this.scene` is the\n * scene it was attached to. `S` = the scene kind (`Scene` by default, `Scene2D` for 2D games).\n *\n * class Hud extends System<'hud'> {\n * static after = [Player]\n * update(dt: number) { … }\n * }\n * scene.system(Hud) // attach\n * scene.hud // the typed accessor\n */\nexport declare abstract class System<K extends string, S extends SystemHost = Scene, E extends EventMap = {}> extends Aspect<K, S, E> {\n}\nexport {};\n","types/core/color.d.ts":"export type ColorInput = string | number | readonly [number, number, number] | readonly [number, number, number, number];\nexport declare const Color: {\n /** [r,g,b] in 0..1 — for the 2D engine's float color setters. */\n toRgb01(c: ColorInput): [number, number, number];\n /** [r,g,b,a] in 0..1. */\n toRgba01(c: ColorInput): [number, number, number, number];\n /** 0xRRGGBB packed int — for the 3D engine's color uniforms / skybox. */\n toPackedRgb(c: ColorInput): number;\n /** 0xRRGGBBAA packed int (unsigned). */\n toPackedRgba(c: ColorInput): number;\n /** '#rrggbbaa' (lower-case, always eight digits) — the UI wire form and the 3D material color. */\n toHexString(c: ColorInput): string;\n /** [r,g,b,a] in 0..1, or `null` when `c` is not a color — the non-throwing probe. */\n tryParse(c: unknown): [number, number, number, number] | null;\n};\n","types/core/compWrite.d.ts":"export type CompAxis = \"x\" | \"y\" | \"z\" | \"w\";\n/** Implemented by a class whose vector getters accept component writes (see above). The class also\n * carries `static _comps: string[]` naming those getters — compile-time data, absent at runtime. */\nexport interface CompWriter {\n _writeComp(prop: string, axis: CompAxis, value: number): void;\n}\n/** `<o>.<prop>.<axis> = value`, routed to the owner when it has the hook. Returns the value. */\nexport declare const __compWrite: (o: any, prop: string, axis: CompAxis, value: number) => number;\n/** `<o>.<prop>.<axis> op= v` — `op`: 0 `+=`, 1 `-=`, 2 `*=`, 3 `/=`. The current component is read\n * through the normal getter (one fresh vector), the result written like `__compWrite`. */\nexport declare const __compOp: (o: any, prop: string, axis: CompAxis, op: number, v: number) => number;\n","types/core/events.d.ts":"export type EventMap = Record<string, (...args: any[]) => void>;\nexport declare class Emitter<E extends EventMap> {\n private _listeners;\n addEventListener<K extends keyof E>(channel: K, callback: E[K]): void;\n removeEventListener<K extends keyof E>(channel: K, callback: E[K]): void;\n /** Fire all listeners on a channel. Protected: only the owning class emits. */\n protected dispatch<K extends keyof E>(channel: K, ...args: Parameters<E[K]>): void;\n protected hasListeners<K extends keyof E>(channel: K): boolean;\n /** Drop every listener on every channel (used when the owning object is disposed). */\n protected clearListeners(): void;\n}\n","types/core/fields.d.ts":"/** Editor widget kinds the inspector knows how to render. `\"node\"` = a scene-node reference\n * (`ref('name')` in the file, name dropdown + pick-in-viewport in the inspector) — declare it via\n * `static fields` on fields typed `Node | null`; a `Node | null` type annotation is also picked\n * up syntactically by the editor's source scan. `\"asset\"` = a project-asset path (the editor\n * fills the dropdown with the project's GLBs — `ui.asset()` in windows/tools/cards). */\nexport type FieldEditor = \"number\" | \"text\" | \"color\" | \"switch\" | \"select\" | \"vec2\" | \"vec3\" | \"vec4\" | \"node\" | \"asset\";\nexport type FieldMetaEntry = {\n /** Inspector label (default: the field name). */\n label?: string;\n min?: number;\n max?: number;\n step?: number;\n /** Allowed values — renders a dropdown (editor \"select\"). */\n options?: readonly (string | number)[];\n /** Override the editor inferred from the default value. */\n editor?: FieldEditor;\n /** Exclude the field from the inspector. */\n hidden?: boolean;\n};\n/** Declared on an aspect class as `static fields: FieldMeta<MyAspect> = { … }`. All optional. */\nexport type FieldMeta<T = unknown> = {\n [K in Extract<keyof T, string>]?: FieldMetaEntry;\n};\n/** One editable field: key + default value + resolved editor + merged metadata. */\nexport type FieldDescriptor = {\n key: string;\n label: string;\n /** The default value (from a freshly constructed instance; undefined if only declared in meta). */\n value: unknown;\n /** Resolved editor kind; undefined = no editor known (inspector shows it read-only). */\n editor: FieldEditor | undefined;\n min?: number;\n max?: number;\n step?: number;\n options?: readonly (string | number)[];\n};\nexport type AspectClassInfo = {\n /** The accessor name (`static aspect`, injected by chisel for user aspects). */\n name: string;\n className: string;\n fields: FieldDescriptor[];\n /** True for editor-run classes (`static editor` — generators). The editor routes their\n * structural changes through a re-run instead of a live patch. */\n editor?: boolean;\n /** True when the class declares a custom `static inspector(ui, aspect)` card. */\n inspector?: boolean;\n};\n/** Infer the editor widget from a default value's shape. */\nexport declare const inferFieldEditor: (value: unknown) => FieldEditor | undefined;\n/**\n * Enumerate the editable fields of a class: construct a default instance, take its own enumerable\n * non-underscore fields (minus the Aspect base plumbing), infer editors from the default values, and\n * merge the class's optional `static fields` metadata (which can also add keys that have no runtime\n * default, e.g. fields declared without an initializer).\n */\nexport declare const describeFields: (ctor: abstract new () => unknown) => FieldDescriptor[];\n/** Describe an aspect class for the inspector: accessor name + class name + editable fields. */\nexport declare const describeAspect: (ctor: abstract new () => unknown) => AspectClassInfo;\n","types/core/InspectorUI.d.ts":"import type { FieldEditor } from \"./fields\";\n/** One user interaction coming back from the editor panel: the widget's id (+ value for fields). */\nexport type InspectorEvent = {\n id: string;\n value?: unknown;\n};\nexport type InspectorFieldWidget = {\n kind: \"field\";\n id: string;\n /** The bound key — an aspect field (doc-bound) or an editor-state key. */\n key: string;\n label: string;\n editor: FieldEditor | undefined;\n value: unknown;\n /** True = persisted to the scene file by the editor; false = transient editor state. */\n doc: boolean;\n /** True = emitted by `ui.auto()` — the editor may overlay its syntactic hints (options/node). */\n auto?: boolean;\n min?: number;\n max?: number;\n step?: number;\n options?: readonly (string | number)[];\n};\nexport type InspectorWidget = InspectorFieldWidget | {\n kind: \"button\";\n id: string;\n label: string;\n} | {\n kind: \"toolButton\";\n id: string;\n label: string;\n tool: string;\n} | {\n kind: \"header\";\n id: string;\n label: string;\n} | {\n kind: \"info\" | \"warn\";\n id: string;\n text: string;\n};\ntype FieldOpts = {\n label?: string;\n min?: number;\n max?: number;\n step?: number;\n /** Default for EDITOR-STATE keys (doc keys default from the class field). */\n value?: unknown;\n};\n/**\n * The widget builder handed to `static inspector(ui, aspect)` (and to editor windows/tools later).\n * One instance lives per card and persists across runs — it carries the card's editor state.\n */\nexport declare class InspectorUI {\n /** Numeric field (min/max/step render as a slider-style scrub range). */\n number(key: string, opts?: FieldOpts): number;\n /** Alias of `number` — give it min/max/step and the editor renders a scrubable range. */\n slider(key: string, opts?: FieldOpts): number;\n text(key: string, opts?: FieldOpts): string;\n color(key: string, opts?: FieldOpts): string;\n switch(key: string, opts?: FieldOpts): boolean;\n /** Dropdown — `options` may be computed fresh every run (dynamic lists come free). */\n select(key: string, options: readonly (string | number)[], opts?: FieldOpts): string | number;\n vec2(key: string, opts?: FieldOpts): [number, number];\n vec3(key: string, opts?: FieldOpts): [number, number, number];\n vec4(key: string, opts?: FieldOpts): [number, number, number, number];\n /** Scene-node reference (`ref()` fields): name dropdown + pick-in-viewport. Returns the RAW doc\n * value (`{ $ref }` marker or null) — read the resolved live node off the aspect instance. */\n node(key: string, opts?: FieldOpts): unknown;\n /** Project-asset path (the editor renders a dropdown of the project's GLBs). \"\" = none picked. */\n asset(key: string, opts?: FieldOpts): string;\n /** True on the run that consumes this button's click — do the action right there. */\n button(label: string, opts?: {\n id?: string;\n }): boolean;\n /** A toggle that activates/deactivates the named viewport tool (`registerEditorTool`). The\n * editor owns the active-tool state — the click never round-trips into the scene world. */\n toolButton(label: string, tool: string): void;\n header(label: string): void;\n info(text: string): void;\n warn(text: string): void;\n /** Emit the inferred field widgets (all declared aspect fields, or just the named ones) — the\n * zero-ceremony baseline; append custom widgets around it. */\n auto(...keys: string[]): void;\n private _vec;\n private _field;\n}\nexport {};\n","types/core/pins.d.ts":"/** The handle of a wrapper whose resource is gone: `id` 0, nothing to finalize. Replacing `_h`\n * with it drops the real handle, so the runtime's record can go. */\nexport declare const DEAD_HANDLE: Handle;\nexport interface Pinned {\n readonly _h: Handle;\n /** The runtime freed the resource underneath (an ancestor's free): mark the wrapper dead. */\n _freed?(): void;\n}\nexport declare class Pins<T extends Pinned> {\n private readonly map;\n /** Keep `obj` alive and findable while native owns its resource. */\n pin(obj: T | null | undefined): void;\n unpin(id: number): void;\n get(id: number): T | undefined;\n has(id: number): boolean;\n /** The runtime freed these resources: drop the pins, tell the wrappers. */\n freed(ids: number[]): void;\n}\n","types/core/signals.d.ts":"/** Runs every pending effect now instead of waiting for the microtask (test/host hook). */\nexport declare const flushEffects: () => void;\nexport interface Signal<T> {\n value: T;\n /** Read without subscribing the current effect/computed. */\n peek(): T;\n}\nexport interface Computed<T> {\n readonly value: T;\n /** Read without subscribing the current effect/computed (still recomputes if stale). */\n peek(): T;\n}\n/**\n * A reactive value. Reading `.value` inside an `effect`/`computed` (or a function-valued style\n * prop / `UIText` content) subscribes it; writing `.value` re-runs subscribers (batched — once\n * per microtask).\n */\nexport declare function signal<T>(initialValue: T): Signal<T>;\nexport declare function signal<T = undefined>(): Signal<T | undefined>;\n/** A lazily-cached derived value: recomputes on read after any of its dependencies changed. */\nexport declare function computed<T>(fn: () => T): Computed<T>;\n/**\n * Runs `fn` now and again whenever any signal/computed it read changes (batched per microtask).\n * Returns a dispose function; an undisposed effect lives for the rest of the app run.\n */\nexport declare function effect(fn: () => void): () => void;\n/** The shape UINode's Element exposes for binding ownership. */\nexport interface BindingHost {\n}\n","types/core/StateMachine.d.ts":"export type StateGuard<C> = (ctx: C, t: number) => boolean;\nexport type StateHandler<C> = (ctx: C, ...args: any[]) => string | void;\nexport interface StateDef<C> {\n /** The child entered by default when this (compound) state is entered. */\n initial?: string;\n /** Child states — this becomes a compound state; only a leaf is ever \"the\" state. */\n states?: Record<string, StateDef<C>>;\n /** Entered (from = the previous leaf's path, '' at start). */\n enter?: (ctx: C, from: string) => void;\n /** Left (to = the next leaf's path). */\n exit?: (ctx: C, to: string) => void;\n /** Every step while active, outer states first; `t` = seconds in this state. Return a state name\n * to transition. */\n update?: (ctx: C, dt: number, t: number) => string | void;\n /** Guarded transitions, tested every step before `update` — key = target, first true wins. */\n to?: Record<string, StateGuard<C>>;\n /** Leave for `target` after `seconds` in this state. */\n after?: [seconds: number, target: string];\n /** Event handlers for `send(name, …args)`: a target name, or a function returning one (or nothing). */\n on?: Record<string, string | StateHandler<C>>;\n}\nexport interface StatesDef<C> {\n initial: string;\n states: Record<string, StateDef<C>>;\n /** Any-state guards — tested first, in every state. */\n to?: Record<string, StateGuard<C>>;\n /** Any-state event handlers — the fallback when no active state handles the event. */\n on?: Record<string, string | StateHandler<C>>;\n /** Any-state update, runs before the active states' own. */\n update?: (ctx: C, dt: number, t: number) => string | void;\n}\nexport type StateMachineEvents = {\n /** After a transition completed (both are leaf paths; `from` = '' for the initial entry). */\n change: (to: string, from: string) => void;\n};\n/** Identity helper — names the context type once so every callback is typed. */\nexport declare const defineStates: <C>(def: StatesDef<C>) => StatesDef<C>;\nexport declare class StateMachine<C> {\n readonly ctx: C;\n private readonly root;\n private readonly byPath;\n /** the active branch, root's child (index 0) → leaf */\n private chain;\n private prev;\n private listeners;\n private changed;\n constructor(def: StatesDef<C>, ctx: C);\n /** The active leaf's path ('combat.shoot'). */\n get state(): string;\n /** The leaf we came from ('' before the first transition). */\n get previous(): string;\n /** Seconds in the active leaf. */\n get time(): number;\n /** Every active state's path, outermost first. */\n get branch(): string[];\n /** Is `name` (a state name or dotted path) active — as the leaf OR as one of its ancestors? */\n is(name: string): boolean;\n /** Seconds in the named active state (0 when it is not active). */\n timeIn(name: string): number;\n /** Force a transition (a spawn, a reset from outside the table). */\n go(name: string): void;\n /** Deliver an event. Innermost active state first, the root's `on` last. True if handled. */\n send(event: string, ...args: unknown[]): boolean;\n /** One tick: clocks, guards (outer first, chained), then updates (outer first). */\n step(dt: number): void;\n /** Listen for transitions. */\n on(event: \"change\", fn: StateMachineEvents[\"change\"]): this;\n off(event: \"change\", fn: StateMachineEvents[\"change\"]): this;\n private build;\n private link;\n private resolveStrict;\n /** Relative first (siblings of `from`, then of each ancestor), then a dotted path from the root. */\n private resolve;\n /** Guards never re-enter a state that is already active (a `dead` guard staying true does not\n * re-enter `dead` every step) — only an explicit `go()` / event does that. */\n private findTransition;\n private active;\n private leafOf;\n private transition;\n private enterBranch;\n}\n","types/core/time.d.ts":"declare class TimeClock {\n private _scale;\n private _paused;\n /** The fixed step: what `updateFixed(dt)` receives, every time, on every machine (1/60). Under\n * `scale` the NUMBER of fixed steps per frame changes, never this value. */\n readonly fixedDt: number;\n /** Seconds of GAME time since the app started (scaled; stops while paused). */\n now: number;\n /** Seconds of wall-clock time since the app started (never stops). */\n unscaledNow: number;\n /** This frame's delta in game seconds — what `update(dt)` receives. 0 while paused. */\n dt: number;\n /** This frame's wall-clock delta in seconds (the host's frame time, clamped by the engine). */\n unscaledDt: number;\n /** Frames dispatched since the app started (counts paused frames too). */\n frame: number;\n /** Speed of the game relative to wall-clock: 1 normal, 0.5 half speed, 2 double. Applied to\n * `dt`, `now` AND the engines' physics / animation / particle clocks. Negative or NaN → 0. */\n get scale(): number;\n set scale(v: number);\n /** Freeze the game: `dt` reads 0, aspects without `updateWhilePaused` are skipped, the engines'\n * simulations stop. `scale` is remembered and restored on resume. */\n get paused(): boolean;\n set paused(v: boolean);\n /** The scale the engines currently run at (0 while paused). */\n get effectiveScale(): number;\n private _push;\n}\n/** The game clock — scale / pause the whole game, read `dt` / `now` anywhere. */\nexport declare const Time: TimeClock;\nexport {};\n","types/g2/autotile.d.ts":"/** A fill entry: an atlas index, or [index, weight] for seeded scatter variants. */\nexport type FillEntry = number | [number, number];\nexport type Dir4 = [number, number, number, number];\n/** One side's tiles: a single index (used for every cell along that side), or — with `size` > 1 —\n * the `size` indices ALONG it (n/s run left→right, w/e run top→bottom). */\nexport type EdgeSlot = number | number[];\n/** A whole `size`×`size` piece: one index (drawn in every cell of the block), or size² indices\n * row-major. Path pieces and parts are blocks — at size 1 they are just a tile. */\nexport type TileBlock = number | number[];\n/** `size`² indices, row-major within the block. */\nexport type FillBlock = number[];\n/** A named element placed BY HAND (a pedestrian crossing in a road, a gate in a fence). It carries\n * its own `id`, so the map stores it like any material — but it CONNECTS as its parent, so the\n * run continues straight through it. Never picked at random: you paint it from the palette, ONE\n * CELL at a time, and the tile is worked out from where that cell sits. */\nexport type TilePart = {\n /** Stable small int, unique across every material and part of the tileset. */\n id: number;\n /** Which run the art is drawn for — 'v' vertical, 'h' horizontal. It also picks the art: the\n * element varies ACROSS the line (a crossing has one tile per lane) and repeats along it, so\n * `tiles` is `size` long, indexed by row for 'h' and by column for 'v'. */\n axis?: \"v\" | \"h\";\n /** The tiles — one index, `size` across the run when `axis` is set, else the size² block. */\n tiles?: TileBlock;\n};\n/** A block variant: the block, or [block, weight] for seeded scatter. */\nexport type BlockEntry = FillBlock | [FillBlock, number];\n/** One transition set of a patch material — the tiles its border shows against a neighbor. */\nexport type PatchSlots = {\n /** Edge line tiles [n, e, s, w] — e.g. `edges[0]` draws where the patch stops toward the top. */\n edges?: [EdgeSlot, EdgeSlot, EdgeSlot, EdgeSlot];\n /** Convex corner tiles [ne, se, sw, nw] — the patch's outside corners. Always one cell. */\n outer?: Dir4;\n /** Concave corner tiles [ne, se, sw, nw] — the notch where two patch arms meet. One cell. */\n inner?: Dir4;\n};\nexport type PatchMaterial = {\n /** Stable small int — what `cells('…')` stores when a map carries Autotile2D. */\n id: number;\n kind: \"patch\";\n /** Editor swatch color ('#4a7c3a'). */\n color?: string;\n /** Block size in cells (default 1). With 2 or 3 the material is classified block-to-block on a\n * lattice anchored at the map origin, `fill` holds size² tiles and each edge `size` tiles. */\n size?: number;\n /** Interior tile — one index, or an ARRAY of scatter variants (each `index` or\n * `[index, weight]`; bare indices weigh 1): `fill: [261, [262, 0.1], [263, 0.05]]`.\n * With `size` > 1 it is instead the row-major BLOCK of size² indices\n * (`fill: [130, 131, 146, 147]`), or a list of such blocks for scatter variants. */\n fill: number | FillEntry[] | BlockEntry[];\n /** Transition sets keyed by the neighboring material's name; '*' = any other neighbor\n * (including empty). Baked packs draw a material fading into a SPECIFIC background. */\n over?: Record<string, PatchSlots>;\n /** Hand-placed elements that connect as this material (see TilePart). */\n parts?: Record<string, TilePart>;\n};\nexport type PathMaterial = {\n id: number;\n kind: \"path\";\n color?: string;\n /** Cells ACROSS the line (default 1). A `size: 2` road is two lanes wide: connectivity runs\n * block to block and every piece below is a 2×2 block instead of one tile. */\n size?: number;\n /** No connections at all. */\n isolated?: TileBlock;\n /** End caps [n, e, s, w] — `ends[0]` connects toward the top only. */\n ends?: [TileBlock, TileBlock, TileBlock, TileBlock];\n /** [vertical (n+s), horizontal (e+w)]. */\n straights?: [TileBlock, TileBlock];\n /** Elbows [ne, se, sw, nw] — `corners[0]` connects top + right. */\n corners?: [TileBlock, TileBlock, TileBlock, TileBlock];\n /** T pieces [n, e, s, w] — `tees[0]` is the tee MISSING the top connection. */\n tees?: [TileBlock, TileBlock, TileBlock, TileBlock];\n /** All four connections. */\n cross?: TileBlock;\n /** Hand-placed elements that connect as this material (see TilePart). */\n parts?: Record<string, TilePart>;\n};\nexport type TileMaterial = PatchMaterial | PathMaterial;\nexport type TilesetDef = {\n /** The atlas image — write `asset('./TileSet.png')`. */\n image: string;\n /** Atlas cell size in image pixels — a number (square) or [w, h]. */\n tile: number | [number, number];\n /** Named materials; names are the editor/`over:` vocabulary, `id`s are what maps store. */\n materials?: Record<string, TileMaterial>;\n};\nexport declare const normalizeFill: (fill: number | FillEntry[]) => [number, number][];\n/** A material's block size — 1 unless it declares `size` (clamped to a positive int). */\nexport declare const blockSize: (mat: TileMaterial) => number;\n/** One cell of a block: a scalar covers the whole block, an array reads row-major. Undefined =\n * unassigned (missing, or the negative sentinel the editor writes for a blank slot). */\nexport declare const blockTile: (block: TileBlock | undefined, n: number, lx: number, ly: number) => number | undefined;\n/** How many tiles a part holds: `size` across the run when it declares an axis, else the block. */\nexport declare const partSlots: (part: TilePart, n: number) => number;\n/** The cell value that draws atlas tile `index` verbatim in a material map. */\nexport declare const rawCell: (index: number) => number;\n/** True for a cell holding a raw atlas tile rather than a material id. */\nexport declare const isRawCell: (v: number) => boolean;\n/** The atlas index behind a raw cell (garbage in, garbage out — guard with isRawCell). */\nexport declare const rawIndex: (v: number) => number;\nexport declare const TILE_INDEX_MASK = 268435455;\n/** The atlas index behind a (possibly oriented) tile value. */\nexport declare const tileIndex: (v: number) => number;\n/** Clockwise quarter-turns (0–3) of a tile value. */\nexport declare const tileTurns: (v: number) => number;\n/** Whether the tile is mirrored horizontally (the mirror applies before the rotation). */\nexport declare const tileFlip: (v: number) => boolean;\n/** True when the value carries any orientation (renderers keep the fast path otherwise). */\nexport declare const tileOriented: (v: number) => boolean;\n/** Build an oriented tile value: `index`, mirrored when `flip`, then `turns` quarter-turns CW. */\nexport declare const packTile: (index: number, turns?: number, flip?: boolean) => number;\n/** The value rotated a further 90° clockwise. */\nexport declare const rot90: (v: number) => number;\n/** The value rotated a further 180°. */\nexport declare const rot180: (v: number) => number;\n/** The value rotated a further 270° clockwise (90° counter-clockwise). */\nexport declare const rot270: (v: number) => number;\n/** The value mirrored horizontally (on screen — existing turns are re-based, group math). */\nexport declare const flipX: (v: number) => number;\n/** The tile a part draws in a cell — indexed ACROSS the run ('h' by row, 'v' by column) so one\n * element covers a lane each and repeats along the run; without an axis it is a plain block. */\nexport declare const partTile: (part: TilePart, n: number, lx: number, ly: number) => number | undefined;\n/** `fill` as weighted BLOCKS of `size`² indices (row-major). Size 1 keeps the scalar/scatter\n * reading; with size > 1 a flat number array is one positional block, an array of arrays is the\n * variant list, and a bare number fills the whole block. Missing entries read as -1. */\nexport declare const fillBlocks: (fill: PatchMaterial[\"fill\"], size?: number) => [number[], number][];\n/**\n * Derive display atlas indices from a material-id grid (row-major, row 0 = top, -1 = empty).\n * Values that match no material id pass through unchanged (so converting maps degrades\n * gracefully); -1 stays -1. Deterministic: same inputs + seed → same output on every platform.\n */\nexport declare const deriveCells: (def: TilesetDef, cols: number, rows: number, cells: ArrayLike<number>, seed?: number) => Int32Array;\n","types/g2/Camera2D.d.ts":"import { Vec2, type Vec2Like } from \"../math/vec\";\nimport type { CompAxis, CompWriter } from \"../core/compWrite\";\nexport declare class Camera2D implements CompWriter {\n private _x;\n private _y;\n private _zoom;\n private _rotation;\n private readonly sceneId;\n constructor(sceneId: number);\n get position(): Vec2;\n set position(v: Vec2Like);\n _writeComp(_prop: string, axis: CompAxis, v: number): void;\n get zoom(): number;\n set zoom(z: number);\n get rotation(): number;\n set rotation(deg: number);\n screenToWorld(screenX: number, screenY: number): Vec2;\n worldToScreen(worldX: number, worldY: number): Vec2;\n}\n","types/g2/cells.d.ts":"export type CellsData = {\n cols: number;\n rows: number;\n /** Row-major tile values (row 0 = the top row), length cols*rows. */\n data: Int32Array;\n};\n/** Encode a grid into a `cells()` payload (the editor / tools side of the codec). */\nexport declare const encodeCells: (cols: number, rows: number, data: ArrayLike<number>) => string;\n/**\n * Decode a `cells('…')` payload into the grid a tilemap block consumes. Scene files call this via\n * the injected global; the value is plain data, so hand-written code may pass any\n * `{ cols, rows, data }` of its own instead (procedural maps).\n */\nexport declare const cells: (payload: string) => CellsData;\n","types/g2/CharacterController2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { FieldMeta } from \"../core/fields\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport type { CompWriter } from \"../core/compWrite\";\nimport { PhysicsGroup2D } from \"./groups2d\";\nimport { type Node2D } from \"./Node2D\";\n/** Where the character's feet are, as reported by the solver after the last step. */\nexport type GroundState2D = \"ground\" | \"slope\" | \"air\";\n/** One surface the mover pushed out of this step. `normal` points back at the character. */\nexport type Collision2D = {\n node: Node2D | null;\n normal: Vec2;\n};\nexport declare class CharacterController2D extends Aspect<\"controller\", Node2D> implements CompWriter {\n static readonly aspect = \"controller\";\n static fields: FieldMeta<CharacterController2D>;\n private _id;\n private _gravityScale;\n private _maxSlope;\n private _group;\n private _dropThrough;\n private _repush;\n onAttach(): void;\n onDetach(): void;\n /** Native character id (0 until attached / no physics support). */\n get id(): number;\n /**\n * This frame's movement command, in world units/s — NOT normalized, NOT a per-frame displacement\n * (that is what Unity's `Move` takes; passing `v * dt` here gives a character 60× too slow).\n *\n * ONE component = horizontal, the everyday platformer call. TWO = the whole velocity, for free mode\n * (`gravityScale = 0`); with gravity on, a two-component call fights the ballistic vertical and the\n * character hangs in the air, so that combination warns once.\n *\n * Sticky only within the frame: the command expires once the engine consumes it. It also **takes the\n * axis back from a latched `velocity`** — commanding is claiming ownership, which is what keeps the\n * two horizontal sources from ever fighting.\n */\n move(x: number): void;\n move(x: number, y: number): void;\n move(v: Vec2Like): void;\n private _warnFree;\n /** Vertical velocity (world units/s) — LATCHED: gravity works on it, you seed it. `= 700` to jump,\n * `+= 300` to stack an explosion on top of the current motion. No ground check: guard it yourself\n * with `grounded` (or don't, for a double jump). Does nothing in free mode. `velocity.y = 700` is\n * the same channel — pick whichever reads better. */\n get velocityY(): number;\n set velocityY(v: number);\n /**\n * READ — the velocity the solver ended up with after the most recent step (world units/s, fresh\n * Vec2): what HAPPENED, not what you asked for. Walking into a wall reads ~0, sliding along one\n * reads the tangent.\n *\n * WRITE — LATCH the whole velocity: a knockback, a wall jump, a launch pad. Unlike `move()` it does\n * not expire, so the character keeps flying, and gravity still pulls the vertical down into a real\n * ballistic arc. It stays until `move()` takes the axis back — so a game simply doesn't call\n * `move()` while the throw lasts, and ends it on its own terms:\n *\n * hero.controller.velocity = [dir.x * 600, 400] // hit by the blast\n * if (thrown) { if (hero.controller.grounded) thrown = false } // landing ends it\n * else hero.controller.move(ix * SPEED) // …and this reclaims the axis\n *\n * Nothing clears the latch by itself, landing included — a kinematic controller has no friction.\n * Reading is not the inverse of writing: against a wall the read is ~0 and would cancel the throw.\n *\n * `c.velocity.y = 700` (the direct spelling) is a jump — the compiler routes it to the exact\n * `velocityY` channel via `_writeComp` below — and `c.velocity.x = 300` latches the whole vector\n * with the measured vertical filling in. A STORED copy is still a copy (`const v = c.velocity`).\n */\n get velocity(): Vec2;\n set velocity(v: Vec2Like);\n /** Compile-time list (chisel reads it, then strips it) — see CharacterController / core/compWrite.ts. */\n static _comps: string[];\n /** True while standing on walkable ground. */\n get grounded(): boolean;\n /** Where the feet are after the last step: walkable ground, too-steep ground, or the air. */\n get groundState(): GroundState2D;\n /** The surface normal under the feet — for orienting a sprite to a slope, or deciding a slide. */\n get groundNormal(): Vec2;\n /** What the character is standing on: a moving platform, a hazard, an ice patch whose `friction`\n * the game can read. The engine already carries the character along a kinematic platform. */\n get groundNode(): Node2D | null;\n /**\n * Every surface the mover pushed out of during the last step, with the normal pointing back at the\n * character. This is what wall jumps and box pushing are written against — a kinematic mover is not\n * a body, so those contacts do not arrive as 'enter' events.\n *\n * const wall = c.collisions.find(h => Math.abs(h.normal.x) > 0.7)\n * if (wall && jumpPressed) c.velocity = [-wall.normal.x * KICK, JUMP]\n *\n * for (const h of c.collisions) h.node?.physics?.applyImpulse([-h.normal.x * PUSH, 0])\n */\n get collisions(): Collision2D[];\n /** Multiplier over the world gravity; default 1. **0 = free mode**: no gravity, no ground, no\n * stick-to-floor — a swimmer, a drone, a ladder climber, or a top-down hero, driven by the\n * two-component `move()`. */\n get gravityScale(): number;\n set gravityScale(v: number);\n /** Max ground slope (degrees) the character treats as walkable; default 45. Live. */\n get maxSlope(): number;\n set maxSlope(v: number);\n /** Which collision group the character belongs to. Live. */\n get group(): PhysicsGroup2D | undefined;\n set group(g: PhysicsGroup2D | undefined);\n /**\n * While this names a node, that node's `OneWay2D` surfaces are not solid for this character — how\n * you drop off a semisolid platform. A plain latch: whoever sets it clears it.\n *\n * if (downPressed && jumpPressed && c.grounded) {\n * const platform = c.groundNode\n * c.dropThrough = platform\n * setTimeout(() => { if (c.dropThrough === platform) c.dropThrough = null }, 200)\n * }\n *\n * Because it names ONE node, the timeout is not delicate: too long merely means you could have\n * re-landed on that platform for a moment, and the platform below stays solid either way.\n */\n get dropThrough(): Node2D | null;\n set dropThrough(n: Node2D | null);\n /**\n * True while a requested collider resize hasn't taken — you asked to stand up and there is something\n * overhead. Resizing goes through the `Shape2D` aspect itself:\n *\n * hero.aspect(Shape2D, { capsule: CROUCHED }) // always fits — you are shrinking\n * hero.aspect(Shape2D, { capsule: STANDING }) // may be refused under a low ceiling\n * if (hero.controller.resizing) … // still crouched; call it again next frame\n *\n * A refusal changes nothing, so the retry is just the same call again — and it is an exact headroom\n * test against the real capsule, unlike a hand-rolled raycast (a ray is a line; a capsule has\n * girth). The FEET stay planted across a resize, so the character neither hovers nor sinks.\n */\n get resizing(): boolean;\n private _state;\n}\n","types/g2/defineScene2d.d.ts":"import type { ColorInput } from \"../core/color\";\nimport type { Vec2Like } from \"../math/vec\";\nimport { type AspectEntry, type MakeEntry as SharedMakeEntry } from \"../scene/grammar\";\nimport { Scene2D } from \"./Scene2D\";\nimport { Node2D } from \"./Node2D\";\nimport { Sprite } from \"./Sprite\";\nimport { Tilemap } from \"./Tilemap\";\nimport { SpriteSheet } from \"./SpriteSheet\";\nimport type { SpriteAnimation } from \"./SpriteAnimation\";\nimport type { CellsData } from \"./cells\";\nimport type { With } from \"../core/Aspect\";\nexport type Scene2dEnv = {\n /** Background color — '#5a6b3b', 0x5a6b3b, or [r,g,b] in 0..1. */\n background?: ColorInput;\n /** Texture sampling: 'nearest' (crisp pixel art, engine default) or 'linear'. */\n filter?: \"nearest\" | \"linear\";\n /** Pixel-art crispness: snap the camera to whole screen pixels (seeds CameraFollow's\n * `pixelSnap`, and the initial camera position lands on whole world units). */\n pixelPerfect?: boolean;\n /** Physics world gravity (Y-up: down is negative). Presence configures the world before any\n * body is created — `[0, 0]` for top-down worlds. Omit to leave the world unconfigured. */\n gravity?: Vec2Like;\n};\n/** A sprite node: one named entry of an imported `.sprite.ts` sheet. The sheet is ART only —\n * colliders/bodies are scene semantics: put Shape2D / Physics2D / Trigger2D in `aspects`. */\nexport type SpriteSourceDef = {\n /** The imported sheet handle: `import props from './props.sprite'` … `sheet: props`. */\n sheet: SpriteSheet;\n /** The entry name; omit when the sheet declares exactly one sprite. */\n name?: string;\n /** Start this clip immediately (sliced entries with clips). */\n clip?: string;\n /** Initial facing for `perDirection` clips. */\n direction?: string;\n};\nexport type TilemapSourceDef = {\n /** The tileset image — `asset('./TileSet.png')`. */\n texture: string;\n /** On-screen cell size in world units — a number (square) or [w, h]. */\n tile: number | [number, number];\n /** Atlas grid: how the texture slices into tiles, [atlasCols, atlasRows]. */\n atlas: [number, number];\n /** The map: a `cells('…')` payload — or any `{ cols, rows, data }` of your own. */\n cells: CellsData | {\n cols: number;\n rows: number;\n data: number[] | Int32Array;\n };\n};\n/** A camera marker node: seeds the scene camera's starting position (+ zoom). To MOVE the camera\n * in play, attach `CameraFollow` to the node being followed — not aspects on this marker. */\nexport type Camera2dNodeDef = {\n zoom?: number;\n};\nexport type Scene2dNodeDef = {\n sprite?: SpriteSourceDef;\n tilemap?: TilemapSourceDef;\n camera?: Camera2dNodeDef;\n /** A code-built subtree — `make(factoryFn, { ...literal args })`, factory returns a Node2D. */\n make?: SharedMakeEntry<any, Node2D>;\n position?: Vec2Like;\n /** Degrees, CCW. */\n rotation?: number;\n scale?: Vec2Like | number;\n /** Draw layer (int) — higher renders on top. */\n layer?: number;\n /** Intra-layer depth for non-Y-sorted layers. */\n z?: number;\n /** Sprite tint (sprite nodes only). */\n color?: ColorInput;\n /** Sprite opacity 0..1 (sprite nodes only). */\n opacity?: number;\n flipX?: boolean;\n flipY?: boolean;\n visible?: boolean;\n /** Editor-only: the move gizmo won't target this node (fields still edit). No runtime effect. */\n locked?: boolean;\n aspects?: readonly AspectEntry<any>[];\n children?: Record<string, Scene2dNodeDef>;\n};\nexport type Scene2dCameraDef = {\n position?: Vec2Like;\n zoom?: number;\n};\nexport type Scene2dDef = {\n env?: Scene2dEnv;\n /** Per-layer config, keyed by layer number: `layers: { 1: { ySort: true } }`. */\n layers?: Record<number | string, {\n ySort?: boolean;\n }>;\n /** Starting camera when there's no camera NODE (a camera node wins). */\n camera?: Scene2dCameraDef;\n nodes?: Record<string, Scene2dNodeDef>;\n};\ntype SourceNodeOf<N extends Scene2dNodeDef> = N extends {\n sprite: {\n clip: string;\n };\n} ? Sprite & {\n anim: SpriteAnimation;\n} : N extends {\n sprite: SpriteSourceDef;\n} ? Sprite : N extends {\n tilemap: TilemapSourceDef;\n} ? Tilemap : Node2D;\ntype AspectsOf<N extends Scene2dNodeDef> = N extends {\n aspects: readonly AspectEntry<infer A>[];\n} ? A : never;\ntype NodeOf<N extends Scene2dNodeDef> = [\n AspectsOf<N>\n] extends [never] ? SourceNodeOf<N> : With<SourceNodeOf<N>, AspectsOf<N>>;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\ntype ChildMapsOf<T extends Record<string, Scene2dNodeDef>> = {\n [K in keyof T]: T[K] extends {\n children: infer C extends Record<string, Scene2dNodeDef>;\n } ? NodesOf<C> : never;\n}[keyof T];\ntype NodesOf<T extends Record<string, Scene2dNodeDef>> = {\n [K in keyof T]: NodeOf<T[K]>;\n} & ([ChildMapsOf<T>] extends [never] ? unknown : UnionToIntersection<ChildMapsOf<T>>);\nexport type Scene2dNodes<D extends Scene2dDef> = D[\"nodes\"] extends Record<string, Scene2dNodeDef> ? NodesOf<D[\"nodes\"]> : Record<string, Node2D>;\nexport type LoadedScene2d<D extends Scene2dDef> = {\n scene: Scene2D;\n nodes: Scene2dNodes<D>;\n};\nexport declare class Scene2dHandle<D extends Scene2dDef = Scene2dDef> {\n readonly def: D;\n private _loading?;\n constructor(def: D);\n /** Instantiate the scene (idempotent — subsequent calls return the same instance). Does not open. */\n load(): Promise<LoadedScene2d<D>>;\n /** Load and make active (only the active 2D scene renders). */\n open(): Promise<LoadedScene2d<D>>;\n}\n/**\n * Define a 2D scene as data — the default export of a `.scene2d.ts` file. Returns a typed handle:\n * `const { scene, nodes } = await handle.open()` gives `nodes.<name>` typed by its source block\n * (Sprite / Tilemap / Node2D) with its `use(...)`d aspects attached.\n */\nexport declare const defineScene2d: <const D extends Scene2dDef>(def: D) => Scene2dHandle<D>;\nexport {};\n","types/g2/groups2d.d.ts":"/** Collides with everything. */\nexport declare const ALL_GROUPS = 4294967295;\nexport declare class PhysicsGroup2D {\n /** The single category bit this group owns. */\n readonly bit: number;\n /** Optional debug label, so an inspector says \"bullets\" rather than \"group #3\". */\n readonly label: string;\n private _ignored;\n /**\n * Stop colliding with these groups — symmetric, so naming it on one side is enough. Safe to call\n * after bodies exist: their filters are re-pushed.\n */\n ignore(...groups: PhysicsGroup2D[]): this;\n /** Members of this group don't collide with EACH OTHER — bullets, debris, a ragdoll's own bones. */\n ignoreSelf(): this;\n}\n","types/g2/loop.d.ts":"export declare const onUpdate: (callback: (dt: number) => void) => void;\nexport declare const offUpdate: (callback: (dt: number) => void) => void;\nexport declare const ensureAnimEvents: () => void;\nexport declare const ensurePhysicsEvents: () => void;\n","types/g2/Node2D.d.ts":"import { AspectHost } from \"../core/Aspect\";\nimport type { CompAxis, CompWriter } from \"../core/compWrite\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport type { Animation } from \"../animate/tween/Animation\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\n/** Animatable transform props of a 2D node; an array of values is a keyframe list. */\nexport type Node2DTweenProps = {\n x?: number | number[];\n y?: number | number[];\n position?: Vec2Like | Vec2Like[];\n /** Degrees. */\n rotation?: number | number[];\n scale?: number | Vec2Like | (number | Vec2Like)[];\n};\nexport { Vec2, type Vec2Like };\nexport type Node2DEvents = {\n /** A looping animation clip wrapped around (fires each loop). */\n loopReached: (clip: string) => void;\n /** A non-looping animation clip finished. */\n completed: (clip: string) => void;\n /** A physics contact / sensor overlap began (the other node, plus where and how hard). The\n * contact's `normal` points AWAY from the other node, so `normal.y > 0.7` reads as \"I landed on\n * top of it\". Sensor overlaps and `exit` carry zeros. */\n enter: (other: Node2D, contact: Contact2D) => void;\n exit: (other: Node2D, contact: Contact2D) => void;\n /** Pointer up over this node's Physics2D shape (a tap/click). */\n click: (ev: ClickEvent<Node2D | null>) => void;\n /** Pointer down on this node's Physics2D shape. Call ev.track(...) to capture the drag. */\n touchstart: (ev: TouchStartEvent<Node2D | null>) => void;\n};\n/** Where a contact happened, delivered as the second argument of 'enter'. `speed` is the approach\n * speed at impact (world units/s) — scale an impact sound with it. Zeros on sensor and 'exit'\n * events, which have no manifold. */\nexport type Contact2D = {\n point: Vec2;\n normal: Vec2;\n speed: number;\n};\nexport declare class Node2D extends AspectHost<Node2DEvents> implements CompWriter {\n /** Native entity id. */\n get id(): number;\n /** Optional debug/editor name (plain JS data — scene2d files stamp their node names here). */\n name?: string;\n protected _x: number;\n protected _y: number;\n protected _rotation: number;\n protected _sx: number;\n protected _sy: number;\n protected _layer: number;\n protected _z: number;\n protected _visible: boolean;\n private _pushXf;\n constructor(internalId?: number | Handle);\n private _pull;\n get x(): number;\n set x(v: number);\n get y(): number;\n set y(v: number);\n _writeComp(_prop: string, axis: CompAxis, v: number): void;\n get position(): Vec2;\n set position(v: Vec2Like);\n /** Rotation in degrees (CCW). */\n get rotation(): number;\n set rotation(deg: number);\n get scale(): Vec2;\n set scale(v: Vec2Like | number);\n /** Tween the transform — `node.animateTo({ x: 120, rotation: 90, duration: 400, easing: 'outBack' })`;\n * arrays are keyframes. Game clock unless `clock: 'ui'`. Returns the {@link Animation} handle. */\n animateTo(props: Node2DTweenProps & TweenMeta): Animation;\n /** Tween FROM the given values to the node's current transform. */\n animateFrom(props: Node2DTweenProps & TweenMeta): Animation;\n /** Draw layer (int). Higher layers render on top. */\n get layer(): number;\n set layer(v: number);\n /** Intra-layer depth for non-Y-sorted layers (higher z = on top). */\n get z(): number;\n set z(v: number);\n get visible(): boolean;\n set visible(v: boolean);\n get parent(): Node2D | null;\n set parent(p: Node2D | null);\n get children(): readonly Node2D[];\n /** Attach children to this node (each keeps its current world transform). Returns this. */\n add(...children: Node2D[]): this;\n /** Detach a direct child (reparents it to root, keeping its world transform). Returns this. */\n remove(child: Node2D): this;\n /**\n * Reparent this node. `keepWorld` (default true) recomputes the local transform so the on-screen\n * position/rotation/scale is unchanged; pass false to keep the local transform and move with the\n * new parent. Self/descendant parents are rejected natively (no cycles).\n */\n setParent(parent: Node2D | null, keepWorld?: boolean): this;\n /** World-space position (composes all ancestors). */\n get worldPosition(): Vec2;\n /** Convert a world-space point into this node's local space (and back). */\n worldToLocal(p: Vec2Like): Vec2;\n localToWorld(p: Vec2Like): Vec2;\n private _syncLocalFromNative;\n addEventListener<K extends keyof Node2DEvents>(channel: K, callback: Node2DEvents[K]): void;\n /** Destroy this node and its whole subtree (children go with it — the 3D / UI contract). Every\n * aspect in the subtree detaches first (physics bodies released, updaters unregistered). */\n destroy(): void;\n}\n","types/g2/OneWay2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { Node2D } from \"./Node2D\";\nexport declare class OneWay2D extends Aspect<\"oneWay\", Node2D> {\n static readonly aspect = \"oneWay\";\n private _normal;\n private _arc;\n private _enabled;\n /** Which side is solid. Default `[0, 1]` — solid from above, i.e. a floor you pass through from\n * below. `[1, 0]` is a wall you can only enter from the left. */\n get normal(): Vec2Like;\n set normal(v: Vec2Like);\n /** How far off `normal` an approach still counts as coming from the solid side, in degrees.\n * Default 90 — the whole half-plane, which is what a platform wants. */\n get arc(): number;\n set arc(v: number);\n /** Turn the one-way behaviour off, making the surface solid from both sides again. */\n get enabled(): boolean;\n set enabled(v: boolean);\n onAttach(): void;\n onDetach(): void;\n onReconfigure(): void;\n private _push;\n}\n","types/g2/Physics2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport { type Node2D } from \"./Node2D\";\nimport { PhysicsGroup2D } from \"./groups2d\";\nexport type MotionType = \"static\" | \"kinematic\" | \"dynamic\";\n/** A neutral solid surface. Deliberately the same default as 3D `Physics.friction`. */\nexport declare const DEFAULT_FRICTION = 0.6;\nexport interface PhysicsConfig {\n /** Gravity in world units/s² (Y-up: down is negative). Default [0, -980]. */\n gravity?: Vec2Like;\n /** Pixels per meter — tunes Box2D's internal tolerances; you still author in world units. Default 64.\n * Only applies before the world exists (it is a global solver tolerance). */\n pixelsPerMeter?: number;\n /** Solver sub-steps per fixed step. Default 4. */\n subSteps?: number;\n}\n/** Closest raycast hit. */\nexport interface RayHit {\n node: Node2D | null;\n point: Vec2;\n normal: Vec2;\n fraction: number;\n}\nexport declare class Physics2D extends Aspect<\"physics\", Node2D> {\n static readonly aspect = \"physics\";\n private _motion;\n /** Static (walls, floors), kinematic (script-driven platforms), or dynamic (fully simulated).\n * Default \"dynamic\", and LIVE: freeze a crate into `'static'`, hand a ragdoll to `'dynamic'`. */\n get motion(): MotionType;\n set motion(m: MotionType);\n /** Lock rotation (essential for platformer characters). */\n fixedRotation: boolean;\n /** Continuous collision for fast-moving bodies (projectiles). */\n bullet: boolean;\n private _mass;\n private _friction;\n private _bounce;\n private _gravityScale;\n private _linearDamping;\n private _angularDamping;\n private _group;\n private _repush;\n private _h;\n /** Which collision group this body belongs to (see Physics2D.addGroup). Live. */\n get group(): PhysicsGroup2D | undefined;\n set group(g: PhysicsGroup2D | undefined);\n /** Mass in world units. Omitted (or 0) = derived from the collider's AREA, so a big crate really is\n * heavier than a small one. Setting it scales the shape-derived mass data, keeping the rotational\n * inertia in the same ratio — a lopsided collider still tips the way its geometry says. */\n get mass(): number;\n set mass(v: number);\n /** Surface friction. 0 is frictionless, ~1 grippy; two bodies COMBINE as sqrt(a×b), so the lower\n * value wins the argument. Default 0.6 — a neutral solid, matching 3D. */\n get friction(): number;\n set friction(v: number);\n /** Bounciness, 0..1 — the fraction of the approach speed returned on impact. Two bodies combine as\n * MAX (the bouncier one wins — the opposite of friction), and below ~64 units/s no bounce is\n * applied at all, which is what stops a ball jittering on the floor forever. */\n get bounce(): number;\n set bounce(v: number);\n private _pushMaterial;\n /** Native physics body id. 0 until attached, or if the build has no physics support. Mirrors 3D `Physics.id`. */\n get id(): number;\n onAttach(): void;\n onDetach(): void;\n /** Re-applying options (`node.aspect(Physics2D, {…})`) pushes the live ones through. */\n onReconfigure(): void;\n /** Linear velocity in world units/second (fresh Vec2 on read). */\n get velocity(): Vec2;\n set velocity(v: Vec2Like);\n /** Angular velocity in degrees/second. */\n get angularVelocity(): number;\n set angularVelocity(degPerSec: number);\n /** Per-body gravity multiplier: 1 = full world gravity, 0 = floats, <0 = repelled. */\n get gravityScale(): number;\n set gravityScale(scale: number);\n get linearDamping(): number;\n set linearDamping(d: number);\n get angularDamping(): number;\n set angularDamping(d: number);\n /** Pause this body — it stops simulating and stops colliding until re-enabled. */\n set enabled(v: boolean);\n /** Box2D puts resting bodies to sleep; wake one to make it react to a change you made by hand. */\n set awake(v: boolean);\n /** Apply an instantaneous impulse at the centre of mass (never spins the body) and wake it. */\n applyImpulse(v: Vec2Like): this;\n /** Apply an impulse at a WORLD point — the lever arm becomes spin. Use this when the push has a real\n * point of contact: a bullet's hit point, a blast pushing a prop at its base. */\n applyImpulseAt(v: Vec2Like, worldPoint: Vec2Like): this;\n /** Apply a continuous force (world units) and wake the body. */\n applyForce(v: Vec2Like): this;\n /** Set the world's gravity / solver settings. OPTIONAL: the world is created on the first body with\n * gravity [0, -980], 64 px/m and 4 sub-steps. Calling this later changes gravity LIVE and leaves\n * bodies alone. */\n static configure(config?: PhysicsConfig): void;\n /** World gravity, live. */\n static get gravity(): Vec2;\n static set gravity(g: Vec2Like);\n private static _gravity;\n /** Whether this build has physics support (CREATOR_2D_PHYSICS). NOTE: this reports the BUILD, not\n * the world — there is nothing else to guard, since the world creates itself. */\n static get supported(): boolean;\n /** Render interpolation of body transforms between the fixed 60 Hz steps (global; default on). Turn\n * off to save per-frame transform writes when you have many moving bodies / don't need >60 Hz\n * smoothness — bodies then advance in discrete steps. */\n private static _interpolation;\n static get interpolation(): boolean;\n static set interpolation(on: boolean);\n /**\n * Register a collision group. Groups are SUBTRACTIVE and SYMMETRIC (see groups2d.ts):\n *\n * const player = Physics2D.addGroup()\n * const bullets = Physics2D.addGroup().ignoreSelf().ignore(player)\n */\n static addGroup(label?: string): PhysicsGroup2D;\n /** The implicit group of every body that never named one - name it to exclude \"everything else\". */\n static get defaultGroup(): PhysicsGroup2D;\n /** Closest body hit by the segment, or null. `node` resolves the hit entity. */\n static raycast(from: Vec2Like, to: Vec2Like, q?: Query2D): RayHit | null;\n /** Every body along the segment, NEAREST FIRST - a piercing bullet, a laser, \"how many walls are\n * between us\". Capped at 32 hits. */\n static raycastAll(from: Vec2Like, to: Vec2Like, q?: Query2D): RayHit[];\n /** Topmost body (solid or sensor) whose shape contains the world point, or null. \"Topmost\" means\n * by DRAW order - layer, then z - so picking agrees with what the player sees. */\n static overlapPoint(p: Vec2Like, q?: Query2D): Node2D | null;\n /** Everything within `radius` of a point - an explosion, an aura, an aggro range. */\n static overlapCircle(centre: Vec2Like, radius: number, q?: Query2D): Node2D[];\n /** Everything inside an axis-aligned box (centre + HALF-extents) - a room, a camera bound. */\n static overlapBox(centre: Vec2Like, half: Vec2Like, q?: Query2D): Node2D[];\n /**\n * Everything touching a capsule from-to of the given radius. A capsule is the shape a DIRECTED\n * question has: a beam with width, a sword arc, \"does my radius fit through this gap\" - none of\n * which an axis-aligned box can express.\n *\n * It is also the SWEPT test: a circle of radius r moving from A to B during a frame sweeps exactly\n * this capsule, so a fast projectile checked this way cannot tunnel through a thin wall the way two\n * separate position checks do.\n */\n static overlapCapsule(from: Vec2Like, to: Vec2Like, radius: number, q?: Query2D): Node2D[];\n}\n/** Which groups a query may hit, and what to skip. */\nexport type Query2D = {\n /** Only hit bodies in these groups. Omitted = everything. */\n groups?: PhysicsGroup2D[];\n /** Skip these nodes - the \"don't hit myself\" case a ray fired from inside its own body needs. */\n ignore?: Node2D | Node2D[];\n};\n","types/g2/scenarios2d.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { Node2D } from \"./Node2D\";\nimport type { Scene2D } from \"./Scene2D\";\n/**\n * Ease the scene camera toward this node every frame (attach it to the player). In a `.scene2d.ts`\n * file the loader wires `scene` automatically; from hand-written code pass it yourself:\n * `hero.aspect(CameraFollow, { scene })`.\n *\n * The eased position accumulates at full precision and only the value PUSHED to the camera is\n * snapped — reading the snapped camera back as the ease-from value would let tiny sub-pixel steps\n * round to zero near settle (the follow would stall a few px off-centre, then jump).\n */\nexport declare class CameraFollow extends Aspect<\"cameraFollow\", Node2D> {\n static readonly aspect = \"cameraFollow\";\n /** The scene2d loader injects the scene into aspects that declare this. */\n static readonly wantsScene = true;\n /** The scene whose camera follows (wired by the scene file loader). */\n scene: Scene2D | null;\n /** Exponential time constant in seconds; smaller = snappier, 0 = pin the node to centre. */\n smooth: number;\n /** Camera offset from the node, in world units. */\n offset: [number, number];\n /** Quantize the camera to whole screen pixels so eased motion never shimmers pixel art.\n * Defaults to the scene's `env.pixelPerfect` (true when unset). */\n pixelSnap: boolean;\n private _x;\n private _y;\n private readonly _grid;\n update(dt: number): void;\n}\n","types/g2/Scene2D.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Aspect, type AspectCtor, type FieldOf, type TargetOf } from \"../core/Aspect\";\nimport { Presentable, type DismissOptions, type PresentOptions } from \"../ui/presentable\";\nimport { type UIWidgetContent } from \"../ui/UILayer\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport { Camera2D } from \"./Camera2D\";\nimport { type Node2D } from \"./Node2D\";\nexport type Scene2DOptions = {\n /** Background color — '#10131a', 0x10131a, or [r,g,b]/[r,g,b,a] in 0..1. */\n background?: ColorInput;\n /** Texture sampling for the 2D renderer: `'nearest'` (default — crisp pixel art) or `'linear'`\n * (smooth — for hi-res / non-pixel-art assets). Applied when the scene is opened, so switching\n * scenes restores the active scene's choice. NOTE: this is a GLOBAL renderer setting (one sampler\n * for ALL textures, not per-texture), so the currently-open scene's filter wins. Omit to leave the\n * current setting (engine default is nearest). */\n filter?: 'nearest' | 'linear';\n};\n/** Returned by scene2d.layer(n); chain .ySort() to enable top-down depth sorting for that layer. */\ndeclare class LayerHandle {\n private readonly sceneId;\n private readonly layer;\n constructor(sceneId: number, layer: number);\n /** In this layer, lower-on-screen sprites overlap higher ones (top-down feet sorting). */\n ySort(enabled?: boolean): this;\n}\nexport declare class Scene2D implements Presentable {\n /** Native scene handle. */\n readonly id: number;\n readonly camera: Camera2D;\n private static _active;\n static get active(): Scene2D | null;\n readonly _touchStartListeners: Array<(ev: TouchStartEvent<Node2D | null>) => void>;\n /** Texture filter to (re)assert on open(); the sampler is global, so each scene reclaims it. */\n private readonly _filter?;\n constructor(options?: Scene2DOptions);\n set background(color: ColorInput);\n /** Address a draw layer to configure it, e.g. scene2d.layer(1).ySort(). */\n layer(n: number): LayerHandle;\n /** Topmost visible sprite whose world bounds contain the world point, or null. Body-free\n * hit-test for tap/click picking — pair with camera.screenToWorld(). */\n pick(worldPoint: Vec2Like): Node2D | null;\n /** Scene-level pointer events. The handler fires for every tap/press in the scene, with\n * `ev.target` = the hit Physics2D node (or null). On 'touchstart' you can ev.track(...) a drag. */\n addEventListener(channel: \"click\", callback: (ev: ClickEvent<Node2D | null>) => void): void;\n addEventListener(channel: \"touchstart\", callback: (ev: TouchStartEvent<Node2D | null>) => void): void;\n removeEventListener(channel: \"click\" | \"touchstart\", callback: (ev: any) => void): void;\n add(...nodes: Node2D[]): this;\n remove(...nodes: Node2D[]): this;\n /** Attach (and configure) a system, or reconfigure it if already present. Returns the scene typed\n * as now-having it (`scene.system(Hud).hud`). A 3D `System<'x'>` (target Scene) is rejected here. */\n system<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;\n /** Safe access — undefined if the system isn't attached. */\n get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;\n /** Existence check AND type guard: inside `if (scene.has(Hud))`, `scene.hud` is present. */\n has<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this is this & FieldOf<A>;\n /** Detach a system (runs its onDetach). Chainable. */\n removeSystem<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this;\n readonly cl: (() => void)[];\n _backButtonCallback?: () => void;\n private _vd?;\n /** Fires when the scene becomes the visible destination (incl. a pop revealing it). */\n onOpen(callback: () => void): this;\n /** Fires when the scene stops being visible (closed, replaced, or covered by a push). */\n onClose(callback: () => void): this;\n /** Hardware/system back while the scene is current. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n /** The UI over the scene — widgets (a HUD, a dialog), laid out over the scene while it is\n * presented; touches outside a widget's box reach the scene. */\n setContent(content: UIWidgetContent): this;\n /** Make this the active scene — shows it as the current destination (replaces a screen /\n * another scene; only the active scene renders). */\n open(options?: PresentOptions): this;\n close(options?: DismissOptions): this;\n destroy(): void;\n}\nexport {};\n","types/g2/Shape2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { Node2D } from \"./Node2D\";\nexport declare class Shape2D extends Aspect<\"shape\", Node2D> {\n static readonly aspect = \"shape\";\n /** Box half-extents [hw, hh] (world units). */\n box?: Vec2Like;\n /** Circle radius. */\n circle?: number;\n /** Capsule between two local points, with a radius. */\n capsule?: {\n from: Vec2Like;\n to: Vec2Like;\n radius: number;\n };\n /** Thin segment (an edge) between two local points. */\n segment?: {\n from: Vec2Like;\n to: Vec2Like;\n };\n /** Convex polygon, up to 8 local points (a convex hull is computed — a CONCAVE outline silently\n * becomes its hull; use `chain` for those). */\n polygon?: Vec2Like[];\n /**\n * A polyline of connected segments — the one shape that expresses a long CONCAVE surface (rolling\n * terrain, a cave wall) in one piece, seam-free. Pass only the points that should be solid; the\n * tangent points Box2D needs at the ends are synthesised here.\n *\n * STATIC bodies only (a polyline has no area, so no mass), at least 2 points (4 with `loop`), and it\n * must not self-intersect. It is ONE-SIDED: solid on the right of the point order — walk the points\n * so that the solid material is on your right, or set `flip`.\n */\n chain?: Vec2Like[];\n /** `chain`: close the contour (an island / a room boundary). Needs at least 4 points. */\n loop?: boolean;\n /** `chain`: put the solid side on the other side of the line. */\n flip?: boolean;\n /** The collider's centre relative to the node, in world units. Applies to EVERY kind — it\n * translates a capsule's / segment's / polygon's / chain's points too, unlike the old `offset`. */\n origin?: Vec2Like;\n private _handle;\n onDetach(): void;\n /**\n * Re-configuring the aspect swaps the fixture in place — same body, same id, same velocity, same\n * position. Nothing happens when the geometry is unchanged, so re-applying the same options in a\n * loop is free.\n */\n onReconfigure(): void;\n private _create;\n /**\n * Box2D's chain wants the two TANGENT points as extra entries and does not collide on its first or\n * last edge — pass it your outline verbatim and you lose both end segments (four points give ONE).\n * So the caller passes only the solid points and the ends are extrapolated here: `p0 + (p0 - p1)`.\n * A loop needs none of that (every point is interior) but does need 4 of them.\n */\n private _createChain;\n private _signature;\n}\n","types/g2/Sprite.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { Vec2, type Vec2Like } from \"../math/vec\";\nimport { Canvas } from \"../canvas/Canvas\";\nimport { Node2D, type Node2DTweenProps } from \"./Node2D\";\nimport type { Texture2D } from \"./Texture2D\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport type { Animation } from \"../animate/tween/Animation\";\n/** Animatable sprite props on top of the 2D transform. */\nexport type SpriteTweenProps = Node2DTweenProps & {\n opacity?: number | number[];\n color?: ColorInput | ColorInput[];\n};\n/** Anything that can back a sprite: a texture, or a Canvas (baked to a texture on assign). */\nexport type TextureSource = Texture2D | Canvas;\nexport type SpriteOptions = {\n texture?: TextureSource;\n /** Pivot, [0,0] = top-left .. [1,1] = bottom-right. Use [0.5, 1] (feet) for Y-sorted depth. */\n anchor?: Vec2Like;\n /** World size; defaults to the texture's pixel dimensions. */\n size?: Vec2Like;\n /** Normalized UV sub-rect [u0,v0,u1,v1]. */\n frame?: [number, number, number, number];\n /** Tint multiplied with the texture. */\n color?: ColorInput;\n opacity?: number;\n layer?: number;\n position?: Vec2Like;\n};\nexport declare class Sprite extends Node2D {\n private _texture?;\n private _anchor;\n private _color;\n private _opacity;\n private _flipX;\n private _flipY;\n private _size;\n constructor(options?: SpriteOptions);\n get texture(): Texture2D | undefined;\n set texture(t: TextureSource | undefined);\n /** Current world size: explicit override if set, else the texture's pixel dimensions (a Canvas-backed\n * sprite defaults to the canvas's LOGICAL size, so pixelRatio is crispness only, not size). */\n get size(): Vec2;\n set size(v: Vec2Like);\n get anchor(): Vec2;\n set anchor(v: Vec2Like);\n /** Set the UV sub-rect (normalized). */\n set frame(uv: [number, number, number, number]);\n /** Set the sub-rect in texture pixels. */\n setFramePx(px: number, py: number, pw: number, ph: number): this;\n /** Tween `opacity` / `color` and the transform — see {@link Node2D.animateTo}. */\n animateTo(props: SpriteTweenProps & TweenMeta): Animation;\n animateFrom(props: SpriteTweenProps & TweenMeta): Animation;\n get color(): ColorInput;\n set color(c: ColorInput);\n get opacity(): number;\n set opacity(a: number);\n get flipX(): boolean;\n set flipX(v: boolean);\n get flipY(): boolean;\n set flipY(v: boolean);\n}\n","types/g2/SpriteAnimation.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { type Vec2Like } from \"../math/vec\";\nimport type { Sprite } from \"./Sprite\";\n/** Per-clip frame list, or an object for per-clip fps/loop/direction overrides. */\nexport type Clip = number[] | {\n frames: number[];\n fps?: number;\n loop?: boolean;\n perDirection?: boolean;\n};\nexport declare class SpriteAnimation extends Aspect<\"anim\", Sprite> {\n static readonly aspect = \"anim\";\n /** Grid cell size in texture pixels (defaults to the full texture). */\n size?: [number, number];\n /** Grid columns override — for sheets with padding; defaults to floor(texWidth / cellWidth). */\n cols?: number;\n /** Pixel origin of the grid in the texture — cells index from here (a SpriteSheet region). */\n origin?: [number, number];\n /** Default fps for clips that don't override it. */\n fps: number;\n /** Default loop for clips that don't override it. */\n loop: boolean;\n /** Named clips; frame indices are row-major into the grid. Set via the attach opts. */\n clips: Record<string, Clip>;\n /** Facing names in texture-row order (row i = directions[i]) for `perDirection` clips. */\n directions?: string[];\n private _clipIds;\n private _clipNames;\n private _current;\n private _defined;\n private _queued;\n private _dir;\n onAttach(): void;\n /** (Re)build native clips from `this.clips`. Called on attach; call again after changing clips. */\n define(): this;\n private _define;\n /**\n * Play a clip by name. Re-playing the active clip is a no-op (keeps it running smoothly).\n * For a `perDirection` clip, `dir` picks the facing — a direction name or a movement vector\n * (nearest compass row wins); omitted, the last direction (or the first row) is kept.\n */\n play(name: string, dir?: string | Vec2Like): this;\n stop(): this;\n /** Current facing (last direction resolved by play()), or null before the first directional play. */\n get direction(): string | null;\n set speed(value: number);\n get current(): string | null;\n get frame(): number;\n private _resolveDir;\n}\n","types/g2/SpriteSheet.d.ts":"import { type Vec2Like } from \"../math/vec\";\nimport { Sprite } from \"./Sprite\";\nimport { SpriteAnimation, type Clip } from \"./SpriteAnimation\";\nimport { Texture2D } from \"./Texture2D\";\n/**\n * A named region of the image. Just a rect is a static sprite; `slice` subdivides the rect into an\n * animation grid ([cols, rows] — the cell is rect size / counts); `clips` names frame runs over\n * that grid (local, row-major). A sliced entry with NO clips loops all of its cells in order.\n */\nexport type SheetSprite = {\n /** Pixel rect [x, y, w, h] in the image. */\n rect?: [number, number, number, number];\n /** Subdivide the rect into an animation grid: [cols, rows]. */\n slice?: [number, number];\n /** Playback fps for this sprite's animation (defaults to the sheet fps, then 12). */\n fps?: number;\n /** Named clips over the local grid (see SpriteAnimation). Omit to loop every cell. */\n clips?: Record<string, Clip>;\n /** Facing names in local-row order for `perDirection` clips (compass tokens: S/SE/E/…). */\n directions?: string[];\n /** Overrides the sheet anchor. */\n anchor?: Vec2Like;\n};\nexport type SpriteSheetDef = {\n /** The image URL — write `asset('./sheet.png')`. */\n image: string;\n /** Default pivot for every sprite made from this sheet ([0.5, 1] = feet, for Y-sorted worlds). */\n anchor?: Vec2Like;\n /** Default fps for sliced sprites / clips that don't override it. */\n fps?: number;\n /** The named sprites. */\n sprites?: Record<string, SheetSprite>;\n};\nexport type SpriteMakeOptions = {\n position?: Vec2Like;\n layer?: number;\n /** Overrides the sheet/sprite anchor. */\n anchor?: Vec2Like;\n /** Start this clip immediately (sliced sprites with clips). */\n clip?: string;\n /** Initial facing for `perDirection` clips. */\n direction?: string;\n};\nexport declare class SpriteSheet {\n private _def;\n private _tex;\n private _loading;\n constructor(def: SpriteSheetDef);\n /** The sheet definition (read-only by convention — the editor owns the file). */\n get def(): SpriteSheetDef;\n /** The loaded texture, or null before load() resolves. */\n get texture(): Texture2D | null;\n /** Load the sheet's texture (idempotent). make() starts this automatically. */\n load(): Promise<Texture2D>;\n /** Names of the sheet's sprites. */\n get spriteNames(): string[];\n /** Build a named sprite; starting a clip hands back the animation handle. */\n make(name: string, opts: SpriteMakeOptions & {\n clip: string;\n }): Sprite & {\n anim: SpriteAnimation;\n };\n make(name: string, opts?: SpriteMakeOptions): Sprite;\n /** The pixel rect [x, y, w, h] of a named sprite's REGION (the whole rect, sliced or not). */\n rectOf(name: string): [number, number, number, number] | null;\n private _applyTexture;\n}\n/** Declare a sprite sheet (the default export of a `.sprite.ts` file). */\nexport declare const defineSpriteSheet: (def: SpriteSheetDef) => SpriteSheet;\n","types/g2/Texture2D.d.ts":"import { type FetchResponse, type File } from \"../runtime/fetch\";\nexport declare class Texture2D {\n /** Native texture handle. */\n readonly id: number;\n readonly width: number;\n readonly height: number;\n constructor(id: number, width: number, height: number);\n static fromCanvas(canvas: {\n _bakeSurface(): number;\n width: number;\n height: number;\n pixelRatio: number;\n }): Texture2D;\n static load(source: string | FetchResponse | File): Promise<Texture2D>;\n destroy(): void;\n}\n","types/g2/Tilemap.d.ts":"import { Node2D } from \"./Node2D\";\nimport type { Texture2D } from \"./Texture2D\";\nexport type TilemapOptions = {\n texture: Texture2D;\n /** Map grid size (in tiles). */\n cols: number;\n rows: number;\n /** On-screen cell size in world units — a single number (square) or [w, h]. */\n tile: number | [number, number];\n /** Atlas grid: how the texture is sliced into tiles, [atlasCols, atlasRows]. */\n atlas: [number, number];\n /** Row-major tile indices into the atlas (-1 = empty), length cols*rows. Row 0 is the top row. */\n data: number[] | Int32Array;\n};\nexport declare class Tilemap extends Node2D {\n readonly cols: number;\n readonly rows: number;\n constructor(options: TilemapOptions);\n setTile(x: number, y: number, index: number): this;\n}\n","types/g2/Tileset.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { Node2D } from \"./Node2D\";\nimport { type TilesetDef, type TileMaterial } from \"./autotile\";\nexport declare class Tileset {\n private _def;\n constructor(def: TilesetDef);\n /** The tileset definition (read-only by convention — the editor owns the file). */\n get def(): TilesetDef;\n /** Names of the declared materials, in file order. */\n get materialNames(): string[];\n /** A material by name. */\n material(name: string): TileMaterial | undefined;\n /** The cell value maps store for a named material (what you paint / pass in `data`). */\n id(name: string): number | undefined;\n /** Derive display atlas indices from a material-id grid (what Autotile2D does at load). */\n derive(cols: number, rows: number, data: ArrayLike<number>, seed?: number): Int32Array;\n}\n/** Declare a tileset (the default export of a `.tiles.ts` file). */\nexport declare const defineTileset: (def: TilesetDef) => Tileset;\n/**\n * Marks a tilemap node's `cells` as MATERIAL ids of a tileset instead of raw atlas indices:\n * `aspects: [use(Autotile2D, { tileset: world })]`. The scene2d loader derives the display\n * indices (neighbor-mask autotile + seeded scatter, deterministic) before building the tilemap;\n * the aspect itself holds no behavior. Change `seed` to reshuffle scatter variants.\n */\nexport declare class Autotile2D extends Aspect<\"autotile\", Node2D> {\n static readonly aspect = \"autotile\";\n /** The imported `.tiles.ts` handle. */\n tileset: Tileset | null;\n /** Scatter seed — same seed, same map, same result on every platform. */\n seed: number;\n}\n","types/g2/touch.d.ts":"/** Register the host pointer callback once, on the first click/touchstart listener (node or scene). */\nexport declare const ensurePointerEvents: () => void;\n","types/g2/Trigger2D.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { PhysicsGroup2D } from \"./groups2d\";\nimport type { Node2D } from \"./Node2D\";\nexport declare class Trigger2D extends Aspect<\"trigger\", Node2D> {\n static readonly aspect = \"trigger\";\n private _h;\n private _enabled;\n private _group;\n private _repush;\n /** Which collision group this zone belongs to. Live. */\n get group(): PhysicsGroup2D | undefined;\n set group(g: PhysicsGroup2D | undefined);\n /** Native physics body id (0 if no physics support). Mirrors 3D `Trigger.id`. */\n get id(): number;\n onAttach(): void;\n onDetach(): void;\n /** Switch the zone off and on — a spent pickup, a hitbox that is only live during a swing. */\n get enabled(): boolean;\n set enabled(v: boolean);\n}\n","types/gl/animation/AnimationClip.d.ts":"import { type FetchResponse } from \"../../runtime/fetch\";\nimport type { Vec3Like } from \"../../math/vec\";\nimport type { QuatLike } from \"../../math/quat\";\n/** A keyframe: `[time (s), value]`. */\nexport type ClipKey<V> = [number, V];\nexport type ClipInterpolation = \"linear\" | \"step\";\n/** Curves for one target node (bone name), any subset of the three channels. */\nexport type ClipTrackDef = {\n position?: ClipKey<Vec3Like | [number, number, number]>[];\n rotation?: ClipKey<QuatLike | [number, number, number, number]>[];\n scale?: ClipKey<Vec3Like | [number, number, number]>[];\n interpolation?: ClipInterpolation;\n};\nexport type ClipDef = {\n /** Clip length in seconds — defaults to the last key time across all tracks. */\n duration?: number;\n /** Target node name → its curves. Names bind to bones (or any child node) at Animator attach. */\n tracks: Record<string, ClipTrackDef>;\n};\nexport type ClipInfo = {\n name: string;\n duration: number;\n trackCount: number;\n};\n/** What `AnimationClip.from(clip, …)` derives from a clip. */\nexport type DeriveOptions = {\n /** The clip MIRRORED — left ↔ right, the motion on the other side of the body (a stop that brakes on the\n * left foot brakes on the right). Derived on the rig of the clip's own file (joints pair by name, the\n * sagittal plane comes from the rest pose), so the result is the same on every model: its contacts,\n * phase, root motion and heading are the mirrored ones, its name is `<name>_M`. Only clips from a GLB\n * carry a rig; a curve-built clip cannot be mirrored. */\n mirror?: boolean;\n /** Start of the window, seconds of the source (default 0). */\n from?: number;\n /** End of the window, seconds of the source (default the clip's end). */\n to?: number;\n};\nexport declare class AnimationClip {\n /** Source name (the clip's name inside its file; `\"clip\"` for procedural clips). Informational —\n * an Animator addresses clips by the key YOU give it. */\n readonly name: string;\n /** Length in seconds. */\n readonly duration: number;\n /** Number of animated (node, channel) tracks. */\n readonly trackCount: number;\n private constructor();\n /** Mark a moment of the clip (SECONDS from its start) with an event name: `kick.addEvent(0.4, 'hit')`\n * → `anim.on('hit', (clip, layer) => …)` fires when the playhead crosses it, loops included.\n * Events are part of the clip: every model playing it gets them; `AnimationClip.from(clip, { from, to })`\n * keeps the ones inside the window, re-timed. Chainable. */\n addEvent(time: number, name: string): this;\n private _pushEvents;\n /** ANCHOR SPANS for a bone — what an anchored IK chain ending in `bone` rides while this clip plays\n * (`IK.TwoBone` with `anchor`; the sockets come from `anim.sockets(...)`). `donor` names the socket\n * set of the gun the take was AUTHORED on ('' = the live set: no delta); `spans` = `[from, to,\n * socket, rotation?, pin?]` in SECONDS — the socket the hand is on through that window (`''` = free:\n * it rides the joint itself), `rotation` 0..1 how much of the socket's turn it takes (default 1),\n * `pin` 0..1 how much it sits ON the socket instead of keeping its own relation to it (default 0: a\n * magazine is REACHED, and the take's motion is what carries the hand there).\n * Gaps between spans = the chain's own socket, pinned by the chain's `anchorPin` — that is where a\n * hand holding the gun is nailed to the grip, so the layers below cannot slide it. A clip WITHOUT\n * anchors takes no part: the hand keeps the take's own relation to the gun. Part of the clip, like\n * events; `AnimationClip.from` carries them re-timed. Chainable.\n * reload.anchors('hand_l', { donor: 'tr15', spans: [[0.9, 1.4, 'mag'], [1.4, 2.0, ''], [2.0, 2.4, 'mag'], [2.4, 2.7, 'bolt']] }) */\n anchors(bone: string, def: {\n donor?: string;\n spans?: readonly (readonly [number, number, string, number?, number?])[];\n }): this;\n /** Drop a bone's anchor spans. */\n clearAnchors(bone: string): this;\n private _pushAnchors;\n /** Load ONE clip from a GLB: the file's only/first clip, or the one named / at the given index. */\n static load(source: string | FetchResponse, clip?: string | number): Promise<AnimationClip>;\n /** Load EVERY clip of a GLB (library files), keyed by clip name. */\n static loadAll(source: string | FetchResponse): Promise<Record<string, AnimationClip>>;\n /** Build a clip from curves in code — no DCC needed. Keys are `[time, value]`; a track binds to the\n * node of that name when the clip is used by an Animator (bones, or any child node). */\n static fromCurves(def: ClipDef): AnimationClip;\n /** A NEW clip derived from `clip`: its mirror (`{ mirror: true }` — the other side of the body), a window\n * of it (`{ from, to }` seconds of the source, re-timed to 0; array-slice semantics), or both. Cut a\n * too-long take down to the action, carve several sub-clips out of one packed timeline, get the\n * left-footed stop from the right-footed one:\n *\n * clips: { Kick: AnimationClip.from(kick, { from: 0.2, to: 1.1 }), StopM: AnimationClip.from(stop, { mirror: true }) }\n *\n * A window drops the keys outside it and interpolates exact boundary values in, so the clip starts and\n * ends precisely on the source's pose at the cut points. Everything downstream (blend spaces, events'\n * times, root motion, foot contacts, phase sync) sees a normal clip. */\n static from(clip: AnimationClip, options: DeriveOptions): AnimationClip;\n private static _label;\n private static _loadSet;\n}\n","types/gl/animation/Animator.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport { type QuatLike } from \"../../math/quat\";\nimport type { Node } from \"../Node\";\nimport type { AnimationClip } from \"./AnimationClip\";\nimport { type ActiveClip, type ClipInfo, type ClipEventHandler, type LayerOptions, type LoopDef, type LoopOptions, type PlayOptions, type StopOptions } from \"./core\";\nimport { Feet } from \"./Feet\";\nimport { Warp } from \"./Warp\";\nimport type { Loop } from \"./Loop\";\nimport type { Layer } from \"./Layer\";\nimport type { Playback } from \"./Playback\";\n/** Level of detail for a GLB instance (docs/lod-plan.md): `'auto'` = the engine's pick by screen size and\n * visibility, or a fixed level 0 (full) … 3 (coarsest mesh, animation every 4th frame without fingers). */\nexport type LodMode = \"auto\" | 0 | 1 | 2 | 3;\nexport declare class Animator extends Aspect<\"anim\", Node> {\n static readonly aspect = \"anim\";\n private _c;\n private _rootMotion;\n private _rootRotation;\n /** The feet: the contact bones, the foot lock, ground IK, footstep events. See `Feet`. */\n feet: Feet;\n /** The warp: stride and orientation fitted to the body's real motion, the step warp dials. See `Warp`. */\n warp: Warp;\n onAttach(): void;\n onDetach(): void;\n /** The clip list, in order: the GLB's embedded clips, then the clips you added (an added clip with an\n * embedded clip's name takes its place). */\n get clips(): readonly AnimationClip[];\n /** One clip by name or index — the resource: its name, duration, tracks, events. `undefined` if none. */\n clip(ref: string | number): AnimationClip | undefined;\n /** Add a clip under a name (default: its own) — from another file, procedural, or sliced. Chainable. */\n addClip(name: string | AnimationClip, clip?: AnimationClip): this;\n /** What the engine measured about a clip on THIS skeleton (unlike `clip()`, which is the file's data):\n * speed, travel, turn, the foot contacts, the gait phase, its cycle, and comparisons with other clips.\n * Binds the clip on first ask. `undefined` if there is no such clip. */\n clipInfo(clip: string | number): ClipInfo | undefined;\n /** Play a one-shot: by name, index, or the first clip. It takes the layer over from whatever it showed,\n * transitioned over `fade`. `await` the Playback: it resolves at the hand-over (`true`, or `false` if cut\n * short), and what you start right then is what the clip hands over to (nothing = back to the loop). */\n play(clip?: string | number, options?: PlayOptions): Playback;\n /** Set the LOOP — what shows when no one-shot plays: a clip, or a blend space (`{ Idle: 0, Run: 6 }`, drive\n * the returned object's `value`). Takes the layer over, a one-shot included. `stop()` removes it. */\n playLoop(def: LoopDef, options?: LoopOptions): Loop | undefined;\n /** Fade everything out, on every layer → the rest pose. */\n stop(options?: StopOptions): this;\n /** The current loop (the object the last `playLoop()` returned), if any. */\n get loop(): Loop | undefined;\n /** A one-shot hasn't handed over yet. */\n get busy(): boolean;\n /** What every layer shows this frame, with weights: a one-shot, or a loop's members with their shares. */\n get active(): ActiveClip[];\n /** Where the base layer is in the GAIT CYCLE: 0 at a left-foot-down, 0.5 at a right-foot-down; -1 when\n * what plays has no cycle. What `play(clip, { phase: 'match' })` matches against. */\n get phase(): number;\n /** A clip's playhead, seconds (-1 = not bound). */\n time(clip: string | number): number;\n /** Scrub a clip's playhead, seconds — inspectors and debug boards (pair with `speed = 0`). Nothing is\n * faded or re-picked. */\n seek(clip: string | number, time: number): void;\n /** Re-aim a playing turn clip's warp (`play({ turn })`) to `deg` for the rest of the clip; `undefined` = off. */\n setTurn(clip: string | number, deg: number | undefined): void;\n /** Global playback rate: 0.3 = slow-mo, 0 = pause. */\n get speed(): number;\n set speed(v: number);\n /** Clip events (`clip.addEvent(0.4, 'hit')` → `anim.on('hit', …)`). */\n on(event: string, cb: ClipEventHandler): this;\n off(event: string, cb: ClipEventHandler): this;\n /** A new layer on top (masked override / additive); the returned object is its handle. */\n addLayer(options?: LayerOptions): Layer;\n /** The root bone's horizontal travel comes OFF the pose and moves the node — or its CharacterController\n * (on this node or an ancestor) as a velocity, so it collides. For clips whose hips actually travel. A\n * character under a `Locomotion` gets this from its displacement mode instead. */\n get rootMotion(): boolean;\n set rootMotion(on: boolean);\n /** With `rootMotion`: the root bone's TURN is root motion too — it comes off the pose and turns the node,\n * so a turn clip leaves the character facing where it took it. Off by default (a walk's hip sway is a\n * turn too); on for a rig whose root carries the heading (`lecodes assets retarget --root-rotation yaw`). */\n get rootRotation(): boolean;\n set rootRotation(on: boolean);\n /** The body's WORLD velocity this frame (m/s): what `anim.warp`'s stride and orientation fit the clips\n * to. A `Locomotion` feeds it itself; when you drive the gait by hand set it every frame (the\n * CharacterController's velocity, or your own). Reads back the last value fed. */\n get motion(): readonly [number, number, number];\n set motion(v: {\n x: number;\n y: number;\n z: number;\n } | readonly [number, number, number]);\n private _motion;\n /** SOCKETS: named frames on a bone of this rig — a weapon's grip / magazine / bolt empties, placed in\n * the scene editor. A NODE socket is read by the engine every frame (a socket on a moving part\n * follows it); a `{ position, quaternion }` one is fixed in the bone's space. The default set is the\n * LIVE one (the weapon in the hands); `set: 'tr15'` names a DONOR set — the same sockets on the gun a\n * take was authored on, which a clip's `anchors()` refer to. Chainable.\n * arms.anim.sockets('ik_hand_gun', { grip_r: w.gripR, grip_l: w.gripL, mag: w.mag })\n * arms.anim.sockets('ik_hand_gun', { grip_l: { position: [0.03, -0.12, -0.05] } }, { set: 'tr15' }) */\n sockets(joint: Node | string, table: Record<string, Node | {\n position?: Vec3Like;\n quaternion?: QuatLike;\n }>, options?: {\n set?: string;\n }): this;\n /** Drop a socket (the live set, or `set`). */\n removeSocket(name: string, set?: string): this;\n /** `'auto'` (default): a character small on screen or out of view is evaluated every 2nd / 4th frame\n * without its finger, toe and twist joints; `'full'`: every frame, every joint (a hero seen through a\n * scope). Independent of `Model.lod`, the mesh level. */\n get lod(): \"auto\" | \"full\";\n set lod(v: \"auto\" | \"full\");\n /** The native animator's id — 0 until something is played or bound. */\n get _id(): number;\n /** Bind a clip to the base layer without playing it; its native slot (-1 = no such clip). */\n _slot(clip: string | number): number;\n}\n","types/gl/animation/core.d.ts":"import { AnimationClip } from \"./AnimationClip\";\nimport { Loop } from \"./Loop\";\nimport { Layer } from \"./Layer\";\nimport { Playback } from \"./Playback\";\nimport { Vec3 } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\n/** A position on a blend axis (1D) or plane (2D). */\nexport type BlendPosition = number | readonly [number, number];\nexport type PlayOptions = {\n /** Transition seconds — how long the difference to the pose the layer SHOWED (its loop, a one-shot,\n * or rest) takes to decay. Default `0` = cut: a fade is always asked for, never implied. Also the\n * transition back to the loop at the end unless `fadeOut` overrides it. */\n fade?: number;\n /** Transition seconds for the way in only (overrides `fade`). */\n fadeIn?: number;\n /** One-shots: the transition BACK to the loop after the end (overrides `fade`; `0` = cut at the end).\n * The clip plays to its last frame; the loop then takes over and the difference between the two poses\n * (and their velocities) decays over this time, so no part of the clip is cut — to play less of it,\n * give it an `end`. On a layer with no loop the clip HOLDS its last frame (a rock that broke stays\n * broken) — `anim.stop({ fade })` is the way back to rest. */\n fadeOut?: number;\n /** Playback rate for this clip (default 1). */\n speed?: number;\n /** Rewind even if the clip is already playing (default: rewind only if it isn't). */\n restart?: boolean;\n /** Play a WINDOW of the clip, seconds of the clip: enter at `start` (default 0; only when the play\n * rewinds — see `restart`) and treat `end` (default the clip's end) as the end — the hand-over fires\n * there, the last frame held there, events beyond it never fire. Only the swing of a longer take, the\n * wind-up without the recovery. A window that lives in the clip table belongs in\n * `AnimationClip.from(clip, { from, to })` instead. Not combined with `phase`. Hosts without the\n * window play the whole clip. */\n start?: number;\n end?: number;\n /** Enter the clip at a point in the GAIT CYCLE instead of at its start: `'match'` = the phase the\n * layer shows right now (the walk's left foot is down → the turn clip starts where its left foot\n * is down too, so nothing slides), or a number 0–1. Clips without a gait cycle ignore it. */\n phase?: number | \"match\";\n /** TURN WARP (degrees, + = left): the node turns this much in total over the clip instead of what the\n * clip's baked heading says — its turn curve scaled, so the difference grows where the clip turns and\n * pivots about the planted foot. A 45° start played with `turn: 60` turns 60; played with `turn: 45`\n * it lands on 45 exactly whatever the clip's own run-off. Needs `rootMotion` + `rootRotation` and a\n * clip with a baked heading (`lecodes assets marks` / `retarget`); a clip that turns under 10° is\n * left alone. Ignored by hosts without it. */\n turn?: number;\n};\nexport type StopOptions = {\n fade?: number;\n};\nexport type LoopOptions = {\n /** Transition seconds from whatever the layer shows — its previous loop, a one-shot still playing,\n * or rest. Default `0` = cut: a loop wanting a transition asks for one (`{ fade: 0.2 }`). */\n fade?: number;\n /** Playback rate of the loop's clips (default 1). */\n speed?: number;\n /** Where in the CYCLE to start, 0–1, or `'match'` = where the layer is now (what a gait loop taking\n * over from a start / turn clip wants). The members share one clock, so this is every member's phase. */\n phase?: number | \"match\";\n};\n/** A blend member with its CYCLE given explicitly: `at` = its position, `offset` = its gait phase at t = 0\n * (0 = a left-foot-down, 0.5 = a right-foot-down, 0–1), `cycles` = how many gait cycles the clip holds\n * (a two-stride loop: 2). Both are measured offline from the clip's foot marks. Members given as a\n * bare position run in normalized time and have no cycle (nothing phase-matches to them). */\nexport type BlendMember = {\n at: BlendPosition;\n offset?: number;\n cycles?: number;\n};\n/** What a layer loops: one clip (name / index), or a blend space `{ name: position | { at, offset, cycles } }`. */\nexport type LoopDef = string | number | Record<string, BlendPosition | BlendMember>;\n/** One clip the layer shows this frame — `layer.active` / `anim.active` (a debug overlay's list). */\nexport type ActiveClip = {\n name: string;\n clip: AnimationClip;\n /** contribution to the pose, 0–1: the shown one-shot 1, a loop member its blend share */\n weight: number;\n /** clock (s) */\n time: number;\n /** a member of the layer's loop (else the layer's one-shot) */\n loop: boolean;\n};\nexport type LayerOptions = {\n /** Bone name(s): the layer drives only these subtrees (`'Spine1'` = upper body). Default: the whole rig. */\n mask?: string | string[];\n /** Blend each clip's DELTA from its own first frame on top of the layers below (lean, breathe, recoil)\n * instead of overriding them. */\n additive?: boolean;\n /** Layer contribution 0–1 (default 1). */\n weight?: number;\n};\nexport type ClipEventHandler = (clip: string, layer: Layer) => void;\n/** A foot planted: which one, and where in the world it landed. */\nexport type StepHandler = (side: \"left\" | \"right\", position: Vec3) => void;\n/** A loop's GAIT CYCLE as two numbers — what a blend member's `{ offset, cycles }` wants: φ(t) = offset +\n * cycles · t / duration, 0 = a left-foot-down. `residual` = the worst foot-down's distance from that line\n * (cycles; a clean loop sits under 0.03), `steps` = the foot-downs it was fitted through. */\nexport type ClipCycle = {\n offset: number;\n cycles: number;\n residual: number;\n steps: number;\n};\n/** A loop's cycle found by POSE against a reference loop (`clipInfo(clip).alignTo(ref)`): the `{ offset,\n * cycles }` under which it shows the reference's pose at the reference's phase. `score` = the fit at that\n * alignment (metres, the joint distance + velocity measure), `margin` = how much worse the runner-up\n * alignment ≥ 0.2 cycle away is — near 0 means ambiguous (a mirror pair, an in-place idle). */\nexport type ClipAlign = {\n offset: number;\n cycles: number;\n score: number;\n margin: number;\n};\n/** What the engine measured on a clip once it was bound to this skeleton (`anim.clipInfo('Walk')`).\n * The root curves are of the clip's ROOT bone — its travel is what root motion would move. */\nexport type ClipInfo = {\n /** total horizontal root travel, metres */\n travel: number;\n /** mean root speed over the clip, m/s */\n speed: number;\n /** total root yaw, radians (+ = left) */\n turn: number;\n /** the root barely moves — an in-place clip */\n inPlace: boolean;\n /** The gait cycle fitted through the foot contacts (a foot already down at t = 0 is not a step) —\n * the numbers a blend member takes as `{ offset, cycles }`. Undefined: no steps. */\n cycle(): ClipCycle | undefined;\n /** This loop's cycle found by POSE against `reference` (its cycle given, else `reference`'s `cycle()`,\n * else offset 0 / one cycle — the answer is then relative to the reference's own time). Reads no marks:\n * a markless loop (swimming, breathing, an upper-body sway) gets a cycle, and a marked one gets a\n * second opinion — a mirrored anchor shows as a 0.5 disagreement with `cycle()`. Undefined: nothing to compare. */\n alignTo(reference: string | number, cycle?: {\n offset: number;\n cycles: number;\n }): ClipAlign | undefined;\n /** the clip has a gait cycle (feet planting in turn) — `phaseAt` is meaningful */\n hasPhase: boolean;\n /** When each foot TOUCHES the ground, seconds — the phase anchor. `still` is the window inside it\n * where the foot is genuinely STATIONARY (a touching foot still rolls for its first beats, and a\n * stop take's final plant touches long before the body has braked); absent = never still.\n * `at` = where the foot is at the touch's start ([x, y, z], model space). */\n contacts: {\n side: \"left\" | \"right\";\n from: number;\n to: number;\n at: [number, number, number];\n still?: {\n from: number;\n to: number;\n };\n }[];\n /** the HANDS on the ground (a cartwheel, a roll, a vault) — from the clip's marks in the GLB; empty when none */\n hands: {\n side: \"left\" | \"right\";\n from: number;\n to: number;\n at: [number, number, number];\n still?: {\n from: number;\n to: number;\n };\n }[];\n /** A CLIMBING clip's tread levels (a stair or slope take): the model-space heights its feet plant\n * at, sorted ascending, with the riser (median level spacing — the step height the clip was\n * authored for). Absent on a flat clip. */\n treads?: {\n riser: number;\n levels: number[];\n };\n /** the gait phase at `time`: 0 at a left-foot-down, 0.5 at a right-foot-down; -1 without a cycle */\n phaseAt(time: number): number;\n /** cumulative root travel (m) at `time` */\n travelAt(time: number): number;\n /** cumulative root yaw (rad, + = left) at `time` */\n turnAt(time: number): number;\n /** the root's own speed at `time`, m/s — how fast the clip is moving the body right there */\n speedAt(time: number): number;\n /** the PELVIS' yaw relative to the clip's heading at `time` (rad, + = left, wrapped to ±π): the stance twist\n * the heading leaves out — an idle stands ~43° off the course it starts along, a stop's tail turns into that\n * stance while the heading holds. A controller that switches clips mid-pose can keep the PELVIS continuous\n * (turn the node by the difference between the two clips' values) where keeping the course would swing\n * the body. Without a baked heading: the pelvis' yaw at frame 0 throughout. */\n pelvisYawAt(time: number): number;\n /** the unit travel direction at `time` ([x, z], model space, held through stills) — integrate\n * direction × d(travel) to reconstruct the root's 2D path (a treadmill display, a turn's arc) */\n directionAt(time: number): [number, number];\n /** the first time the clip has turned `yaw` radians (+ = left): where to enter a turn a body has\n * already begun, so the clip continues the move instead of restarting it */\n timeAtTurn(yaw: number): number;\n /** How far this clip's pose is from `target`'s, in metres — the joint distance plus the velocity\n * difference over a tenth of a second, the planted foot weighted most. That difference is exactly\n * what a hand-over hands the transition to decay away, so it says what switching to `target` would\n * cost at `time`. The two are lined up by cycle PHASE (a clip that continues the walk) or by TIME\n * (`align: 'time'` — two clips that both begin from standing share no cycle). */\n fitTo(target: string | number, time: number, options?: {\n align?: \"phase\" | \"time\";\n }): number | undefined;\n /** The earliest moment (seconds) at which handing over to `target` costs no more than `within`\n * metres — a start's last steps ARE the walk, so this is where it stops being worth playing.\n * `atContact` (default true) snaps to the next foot-down: a switch under a planted foot is the one\n * the eye forgives. -1 = the clip never gets that close. */\n exitTo(target: string | number, options?: {\n within?: number;\n atContact?: boolean;\n align?: \"phase\" | \"time\";\n }): number;\n /** The knee's bend plane at `time`, predicted from the skeleton's calibrated hinge axis carried by\n * this clip's own thigh rotation — continuous even where the leg is straight (where a plane\n * derived from positions is pure noise). `pole` = unit direction from the hip→ankle line toward\n * the knee (a two-bone solver's bend direction), `normal` = the plane's normal; both in the model\n * pose's frame. Undefined = no leg chain, or no knee motion bound to calibrate from. */\n kneePoleAt(side: \"left\" | \"right\", time: number): {\n pole: [number, number, number];\n normal: [number, number, number];\n } | undefined;\n /** The clip's baked physics at `time` (unit body mass, model space): `com` = the body's center of\n * mass (biomechanical segment fractions on the classified bones), `velocity` = its velocity\n * (= linear momentum per kg), `angular` = the angular momentum about the COM (m²/s per kg,\n * low-passed ~0.5 s — the REGULATED component, e.g. a turn's sustained yaw; the per-stride\n * pitch/roll exchange between the limbs and the trunk is filtered out),\n * `support` = per-foot load [left, right] — contact-gated, split by where the COM stands between\n * the feet, scaled by the vertical force proxy (above 1 on a landing impact, 0 in flight).\n * A model, not a measurement — meant for ranking transitions and display, both sides of any\n * comparison sharing the same model. Undefined = nothing classified on this skeleton. */\n physicsAt(time: number): {\n com: [number, number, number];\n velocity: [number, number, number];\n angular: [number, number, number];\n support: [number, number];\n } | undefined;\n /** The clip's MATCHING FEATURE ROW at `time` — a fresh Float32Array(37) in the clip's heading\n * frame at that time (x lateral, + left; y up; z forward): 0–5 feet positions relative to the\n * pelvis' ground point, 6–11 feet velocities, 12–14 pelvis velocity, 15 pelvis height, 16–18\n * COM velocity, 19–20 support L/R, 21–22 contact phase L/R, 23 yaw angular momentum, 24–31 the\n * clip's own path 0.3/0.6/1.0/1.5 s ahead as (lateral, forward) pairs, 32–35 facing change at\n * those horizons (rad, + = left), 36 cyclic flag. What a trajectory-and-state matcher compares.\n * Undefined = no leg chain. */\n featuresAt(time: number): Float32Array | undefined;\n /** The take is a LOOP by measurement: its seam is continuous (feet back where they started\n * relative to the root, no turn). Starts, stops and turns are not. */\n cyclic: boolean;\n};\n/** The calibrated knee hinge-axis report (`anim.feet.kneeAxis('left')`): the axis in the thigh's local\n * frame, and the calibration's own confidence — the angular spread of its measurements (radians;\n * a real knee comes in at a few degrees) over `samples` consecutive-frame deltas of the pack.\n * `plant` = the calibrated PLANT HEIGHTS (model space): where the ankle / toe actually sit under\n * full weight, the median of the pack's still-window lows — absent when nothing plants. */\nexport type KneeAxisReport = {\n axis: [number, number, number];\n spreadMean: number;\n spreadMax: number;\n samples: number;\n plant?: {\n ankleY: number;\n toeY: number;\n };\n};\n/** A clip bound to a layer — one per (clip, layer), reused by every play. `playback` = the most recent\n * one-shot on it (`playing` while it still owns the layer; kept after that so its handle can still be\n * read — a restart re-enters the same slot with a new record). */\nexport type SlotRec = {\n name: string;\n clip: AnimationClip;\n slot: number;\n layer: LayerRec;\n inBlend: boolean;\n playback?: PlaybackRec;\n};\nexport type PlaybackRec = {\n slot: SlotRec;\n playing: boolean;\n done: Promise<boolean>;\n resolve: (natural: boolean) => void;\n};\nexport type LayerRec = {\n index: number;\n view: Layer;\n slots: SlotRec[];\n loop?: LoopRec;\n weight: number;\n mask: string;\n additive: boolean;\n};\nexport type LoopRec = {\n layer: LayerRec;\n members: {\n name: string;\n slot: SlotRec;\n }[];\n value: BlendPosition;\n view: Loop;\n dead: boolean;\n};\nexport declare class Core {\n id: number;\n /** Added clips by name (`addClip`) — the lookup index; an added name overrides an embedded one. */\n readonly table: Map<string, AnimationClip>;\n readonly layers: LayerRec[];\n speed: number;\n private _embedded?;\n private readonly _added;\n private _list?;\n private readonly _listeners;\n readonly node: Node;\n constructor(node: Node);\n embedded(): AnimationClip[];\n /** The ordered clip list: the GLB's clips in file order (an added clip of the same name takes the\n * embedded one's place), then the remaining added clips in insertion order. Cached until addClip. */\n clips(): AnimationClip[];\n addClip(name: string, clip: AnimationClip): void;\n /** A clip by name (added first, then embedded), or by index into `clips()` (none = the first). */\n resolveClip(ref: string | number | undefined): [string, AnimationClip] | undefined;\n private clipNames;\n /** Create the native animator on demand. False = nothing to animate (warned). */\n ensure(): boolean;\n /** The native animator for the RIG alone — an IK chain or a socket on a model that has no clips\n * still needs the joint tree described to the engine. False = no transform hierarchy (warned). */\n ensureRig(): boolean;\n destroy(): void;\n newLayer(options?: LayerOptions): LayerRec;\n addLayer(options: LayerOptions): Layer;\n /** Arm the layer's next transition with a wind-up: see `Layer.anticipate`. */\n anticipate(L: LayerRec, amount: number): void;\n pushLayer(L: LayerRec): void;\n /** The layer's slot for the clip — bound on first use, reused after that. */\n slotFor(L: LayerRec, name: string, clip: AnimationClip): SlotRec | undefined;\n /** The base layer's native slot for a clip, bound on first ask (-1 = no such clip / no animator). */\n slotIndex(ref: string | number): number;\n play(L: LayerRec, ref: string | number | undefined, o: PlayOptions): Playback;\n /** A one-shot on the layer hasn't handed over yet. */\n busy(L: LayerRec): boolean;\n settle(p: PlaybackRec, natural: boolean): void;\n /** Resolve every pending playback on the layer as cut short. */\n private settleLayer;\n stopSlot(s: SlotRec, fade: number): void;\n stopLayer(L: LayerRec, fade: number): void;\n stopAll(fade: number): void;\n loop(L: LayerRec, def: LoopDef, o: LoopOptions): Loop | undefined;\n /** The phase the layer shows, 0–1 through the gait cycle (-1 = nothing / no cycle). */\n layerPhase(L: LayerRec): number;\n /** The entry phase of a play / playLoop: a number as given, `'match'` = what the layer shows now\n * (undefined when it shows no cycle — then the clip starts at its own beginning). */\n private entryPhase;\n /** The loop's phase through its cycle, 0–1 (the members share one clock). */\n loopPhase(b: LoopRec): number;\n setLoopPhase(b: LoopRec, phase: number): void;\n setLoopValue(b: LoopRec, v: BlendPosition): void;\n /** What the layer shows this frame: its source — the one-shot, or the loop's members with their\n * blend shares — in binding order (stable rows). */\n active(L: LayerRec): ActiveClip[];\n slotWeight(s: SlotRec): number;\n /** The slot's gait phase now, wrapped into 0–1 (-1 without a cycle). */\n slotPhase(s: SlotRec): number;\n /** A baked curve of the slot at its current time: 1 travel (m) / 2 yaw (rad) / 3 speed (m/s). */\n slotCurveAt(s: SlotRec, which: 1 | 2 | 3): number;\n /** The clip's total root yaw, radians (+ = left). */\n slotTurn(s: SlotRec): number;\n slotTime(s: SlotRec): number;\n seek(s: SlotRec, time: number): void;\n /** Scrub: set a bound clip's playhead directly, seconds — an inspector's tool. */\n seekTime(ref: string | number, time: number): void;\n /** Re-aim a playing clip's TURN WARP (see `PlayOptions.turn`): the clip's baked heading is scaled so that the\n * whole clip turns `deg` — set mid-play, the scale applies to what is still to come, so a controller that\n * wants a different heading while a turn plays asks for (the clip's total × what it still needs / what\n * the clip still turns). Undefined `deg` switches the warp off. */\n setTurnOf(ref: string | number, deg: number | undefined): void;\n /** A bound clip's current playhead, seconds (-1 = not bound). */\n timeOf(ref: string | number): number;\n /** What the engine measured on the clip once it was bound to this skeleton — binds it if needed. */\n clipInfo(ref: string | number): ClipInfo | undefined;\n /** The skeleton's calibrated knee hinge axis for a side, with its confidence report — measured once\n * over every bound clip's knee rotation track. Undefined = no leg chain / no knee motion bound. */\n kneeAxis(side: \"left\" | \"right\"): KneeAxisReport | undefined;\n /** STEP WARP v2 (the warp rewrite's knobs): `stride` scales each foot's travel-direction offset\n * from its hip — the step shortens or lengthens, uniformly through stance and swing; `lift` is\n * METRES added to each foot's height, gated to the swing by the contact marks (0 = neutral,\n * negative = a shuffle — no probing), and half of what it adds raises the pelvis so the body\n * steps higher with the foot; `pitch` (degrees, + = toes up) rotates each foot about its\n * own lateral axis — a slope's foot rotation; `slope` (degrees, + = ascending) is the INVISIBLE\n * STAIRCASE: foot heights follow the incline (leading foot higher) and the feet auto-pitch by\n * the same angle — pair it with raising the character by tan(slope) × the stride-scaled clip\n * travel (`clipInfo(clip).travelAt`), which holds every planted foot's world height constant on\n * its own tread. Solved in the calibrated knee hinge plane with a SOFT reach (a leg at its limit\n * keeps a residual knee bend instead of popping against the clamp), and whenever a leg would\n * overreach — a descent, a long stride — the pelvis lowers by exactly the excess (weighted by\n * the contact marks, spring-followed; zero when nothing overreaches, so an ascent or a shorter\n * stride is untouched). Omit / null = stage off. */\n setStepWarp(options?: {\n stride?: number;\n lift?: number;\n pitch?: number;\n slope?: number;\n } | null): void;\n /** A slot for a clip on the base layer, bound on demand — what the pair-wise measures address. */\n private slotOf;\n /** The baked distance curve between two clips, cached per pair (the engine caches the bake itself;\n * this keeps the samples on the JS side so a controller can read them per frame without copying). */\n private readonly _fit;\n private fitCurve;\n /** The earliest moment handing `src` over to `target` costs no more than `within` metres. */\n private fitExit;\n /** The contact bones, '\n '-joined per side (\"\" = classify by name). */\n private _feet?;\n setFeet(left: string, right: string): void;\n /** Stride / orientation warping, as the engine's fixed-order parameter array. */\n private _warp?;\n setWarp(params: Float32Array): void;\n /** The body's world velocity this frame (m/s) — the game side of the stride / orientation fit. Nothing\n * to feed before the animator exists; hosts without the warp stage have no method. */\n setMotion(vx: number, vy: number, vz: number): void;\n /** The feet stage (lock / ground IK), as the engine's fixed-order parameter array. */\n private _feetParams?;\n setFeetParams(params: Float32Array): void;\n /** One foot's lock state after this frame's evaluation into `out` (8 floats); false = no such foot\n * or no feet stage on this host. */\n footState(side: 0 | 1, out: Float32Array): boolean;\n private static _warnedIk;\n private hasIk;\n /** A chain ending in `endEntity` (kind 0 two-bone: the bone, its parent, its grandparent; 1 look-at). 0 = none. */\n ikCreate(kind: 0 | 1, endEntity: number): number;\n ikDestroy(ik: number): void;\n ikSet(ik: number, params: Float32Array): void;\n ikNodes(ik: number, target: number, pole: number, rotation: number): void;\n ikAnchor(ik: number, socket: string): void;\n ikState(ik: number, out: Float32Array): boolean;\n /** Sockets by \"set/name\", replayed when the animator is (re)created. */\n private readonly _sockets;\n /** Define a socket on joint `joint` (a bone's entity): a NODE socket (read by the engine every frame) or a\n * fixed TRS in the joint's space. set \"\" = the live set, any other name = a donor's. */\n setSocket(set: string, name: string, joint: number, node: number, trs: Float32Array | null): void;\n removeSocket(set: string, name: string): void;\n private pushSocket;\n private readonly _steps;\n onStepHandler(cb: StepHandler): void;\n offStepHandler(cb: StepHandler): void;\n private onStep;\n setSpeed(v: number): void;\n setRootMotion(on: boolean, rotation?: boolean): void;\n on(event: string, cb: ClipEventHandler): void;\n off(event: string, cb: ClipEventHandler): void;\n /** Native slot event: 0 completed / 1 loop / 2 settled (no longer a source) / 3 hand-over / 4+i clip event i. */\n private onEvent;\n}\n","types/gl/animation/DynamicBone.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { Node } from \"../Node\";\n/** One value for the chain, or `[root, tip]` interpolated down it by depth. */\nexport type DynamicBoneCurve = number | readonly [root: number, tip: number];\n/** `'none'`, `'probe'` (a ray from the chain root down against the physics world, every frame), a\n * height (a horizontal plane at that world y) or a world point (a plane through it, `floorNormal` up). */\nexport type DynamicBoneFloor = \"none\" | \"probe\" | number | Vec3Like;\n/** `'auto'` = every DynamicBoneCollider under the model; `'humanoid'` = those plus capsules generated\n * on the standard humanoid bones (hips, spine, head, limbs — the Ragdoll's layout); `'none'`; or the\n * nodes carrying the colliders to use. */\nexport type DynamicBoneColliders = \"auto\" | \"humanoid\" | \"none\" | Node[];\n/** The cloth's SIDE of every collider marked `oneSided`: `'none'` = no side, every collider pushes a bone to\n * its nearest surface (tails, ropes); `'auto'` = away from the root bone's own axis (a cloak's strips round\n * a spine face out from it); a vector = a fixed direction in the root bone's frame (a cape hanging BEHIND\n * the arms: the body's backward). A one-sided collider that is moving AWAY from that side — an arm swinging\n * forward under the cape — puts a bone it has run into over to the side instead of carrying it: the arm\n * passes through the cloth and the cape hangs behind it again, instead of being dragged round the body.\n * Still, or moving toward the cloth, it pushes like any other collider, so cloth draped on an arm at rest\n * stays where it is. Two-sided colliders (the body's) never read the side. */\nexport type DynamicBoneSide = \"none\" | \"auto\" | Vec3Like;\n/** A capsule (or a sphere) riding a bone — what dynamic bones stay out of. Attach to a body bone:\n * `hips.aspect(DynamicBoneCollider, { radius: 0.12, to: 'Spine' })`. The capsule runs from\n * `offset` (the bone's origin by default) to the `to` bone's origin, or to `end` (both in the bone's\n * local space); neither = a sphere at `offset`. Picked up by every DynamicBone on the same model\n * with `colliders: 'auto'` / `'humanoid'`, or listed explicitly. */\nexport declare class DynamicBoneCollider extends Aspect<\"dynamicBoneCollider\", Node> {\n static readonly aspect = \"dynamicBoneCollider\";\n /** Radius in metres, in the world: the bone's scale does not touch it (`offset` / `end` are in the bone's own units). */\n radius: number;\n /** Start of the capsule in the bone's local space (default: the bone's origin). */\n offset: Vec3Like;\n /** End of the capsule in the bone's local space (a sphere when neither `end` nor `to` is set). */\n end?: Vec3Like;\n /** The bone the capsule reaches (its origin), instead of `end`. */\n to?: string;\n /** ONE-SIDED: the cloth belongs on the chain's `side` of this capsule (see DynamicBone.side). While the capsule\n * moves away from that side it puts a bone it has run into over to the side instead of carrying it — an arm\n * under a cape may push the cape back, never drag it forward round the body. Needs a `side` on the DynamicBone. */\n oneSided: boolean;\n static fields: FieldMeta<DynamicBoneCollider>;\n private _id;\n private _segment;\n onAttach(): void;\n onReconfigure(): void;\n onDetach(): void;\n}\nexport declare class DynamicBone extends Aspect<\"dynamicBone\", Node> {\n static readonly aspect = \"dynamicBone\";\n /** Only these bones (by name) join the chain — the root always does, a bone left out takes its\n * subtree with it. Default: the root's whole subtree. */\n bones?: string[];\n /** Depth limit under the root (0 = no limit). */\n depth: number;\n /** Particle radius for the collisions, metres. */\n radius: DynamicBoneCurve;\n /** 0..1 — how fast a bone returns to the animated shape (per 1/60 s). 0 = a rope, 1 = rigid. */\n stiffness: DynamicBoneCurve;\n /** 0..1 — velocity lost per 1/60 s. 0.02 swings like a rope, 0.1 settles like a tail, 0.3 is honey. */\n damping: DynamicBoneCurve;\n /** m/s² downward. A hanging rest pose feels none of it (the bone length cancels it); a pose that\n * sticks out droops by as much as `stiffness` lets it. */\n gravity: DynamicBoneCurve;\n /** Max deviation from the animated direction, degrees per bone (0 = free). */\n angleLimit: DynamicBoneCurve;\n /** Relative mass per bone. A bone-length constraint moves its two ends in inverse proportion to\n * their masses (the root is kinematic): `[3, 1]` makes a tail's base carry its tip, `1` shares\n * evenly like a rope. */\n mass: DynamicBoneCurve;\n /** Bones (by name) that ride the animation exactly while their subtrees still simulate: a sheet's\n * several roots under one anchor (a cloak's seven strips under the spine), so ONE chain owns them all\n * and `link` ties neighbouring strips — neighbours in THIS order, so list the strips round the ring\n * (front-left … back … front-right); the front stays open. */\n pinned?: string[];\n /** Metres a PINNED bone may be pushed off its animated place by a collider — a soft pin. Its particle\n * collides and takes the edge pushes like a free bone (the strip below hangs from where it IS) and is\n * drawn back to the animation when the collider leaves; the bone's local translation follows. A hard\n * pin (0) at a capsule's edge made the first free bone below it jitter: the edge push on a segment\n * with an immovable end is a lever, and a touch near the root threw the child out. 2–3 cm for a\n * cloak's roots under a shoulder capsule. */\n pinGive: number;\n /** 0..1 of the character's travel the chain takes rigidly (0 = the full whip on a dash, 1 = it\n * moves with the body and only the pose's own motion swings it). */\n follow: number;\n /** World wind, m/s². */\n wind: Vec3Like;\n /** The BODY'S TURN, ≥ 0. Above 0 the chain lives in the parent bone's ROTATING frame: `damping` acts\n * against the body's rigid motion (its travel plus its spin), so a heavily damped cloak RIDES a turn —\n * sweeps round with the back — instead of standing in the world while the character spins under it and\n * being dragged round after. The turn's inertia comes back as the frame's forces, scaled by this value:\n * a centrifugal push `ω² · r` along each bone's animated direction from the axis (the hem, farthest\n * from the spine, flies out and, on the chain's length, up). The frame's own physics is built in: the\n * whip back when the turn starts and forward when it stops, Coriolis. 1 = the physical push; more = a\n * bigger fling. With low damping the frame reproduces a free particle (nothing is counted twice);\n * an animation's spine sway is ~1 % of a 900°/s turn. A rotation over 90° in one frame (a respawn\n * facing) counts as a snap, not a spin. 0 = the plain translational frame, no turn forces. */\n spin: number;\n /** With `spin`: the cloth's INERTIA against the body's turn, seconds — the cloth's own rotation follows the\n * body's with this time constant. It falls behind when a turn starts (by about ω·τ: 45° at 900°/s and 0.05),\n * rides once caught up, and keeps turning past the back when the body stops (the same angle, eased out over\n * τ). Smooth by construction. 0 = glued to the turn; large = the cloth stays in the world while the body spins. */\n spinInertia: number;\n /** 0..1 strength of the ties between neighbouring columns at the same depth (a cloak). */\n link: number;\n /** 0..1 blend from the animation (0) to the simulation (1). At 0 nothing is simulated and the\n * chain re-arms on the animated pose when it comes back. */\n weight: number;\n /** Substep rate, Hz (≤ 4 substeps per frame). */\n rate: number;\n /** A root jump longer than this in one frame (metres) resets the chain instead of whipping it. */\n teleport: number;\n /** What the particles stay above: `'none'`, `'probe'`, a height, or a world point. */\n floor: DynamicBoneFloor;\n /** The floor plane's normal when `floor` is a point. */\n floorNormal: Vec3Like;\n /** Friction against the floor, a Coulomb coefficient: a resting bone's slide loses up to\n * `floorFriction · gravity · dt` of speed per substep (0 = ice, 1 = a rubber sole). While a bone\n * rests on the floor or a collider, `stiffness` and `angleLimit` let go of it: the surface's\n * reaction outranks the spring, or a hem folded on the floor would run away along it. */\n floorFriction: number;\n /** Constraint passes per substep (1..8, default 4). Each pass shares every bone length between its\n * ends, so a pull needs passes to travel down a long chain: a long rope may want 8, a short tail is\n * fine with 2. */\n iterations: number;\n /** What the chain collides with (see DynamicBoneColliders). */\n colliders: DynamicBoneColliders;\n /** The cloth's outside — makes the colliders one-sided (see DynamicBoneSide). */\n side: DynamicBoneSide;\n /** How firmly `guide()` targets are HELD through the constraint passes, 0..1. At 0 a guide is applied once\n * before the passes and the length / link passes may drag the bone back toward its un-guided neighbours\n * within the same frame; at 0.5 it is re-pulled after every pass with half its weight (converges with the\n * passes), at 1 with its full weight (a target the bone length cannot reach then jitters). */\n guideHold: number;\n /** The chain's EDGES collide with the capsules too — every bone segment and every link, not only the bones'\n * particles: a capsule thinner than a bone's length (a forearm) no longer passes through the cloth between\n * two bones. Off = particles only. */\n edges: boolean;\n static fields: FieldMeta<DynamicBone>;\n private _id;\n private _chain;\n private _depths;\n private _blob;\n private _sent;\n private _floorKey;\n private _colliderKey;\n private _collidersDirty;\n private _collidersRef;\n private _own;\n private _colliderSet;\n /** The bones of the chain, the root first. */\n get chain(): readonly Node[];\n onAttach(): void;\n onReconfigure(): void;\n /** Every field is live: what changed since the last frame is pushed here, before the engine's stage. */\n update(): void;\n onDetach(): void;\n /** Snap the chain onto the animated pose next frame (a teleport, a camera cut). */\n reset(): void;\n /** GUIDES: world points the bones' particles are drawn to each substep before the constraints —\n * weight 1 = there before them, the rest of the chain hangs, collides and links as before (a cape's\n * strips riding the arms). Replaces the previous set; an empty list clears. A late-phase script\n * (after the animator, before the engine's chain stage) refreshes it every frame. */\n guide(rows: readonly {\n bone: Node;\n at: Vec3Like;\n weight: number;\n }[]): void;\n /** The particles' world positions (the bones, then the leaves' virtual tips) — for a debug draw. */\n get particles(): Vec3[];\n private _collect;\n private _fill;\n /** Neighbour links: the bones at the same depth tied pairwise, the columns in the order of `pinned` (a cloak's\n * strips listed round the ring) — columns not listed there follow in tree order. Tree order alone is the\n * engine's child order, which for a GLB is the file's node order REVERSED (Filament prepends each child), so\n * strips added to a rig later were tied across the body instead of to their neighbours: the ermine's cloak\n * had one true neighbour pair out of eight, the rest were rods through the chest. */\n private _links;\n private _sync;\n private _pushFloor;\n private _pushColliders;\n /** Capsules on the standard humanoid bones, sized like the Ragdoll's parts. */\n private _makeHumanoid;\n}\n","types/gl/animation/Feet.d.ts":"import { Vec3 } from \"../../math/vec\";\nimport type { KneeAxisReport, StepHandler } from \"./core\";\n/** The feet settings (`anim.feet.set()` / the properties of `anim.feet`). Distances are metres, times\n * seconds. Every key is optional and only the keys given change. */\nexport type FeetOptions = {\n /** The contact bones per side — `'LeftFoot'`, or with a toe / ball `['LeftFoot', 'LeftToeBase']`.\n * Default: classified from the bone names (Mixamo / Unity / Blender / UE). Setting them re-bakes\n * every clip's contacts and phase. */\n left?: string | string[];\n right?: string | string[];\n /** FOOT LOCK: a foot the shown clip calls planted is pinned where it landed — heel to ball, rolling\n * as the clip rolls — and the leg re-solved to keep it there while the body moves on. Off by default. */\n lock?: boolean;\n /** GROUND IK: each foot is put on the ground the engine probes under it (stairs, a slope, a kerb),\n * aligned to its normal, the pelvis lowered so the leg can reach. Needs a physics world to probe;\n * without one the ground is the node's own plane. Off by default. */\n ik?: boolean;\n /** How far the pelvis may drop for the ground (default 0.35). */\n pelvis?: number;\n /** A locked foot never absorbs more residual than this — beyond it the anchor follows the animation\n * instead of fighting it (default 0.10). */\n unlockDistance?: number;\n /** The lock's ease in / out, seconds (default 0.08 / 0.12). */\n lockIn?: number;\n lockOut?: number;\n /** 0..1: how much the foot tilts onto the ground normal (default 1). */\n align?: number;\n /** The probe ray's reach above and below the ankle (default 0.6). */\n probe?: number;\n /** The lock plants only once the animated ankle moves slower than this, m/s (default 0.2). Raise it\n * to pin a foot a transition is still dragging. */\n plantSpeed?: number;\n};\n/** One foot after this frame's evaluation (`anim.feet.state(side)`): whether the lock holds it, the\n * lock's weight (eased 0…1), where it was pinned and where the leg was asked to put the ankle — all world. */\nexport type FootState = {\n locked: boolean;\n weight: number;\n anchor: Vec3;\n target: Vec3;\n};\nexport declare class Feet {\n private readonly _c;\n private readonly _o;\n /** Change several settings at once; only the keys given change. Chainable. */\n set(options: FeetOptions): this;\n /** The current settings (what was set; unset keys are the engine's defaults). */\n get options(): Readonly<FeetOptions>;\n get lock(): boolean;\n set lock(v: boolean);\n get ik(): boolean;\n set ik(v: boolean);\n get pelvis(): number;\n set pelvis(v: number);\n get unlockDistance(): number;\n set unlockDistance(v: number);\n get lockIn(): number;\n set lockIn(v: number);\n get lockOut(): number;\n set lockOut(v: number);\n get align(): number;\n set align(v: number);\n get probe(): number;\n set probe(v: number);\n get plantSpeed(): number;\n set plantSpeed(v: number);\n /** The contact bones (`undefined` = classified from the names). */\n get left(): string | string[] | undefined;\n set left(v: string | string[] | undefined);\n get right(): string | string[] | undefined;\n set right(v: string | string[] | undefined);\n /** One foot's state after this frame's evaluation — where the lock holds it and with what weight\n * (a debug beam under the foot). `undefined` on a host without the feet stage, or before anything played. */\n state(side: \"left\" | \"right\"): FootState | undefined;\n /** The skeleton's calibrated KNEE HINGE AXIS for a side (thigh-local, unit) with its confidence report —\n * measured once over every bound clip's knee rotation track. `undefined` = no leg chain, or no knee\n * motion bound to calibrate from. */\n kneeAxis(side: \"left\" | \"right\"): KneeAxisReport | undefined;\n /** A foot planted (world position) — audio, dust, decals. Fires for what the BASE layer shows, from\n * the clip's own contacts; a clip with no contacts fires nothing. */\n onStep(cb: StepHandler): this;\n offStep(cb: StepHandler): this;\n private pushBones;\n private push;\n}\n","types/gl/animation/IK.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport { Quat } from \"../../math/quat\";\nimport type { Node } from \"../Node\";\nimport type { Core } from \"./core\";\ntype Target = Node | Vec3Like;\n/** What both chains share: the native handle, the parameter push, the readback. */\ndeclare abstract class Chain<Name extends string> extends Aspect<Name, Node> {\n protected _rig?: Core;\n protected _ik: number;\n protected _weight: number;\n protected _enabled: boolean;\n protected abstract readonly kind: 0 | 1;\n /** 0–1 contribution (blend in/out, e.g. foot planting only while grounded). */\n get weight(): number;\n set weight(v: number);\n /** Solve every frame (default). */\n get enabled(): boolean;\n set enabled(v: boolean);\n /** After the last solve: how far the end bone still is from its target, metres (0 = reached). */\n get error(): number;\n onAttach(): void;\n onDetach(): void;\n onReconfigure(): void;\n protected params(): Float32Array;\n /** Push the description to the engine (a no-op until attached). */\n protected abstract push(): void;\n}\n/** Two-bone analytic IK (limbs). Attach to the END bone: `foot.aspect(IK.TwoBone, { target })` solves\n * upper (grandparent) + mid (parent) so the end reaches `target`; `pole` steers the bend (knee /\n * elbow) — a Node or world point; `anchor` makes it ride a socket of the rig instead (see the file\n * header). */\ndeclare class TwoBone extends Chain<\"ik\"> {\n static readonly aspect = \"ik\";\n protected readonly kind: 0;\n private _target?;\n private _pole?;\n private _rotation?;\n private _rotationWeight;\n private _anchor;\n private _anchorTime;\n private _anchorPin;\n /** Where the end bone should be (a Node — read by the engine every frame — or a world position). */\n get target(): Target | undefined;\n set target(v: Target | undefined);\n /** Bend hint — the mid joint is pulled toward it (a Node or a world point). */\n get pole(): Target | undefined;\n set pole(v: Target | undefined);\n /** World rotation the END bone takes after the solve — a Node (its world rotation) or a Quat. Unset =\n * the end bone keeps its animated rotation (a hand on a grip, a foot on a slope want it set). Blended\n * by `weight · rotationWeight`. An anchored chain takes its rotation from the socket instead. */\n get rotation(): Node | Quat | undefined;\n set rotation(v: Node | Quat | undefined);\n /** 0–1 contribution of `rotation` (on top of `weight`); for an anchored chain, of the socket's turn. */\n get rotationWeight(): number;\n set rotationWeight(v: number);\n /** ANCHORED: the name of the LIVE socket the end bone rides (`anim.sockets(...)`) — its target and\n * rotation come from the socket and the playing clips' anchor spans; `target` / `pole` / `rotation`\n * are ignored. '' = a plain chain. */\n get anchor(): string;\n set anchor(v: string);\n /** Anchored: how fast the hand moves between sockets — the halflife (s) of the spring the applied\n * delta follows the wanted one with (default 0.05). */\n get anchorTime(): number;\n set anchorTime(v: number);\n /** Anchored: 0..1 how hard the end bone is PINNED on its socket while the playing clips leave it there\n * (a GAP in their spans — the hand is holding the gun). 1 = it sits exactly on the socket, so nothing\n * in the pose below can slide it along the gun; 0 (default) = it keeps the take's own relation to the\n * socket, moved by the delta. A clip's SPANS carry their own pin and default to 0, because a hand on\n * its way to a magazine must keep the take's motion — so this knob is about holding, not reaching. */\n get anchorPin(): number;\n set anchorPin(v: number);\n /** After the last solve: the anchor delta applied — how far (m) and how much (rad) the live socket\n * moved the hand off the take's own pose. 0 for a plain chain. */\n get anchorDelta(): {\n distance: number;\n angle: number;\n };\n protected push(): void;\n}\n/** Aim a bone at a target (head / eyes / turret). Attach to the bone itself:\n * `head.aspect(IK.LookAt, { target: camera, limit: 70 })`. `axis` is the bone's LOCAL forward\n * (the direction that should point at the target) — rigs differ; default −Z, Mixamo heads look\n * along +Z of the head bone in most exports, so pass `axis: [0, 0, 1]` there if it faces backwards. */\ndeclare class LookAt extends Chain<\"lookAt\"> {\n static readonly aspect = \"lookAt\";\n protected readonly kind: 1;\n private _target?;\n private _axis;\n private _limit;\n /** What to look at (a Node — read by the engine every frame — or a world position). */\n get target(): Target | undefined;\n set target(v: Target | undefined);\n /** The bone's local axis that should point at the target. */\n get axis(): Vec3Like;\n set axis(v: Vec3Like);\n /** Max deflection from the animated direction, in degrees (default 80). */\n get limit(): number;\n set limit(v: number);\n protected push(): void;\n}\n/** Inverse kinematics aspects — attach to bones (see file header). */\nexport declare const IK: {\n TwoBone: typeof TwoBone;\n LookAt: typeof LookAt;\n};\nexport type IKTwoBone = TwoBone;\nexport type IKLookAt = LookAt;\nexport {};\n","types/gl/animation/Layer.d.ts":"import type { ActiveClip, LoopDef, LoopOptions, PlayOptions, StopOptions } from \"./core\";\nimport type { Loop } from \"./Loop\";\nimport type { Playback } from \"./Playback\";\nexport declare class Layer {\n private readonly _r;\n private readonly _c;\n /** Play a one-shot on this layer (transitioned over `fade`); resolves at its hand-over. */\n play(clip?: string | number, options?: PlayOptions): Playback;\n /** Set / transition this layer's loop (a clip, or a blend space) — over `fade` from whatever the\n * layer shows, a one-shot included (it is cut short). */\n playLoop(def: LoopDef, options?: LoopOptions): Loop | undefined;\n /** Fade everything on this layer out — one-shots and its loop. */\n stop(options?: StopOptions): this;\n /** ANTICIPATION for the NEXT play / playLoop on this layer (consumed by it): the transition begins with\n * every joint moving AGAINST the new clip's motion - `amount` x its velocity - and the transition's\n * spring brings it round: a wind-up before the swing. Position and rotation, the joints the layer\n * drives. 0.3-1 reads as a natural anticipation; the duration is the transition's own fade.\n * Ignored by hosts without it. */\n anticipate(amount: number): this;\n /** This layer's current loop (the object the last `playLoop()` returned), if any. */\n get loop(): Loop | undefined;\n /** Where this layer is in the gait cycle, 0–1 (-1 = what it shows has no cycle). */\n get phase(): number;\n /** Layer contribution 0–1. */\n get weight(): number;\n set weight(v: number);\n /** A one-shot on this layer hasn't handed over yet. */\n get busy(): boolean;\n /** What this layer shows this frame with its weight — its one-shot, or its loop's members. */\n get active(): ActiveClip[];\n}\n","types/gl/animation/Locomotion.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { Animator } from \"./Animator\";\nimport type { FeetOptions } from \"./Feet\";\nimport type { WarpOptions } from \"./Warp\";\nimport type { Node } from \"../Node\";\n/** How fast the character wants to go: the gait picks its clips and its speed. */\nexport type Gait = \"walk\" | \"run\" | \"sprint\";\n/** What the engine shows: the idle, a start, the gait loop, a turn while moving, a stop, a turn on the spot —\n * an ACTION (`act()`): a one-shot that owns the body until it hands over — or the STRAFE blend (`move({ strafe })`). */\nexport type LocomotionState = \"idle\" | \"start\" | \"move\" | \"turn\" | \"stop\" | \"spin\" | \"action\" | \"strafe\";\n/** Who moves the body:\n * `'hybrid'` (the default) — the clip's own recorded motion moves it; while the gait loop shows it\n * is ADJUSTED toward what the simulation wants by at most `tuning.adjust` metres a second, and a\n * start / turn / stop / spin moves it alone. The recording keeps the feet honest, the clamp keeps\n * the player in charge of the arcs. What a pack authored with root motion wants.\n * `'code'` — the simulation moves it and the animation has to be warped to follow (stride warping);\n * for packs recorded in place.\n * `'data'` — the clips' root motion moves it and nothing adjusts it; the simulation only predicts. */\nexport type Displacement = \"hybrid\" | \"code\" | \"data\";\n/** One clip of the set: its name, or the name with what the clip itself cannot say — `gait` (which\n * gait a transition belongs to: a walking body plays the walking starts, stops and turns; left out =\n * any gait) — and overrides for what the engine would otherwise measure: `angle` (degrees the clip\n * turns the body, + = left) for a start / turn / spin, `speed` (m/s) for a gait clip. */\nexport type LocomotionClip = string | {\n clip: string;\n gait?: Gait;\n angle?: number;\n speed?: number;\n};\n/** The clips the selector may show. Everything but `idle` is a list; an empty one simply means the\n * engine never shows that kind (a pack without turns steers through them instead). */\nexport type LocomotionSet = {\n /** standing still */\n idle?: LocomotionClip;\n /** the gait loop's members, slowest first — walk, run, sprint. Blended by the simulated speed. */\n gaits?: LocomotionClip[];\n /** standing → moving, one per direction (the engine picks by the turn each one makes) */\n starts?: LocomotionClip[];\n /** moving → standing */\n stops?: LocomotionClip[];\n /** turns taken while moving */\n turns?: LocomotionClip[];\n /** turns on the spot — what a facing still owed by a standing body plays */\n spins?: LocomotionClip[];\n /** the STRAFE set: the same gait recorded forward, backward, to either side and on the diagonals — the members of\n * the directional blend `move(dir, { face, strafe: true })` shows. `angle` = the way a take travels in the body's\n * frame (degrees, + = left); left out, the engine reads it off the take's root. */\n strafes?: LocomotionClip[];\n};\n/** The tuning. Times are seconds, speeds m/s, angles degrees. */\nexport type LocomotionTuning = {\n /** How briskly the simulated speed reaches the wanted one — the halflife of the difference, per\n * gait (default 0.27 walking, 0.2 running). Smaller = more responsive, larger = heavier. */\n responseWalk?: number;\n responseRun?: number;\n /** How briskly the body brakes when nothing is asked for (default 0.15). Braking is not\n * acceleration backwards: a body plants and stops in far less than it takes to reach a run, and\n * with the gait's own number the tail of the curve is a long, visible glide. */\n responseStop?: number;\n /** The same for the facing (default 0.15). */\n responseFacing?: number;\n /** Top speed per gait. Left out (the default), each gait travels at the speed its own clip was\n * recorded at — which is what keeps the feet from sliding. */\n speeds?: Partial<Record<Gait, number>>;\n /** The step warp's split when a gait is asked for at a speed that is not its clip's own: the\n * STRIDE (spatial squash of the leg's reach) gets ratio^strideShare, clamped to `strideBand`,\n * and the cadence takes all the rest — the asked speed is always delivered exactly.\n * 0 = all cadence (slow motion), 1 = all stride (within the band). Default 0.5. */\n strideShare?: number;\n /** How far the stride's share may squash or stretch the legs' reach (default [0.85, 1.15]) —\n * past it the warp re-bends legs the clip authored straight. */\n strideBand?: [number, number];\n /** PIN the step warp's stride ratio (a tuning bench's knob): the step width is held at exactly\n * this, whatever speed is asked — the body's speed falls out of stride × cadence instead of\n * driving the split. Leave out (or 0) for automatic. */\n warpStride?: number;\n /** PIN the step warp's cadence ratio the same way — the animation's pace held at exactly this.\n * With both pinned, stride and pace are fully independent. Leave out (or 0) for automatic. */\n warpCadence?: number;\n /** Cap on how fast the body may turn by STEERING, deg/s (default: uncapped) — the arc it walks when\n * the heading is off by less than `turnMin`. A start / turn / spin clip owns the facing while it\n * turns: the body then turns exactly as much as the (warped) animation does. */\n turnRate?: number;\n /** Heading error that plays a turn clip instead of steering through it (default 60°). Which turn\n * clip is not a threshold: every one is entered where the gait phase allows nearest to its pivot,\n * and the one whose turn LEFT from there best answers the error wins. */\n turnMin?: number;\n /** Facing still owed by a standing body that turns it on the spot (default 30°). Less than this it\n * accepts — a standing body never rotates by code, that is the one thing no tuning makes look right. */\n spinMin?: number;\n /** Transition seconds between clips (default 0.2), and into the idle after a stop (default 0.3). */\n blend?: number;\n stopBlend?: number;\n /** How far a start / turn / spin clip's recorded turn may be SCALED so it delivers exactly the heading\n * asked for, as a fraction (default 0.3 = ×0.7 … ×1.3). What lies beyond the clamp is steered once\n * the body moves. 0 = the recording is law. */\n yawWarp?: number;\n /** A start or a turn hands over to the gait loop at the first foot-down after its turn is delivered\n * at which its pose is within this many metres of the loop's — the engine's baked fit curve —\n * instead of at its end (default 0.15). 0 = at the end. */\n exitTolerance?: number;\n /** A stop asked to move again resumes the gait loop while the body still travels at this fraction of\n * the gait's speed or more (default 0.5); slower, it starts afresh. */\n resumeSpeed?: number;\n /** …and then let it play this many more FOOT-DOWNS before handing over (default 0). `exitTolerance`\n * answers \"when has this pose become the walk's\", which is the earliest honest moment and not always\n * the best-looking one — a start that has just found the gait still reads as a start for another step\n * or two. 1 or 2 gives a take room to finish its thought; a take that runs out hands over at its own\n * end regardless, so nothing can hang. */\n exitSteps?: number;\n /** How much braking room, in metres, to trade for each second of a stop take's lead-in that would\n * otherwise be skipped (default 0). A stop cannot be rewound — the variants are one cycle long, so\n * no earlier frame has the same foot down — so the only way to begin a stop nearer its own start is\n * to prefer the VARIANT that starts there for the foot the body happens to be on. Raise it (0.5…1.5)\n * to see the whole braking gesture; leave it at 0 to land exactly where the body should stop. */\n stopEarly?: number;\n /** How much braking room, in metres, one extra FOOT-DOWN in the stop is worth (default 0). A stop\n * take is one cycle long, so wanting another step means wanting a LONGER variant, and a longer one\n * lands the body further along than it asked to stop — the trade is this number. Around 1 buys a\n * second step on a pack like Mobility Pro; 0 lands exactly where the body should stop. */\n stopSteps?: number;\n /** How far a stop take's pose may be from the one showing, in metres, for it to be entered BEFORE\n * its own first foot-down (default 0.25). Ahead of that footfall a take's phase curve is an\n * extrapolation: it can match the body's phase arithmetically with the legs at a different stage\n * of the stride, which is why the pose is asked directly. 0 = never enter a take early — the body\n * then takes whatever later entry matches its foot, which on a walk can be three quarters of the\n * way through a take, on top of one of its plants. */\n stopFit?: number;\n /** What a metre of POSE distance at the entry is worth against a metre of braking room when the\n * variants are ranked (default 1). Both are metres and the feet pay both: room the body has not\n * got is taken out of the root while a foot is planted, and a pose the transition has to hide is\n * dragged out of that same foot over the blend. 0 = rank by braking room alone, which picks a\n * take by where it ENDS and lets it start from any pose at all. */\n stopPose?: number;\n /** Input magnitude below which a stick counts as released (default 0.2). */\n deadZone?: number;\n /** `displacement: 'hybrid'`: how far, m/s, the body may be pushed off what the animation recorded,\n * toward what the simulation wants, while the gait loop shows (default 0.5) — a start, turn, stop\n * or spin moves the body alone, since pushing it there is its planted foot skating. 0 = the\n * recording is law; large = the code is law — responsive, and the feet start lying. */\n adjust?: number;\n};\n/** One stop take as the selector weighed it, from `stopReport()`. A stop is chosen for the foot the\n * body stands on and the room it needs: `phaseOk` and `afterFirstStep` are the two pass/fail rules,\n * `score` ranks whatever passed (lower wins), and `chosen` marks the one that plays. */\nexport type StopCandidate = {\n /** the take's clip name */\n clip: string;\n /** seconds into it the entry would be — near its end means its braking gesture is skipped */\n at: number;\n /** metres it still travels from that entry */\n room: number;\n /** metres this body needs to come to rest (the same for every row) */\n need: number;\n /** seconds from the entry to its next foot-down */\n wait: number;\n /** foot-downs left after the entry: 0 = it plants where it stands */\n steps: number;\n /** does it have a frame at the body's own cycle phase (the right foot down)? */\n phaseOk: boolean;\n /** is that frame at or after its own first foot-down? Ahead of it the phase curve is an\n * extrapolation — it can match arithmetically at the wrong stage of the stride */\n afterFirstStep: boolean;\n /** …and it is ahead of it, but its POSE matched what is showing closely enough to be let in\n * anyway (`fit` under `tuning.stopFit`) */\n earlyByPose: boolean;\n /** the one that is playing */\n chosen: boolean;\n /** |room − need| + the pose distance + how late in the take (lower wins) */\n score: number;\n /** how far this entry's pose is from the one showing, in the fit measure's metres (-1 = not\n * measured). Under `tuning.stopFit` an entry ahead of the take's first foot-down is allowed. */\n fit: number;\n};\nexport type LocomotionEvents = {\n /** What the selector shows changed. */\n state: (state: LocomotionState) => void;\n};\nexport declare class Locomotion extends Aspect<\"loco\", Node, LocomotionEvents> {\n static readonly aspect = \"loco\";\n /** The animator whose clips are shown. Default: the first one on this node or under it (a Model\n * child), which is the usual character — a capsule node with the model inside. */\n animator?: Animator;\n /** The clips the selector may show. */\n set: LocomotionSet;\n /** Who moves the body (see `Displacement`). */\n displacement: Displacement;\n /** The feel (see `LocomotionTuning`). */\n tuning: LocomotionTuning;\n /** Fit the POSE to what the body does — stride and orientation warping (see `Animator.warp`, which\n * this simply sets). The simulation feeds the engine the body's motion every frame, so here it\n * only has to be turned on: `warp: true`, or `{ stride: [0.7, 1.4], orientation: 45 }`. Off by\n * default — a pack whose gaits already cover the speeds it is played at does not need it. */\n warp?: WarpOptions | boolean;\n /** The FEET (see `Animator.feet`, which this simply sets). Default: the foot lock on, ground IK off\n * — a planted foot stays where it landed through every transition the selector makes, which is the\n * last of the slide once the recording moves the body. `true` = lock + ground IK (stairs, slopes);\n * `false` = neither; or the options themselves. */\n feet?: FeetOptions | boolean;\n private _loco;\n private _dir;\n private _face;\n private _mag;\n private _gait;\n private _seq;\n private _act;\n private _strafe;\n private readonly _in;\n private readonly _out;\n private readonly _names;\n private _report?;\n private get anim();\n private get controller();\n protected onAttach(): void;\n protected onDetach(): void;\n /** Re-read the set and the tuning — after changing either at runtime (a weapon that changes the\n * walk, a slowed-down character). */\n rebuild(): void;\n /** Register one clip of the set: the engine measures the clip's own turn / speed unless given. */\n private enter;\n /** Why the stop that is playing is the one that plays: every candidate the selector weighed, in\n * the order it weighed them. Read it when a stop looks wrong — the answer is usually that the\n * take that would have looked right was rejected by one of the two rules, not that the score\n * picked badly. Empty until a stop has been chosen (and on hosts without the debug read). */\n stopReport(): StopCandidate[];\n /** Re-push the TUNING alone — the numbers, not the clip set. What a live tweak wants (a debug\n * slider, a character that gets heavier when hurt): `rebuild()` also re-measures the set, which\n * mid-clip is more than a changed number asks for. */\n retune(): void;\n private pushTuning;\n /** State the movement intent for this frame: a world direction (its length is the stick's pull,\n * clamped to 1) and the gait. `null` = no movement — the body stops, but it keeps facing where it\n * was last asked to, and turns there on the spot if it still owes the turn.\n * `face` states a facing of its own (aiming, a camera-relative shooter) — and with `strafe: true` the body MOVES\n * where the direction points while it faces there: the loop becomes the directional blend of `set.strafes` (a\n * guard, a lock-on), the facing is steered standing too, state `'strafe'`. Stated every frame like the rest. */\n move(direction: Vec3Like | null | undefined, options?: {\n gait?: Gait;\n face?: Vec3Like;\n strafe?: boolean;\n }): void;\n /** Play an ACTION: a one-shot that OWNS the body the way a start or a stop does — a roll, a backstep, a lunging\n * attack. Its recording moves the body alone (in every displacement mode but `'data'`, where the host does),\n * the steering and the selector stand by, and when it hands over the usual rules carry on: a direction held\n * starts (or, still carrying speed, runs on), nothing held stands.\n *\n * `direction` is where its TRAVEL must go, world (`Vec3`, or a heading in degrees, 0 = +Z, + = toward +X). A\n * clip travels some way relative to the body — forward, left, back; measured off its own root, or `angle`\n * (degrees, + = left) — and the body is turned by what is left between that and `direction`, over `turn`\n * seconds (default 0.12), so the travel lands exactly where it was pointed. Which clip to play is yours to\n * pick: the one whose travel is nearest the direction IN THE BODY'S FRAME (`direction − facing`) leaves the\n * least to turn. Left out = it plays where the body faces.\n *\n * `at` enters the clip that many seconds in (a wind-up skipped), `rate` plays it faster or slower (its metres\n * stay, the time changes), `travel` takes only that share of its recorded travel (an attack aimed at a target:\n * 0.3 to stop at the blade's length from one that is close, 1.3 to reach one a step too far — the pose is\n * untouched, so keep it to a fast step; `{ share, at, after }` takes another share from clip time `at` on: a\n * swing's take travels on after its cut, into a body that stands at the blade's length), `dash` THROWS the body\n * `distance` metres along the action's direction on top of that, inside `time` seconds (default 0.12) from its first\n * step, eased out — the gap to a target closed in the wind-up, the blow struck from where it lands (scaling a take's\n * own step is a slide stretched over the whole swing), `fade` is the transition into it and `out` the one out of it (default: the tuning's\n * `blend`; an action ends in ITS stance, not the idle's, and a longer way out is what hides that), and `exit` is the\n * clip time from which a MOVE intent may take over — the cancel window: along the way the body faces at once, a\n * heading that needs a turn as soon as the body has slowed to where a start can answer; with nothing asked for it plays out, to\n * its end (an action ends in its own recovery, at rest), and the body then STANDS THE WAY THE ACTION LEFT IT:\n * the facing intent that outlives a released key is not a demand after an action — no turn on the spot.\n * WHEN an action may be asked for (out of another one, out of a start) is the caller's rule: this cuts into\n * whatever shows. `state` reads `'action'` while it does. False = no such clip. */\n act(clip: string, options?: {\n direction?: Vec3Like | number;\n angle?: number;\n turn?: number;\n at?: number;\n exit?: number;\n fade?: number;\n out?: number;\n rate?: number;\n travel?: number | {\n share: number;\n at: number;\n after: number;\n };\n dash?: {\n distance: number;\n time?: number;\n };\n }): boolean;\n /** Face this way without moving — the facing intent on its own (`Vec3`, or a heading in degrees,\n * 0 = +Z, + = toward +X). A standing body turns to it on the spot. */\n face(direction: Vec3Like | number): void;\n /** The gait the intent asks for. */\n get gait(): Gait;\n set gait(g: Gait);\n /** Is a movement intent standing right now? (The debug answer to \"is a key held\".) */\n get moving(): boolean;\n /** The direction the intent points, world. */\n get direction(): Vec3;\n /** The heading the intent asks the body to face, degrees (0 = +Z, + = toward +X). */\n get heading(): number;\n /** The speed the intent asks for, m/s — it jumps the moment a key goes down or the gait changes.\n * `speed` is what the body has made of it. */\n get intentSpeed(): number;\n /** What the selector shows. */\n get state(): LocomotionState;\n /** The body's speed, m/s — the simulation's, which is what the animation is fitted to. */\n get speed(): number;\n /** The body's velocity, world m/s. */\n get velocity(): Vec3;\n /** Where the body faces, degrees (0 = +Z, + = toward +X) — the node's yaw, which this drives. */\n get facing(): number;\n /** Where the base layer is in the gait cycle, 0–1 (-1 when what shows has no cycle). */\n get phase(): number;\n /** How far the STOP that is showing was entered from the phase the body was on, in cycles, signed —\n * measured at the switch. 0 while no stop shows; ±0.5 would be the other foot on the ground. */\n get stopFootOffset(): number;\n /** Foot-downs left in the stop that is showing, counted from the frame it was entered at. 0 means it\n * was entered past its own last footfall — the body will not step, it will only settle. -1 when no\n * stop shows. The number behind \"he did not take a step, he just pulled the foot back\". */\n get stopStepsLeft(): number;\n /** Seconds from the frame the shown stop was entered at to its next foot-down. Large means it was\n * entered just AFTER a footfall: the leg is planted and then held still until the one after, which\n * reads as a foot that sticks. -1 when no stop shows. */\n get stopStepWait(): number;\n /** Degrees the clip showing still turns the body by (a start / turn / spin, after its warp); 0 for\n * the loop and the idle — the heading the engine has committed to but not yet delivered. */\n get yawLeft(): number;\n /** The shown transition's clip time and the time it hands over at, seconds (-1 for the loop / idle;\n * `exitAt` -1 = at the clip's end). A debug readout. */\n get clipTime(): number;\n get exitAt(): number;\n /** Where the body will be in 0.2 / 0.4 / 0.7 s if the intent holds — the path the selector judges\n * a turn by, and a debug overlay's dots. */\n get trajectory(): Vec3[];\n protected updateBefore(dt: number): void;\n protected updateFixed(dt: number): void;\n}\n","types/gl/animation/Loop.d.ts":"import type { BlendPosition } from \"./core\";\nexport declare class Loop {\n private readonly _r;\n private readonly _c;\n /** Position on the axis (number) or plane (`[x, y]`) — units are whatever the positions use. Live\n * even while a one-shot plays (the loop returns at the new mix). */\n get value(): BlendPosition;\n set value(v: BlendPosition);\n /** Where the loop is in its GAIT cycle, 0–1: 0 at a left-foot-down, 0.5 at a right-foot-down —\n * one clock for every member, aligned by their contacts (a walk and a run whose feet land at\n * different fractions of their clips still agree). Set it to jump the cycle: `playLoop(def,\n * { phase })` on the way in, or here to re-sync with something else. */\n get phase(): number;\n set phase(v: number);\n /** Each member's share of the mix, 0–1. */\n get weights(): Record<string, number>;\n}\n","types/gl/animation/Playback.d.ts":"import type { AnimationClip } from \"./AnimationClip\";\nimport type { StopOptions } from \"./core\";\nimport type { Layer } from \"./Layer\";\nexport declare class Playback implements PromiseLike<boolean> {\n private readonly _r;\n private readonly _c;\n /** The clip that plays. */\n get clip(): AnimationClip;\n /** The layer it plays on. */\n get layer(): Layer;\n /** Clock (s). */\n get time(): number;\n /** 0–1 through the clip (the current cycle, when looping). */\n get progress(): number;\n /** Where this clip is in the GAIT cycle now, 0–1 (-1 when it has none). */\n get phase(): number;\n /** The root yaw the clip has turned the body by so far, radians (+ = left) — a turn clip's progress. */\n get turned(): number;\n /** The root yaw still to come: where this clip will leave the body facing, relative to now (rad). */\n get turnLeft(): number;\n /** The horizontal distance the clip's root has travelled so far, metres. */\n get travelled(): number;\n /** Not handed over yet (the clip still owns the layer). */\n get playing(): boolean;\n /** Contribution to the pose: 1 while this clip is the layer's source, 0 once something else took\n * the layer over (the difference between the two poses is what decays, not this weight). */\n get weight(): number;\n /** Resolves at the hand-over (`true`) or when cut short (`false`) — the promise `await playback`\n * uses; the one to return from async functions or put in `Promise.all`. */\n get done(): Promise<boolean>;\n then<A = boolean, B = never>(onFulfilled?: ((v: boolean) => A | PromiseLike<A>) | null, onRejected?: ((e: unknown) => B | PromiseLike<B>) | null): Promise<A | B>;\n /** Move the clock (s). */\n seek(time: number): this;\n /** Cut this clip short (the layer's loop comes back if nothing else takes over), over `fade`. */\n stop(options?: StopOptions): this;\n}\n","types/gl/animation/Warp.d.ts":"/** What `anim.warp` turns on. Speeds are m/s, angles degrees, distances metres. */\nexport type WarpOptions = {\n /** Fit the stride to the speed the body actually travels at. `[min, max]` clamps the scale (default\n * 0.85…1.2). A CORRECTION: a pack whose takes already read right at the speeds it is played at wants\n * none of this; open the range for a pack that must cover speeds it was never recorded at. The clip's\n * own speed is its root motion — an in-place loop takes part only with a declared pace (see above). */\n stride?: boolean | [number, number];\n /** Turn the lower body toward where the body really travels; a number caps the turn in degrees\n * (default 20). The whole twist lives in one joint: a few degrees read as a lean, a lot as a broken\n * back. Only applied while the gait LOOP shows — a start, a turn or a stop walks a path of its own. */\n orientation?: boolean | number;\n /** Below this speed — the game's or the clip's — both warps are off (default 0.2). */\n minSpeed?: number;\n /** How far the pelvis may drop to keep a stretched leg from locking straight (default 0.25). */\n pelvis?: number;\n /** The stride scale's own spring, seconds (default 0.15): the shown clip's recorded speed steps at every\n * switch, so the scale is smoothed rather than followed. */\n strideTime?: number;\n};\n/** STEP WARP dials (`anim.warp.step`): `stride` scales each foot's travel-direction offset from its hip,\n * `lift` = metres ADDED to its height (swing-gated; negative = a shuffle; half of it raises the pelvis),\n * `pitch` (degrees, + = toes up) rotates each foot about its lateral axis, `slope` (degrees, + = ascending)\n * the invisible staircase — feet on the incline, auto pitch, the character raised to hold each planted\n * foot on its tread. A tuning bench's dial; locomotion will drive this itself later. */\nexport type StepWarpOptions = {\n stride?: number;\n lift?: number;\n pitch?: number;\n slope?: number;\n};\nexport declare class Warp {\n private readonly _c;\n private _o;\n private _step;\n /** Replace the settings: `true` = both warps with the defaults, `false` / `{}` = off, or the options.\n * (Replaces, does not merge — what is not asked for is off.) Chainable. */\n set(w: WarpOptions | boolean): this;\n /** The current settings. */\n get options(): Readonly<WarpOptions>;\n get stride(): boolean | [number, number];\n set stride(v: boolean | [number, number]);\n get orientation(): boolean | number;\n set orientation(v: boolean | number);\n get minSpeed(): number;\n set minSpeed(v: number);\n get pelvis(): number;\n set pelvis(v: number);\n get strideTime(): number;\n set strideTime(v: number);\n /** The step warp dials; `null` = off. */\n get step(): StepWarpOptions | null;\n set step(v: StepWarpOptions | null | undefined);\n private push;\n}\n","types/gl/audio/AudioSource.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { type PlaySoundOptions, type Rolloff } from \"../../audio/audio\";\nimport type { Sound } from \"../../audio/Sound\";\nimport type { Voice } from \"../../audio/Voice\";\nimport type { Node } from \"../Node\";\nexport type AudioCone = {\n /** Degrees of full volume around the node's −Z. */\n inner: number;\n /** Degrees where the volume has fallen to `outerGain`. */\n outer: number;\n /** Volume behind the source, 0 … 1. */\n outerGain?: number;\n};\nexport declare class AudioSource extends Aspect<\"audio\", Node> {\n static readonly aspect = \"audio\";\n static fields: FieldMeta<AudioSource>;\n private _minDistance;\n private _maxDistance;\n private _rolloff;\n private _cone;\n private _doppler;\n private _spread;\n private _occlusion;\n private _bus;\n /** Metres of full volume around the node. Default 1. */\n get minDistance(): number;\n set minDistance(v: number);\n /** Metres beyond which the source no longer gets quieter. Default 50. */\n get maxDistance(): number;\n set maxDistance(v: number);\n /** `inverse` (default), `linear`, `exponential`, `none`. */\n get rolloff(): Rolloff;\n set rolloff(v: Rolloff);\n /** Directional source along the node's −Z; null = omnidirectional (default). */\n get cone(): AudioCone | null;\n set cone(v: AudioCone | null);\n /** Doppler amount 0 … 1 (0 = off, the default) — needs the node to actually move. */\n get doppler(): number;\n set doppler(v: number);\n /** 0 = pin-point panning (default) … 1 = the same on every speaker (a big, close source). */\n get spread(): number;\n set spread(v: number);\n /** The engine raycasts listener → source (against solid bodies) and muffles the voices when\n * something is in the way. Default false. */\n get occlusion(): boolean;\n set occlusion(v: boolean);\n /** Default bus for voices on this source. Default `sfx`. */\n get bus(): string;\n set bus(v: string);\n /** Live voices on this source. */\n get voices(): number;\n onAttach(): void;\n onDetach(): void;\n /** Play a clip from this node. */\n play(sound: Sound, options?: PlaySoundOptions): Voice;\n /** Stop every voice on this source (fade in seconds). */\n stopAll(fade?: number): void;\n private _push;\n}\n","types/gl/audio/AudioZone.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type ReverbParams, type ReverbPreset } from \"../../audio/Bus\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\nexport declare class AudioZone extends Aspect<\"audioZone\", Node> {\n static readonly aspect = \"audioZone\";\n private _box;\n private _sphere;\n private _reverb;\n private _blend;\n private _bus;\n /** The engine's zone id — what `audio.stats.listenerZone` reports while the listener is inside. */\n get id(): number;\n /** Half-extents [hx, hy, hz]; falls back to the node's Shape box, then a 1 m cube. */\n get box(): Vec3Like | null;\n set box(v: Vec3Like | null);\n /** Radius; falls back to the node's Shape sphere. */\n get sphere(): number | null;\n set sphere(v: number | null);\n /** A preset name or explicit params (see Bus.reverb). */\n get reverb(): ReverbPreset | ReverbParams;\n set reverb(v: ReverbPreset | ReverbParams);\n /** Crossfade depth in metres inside the border (0 = a hard edge). Default 1. */\n get blend(): number;\n set blend(v: number);\n /** The bus the zone's reverb rides on. Default `sfx`. */\n get bus(): string;\n set bus(v: string);\n onAttach(): void;\n onDetach(): void;\n private _push;\n}\n","types/gl/audio/SceneAudio.d.ts":"import type { Node } from \"../Node\";\nexport declare class SceneAudio {\n private _listener;\n private _doppler;\n /** The node the engine listens from; null (default) = the active camera. */\n get listener(): Node | null;\n set listener(node: Node | null);\n /** Multiplies every source's doppler amount (0 = off everywhere). Default 1. */\n get dopplerFactor(): number;\n set dopplerFactor(v: number);\n}\n","types/gl/Camera.d.ts":"import { Vec3 } from \"../math/vec\";\nimport { Node, type NodeTweenProps } from \"./Node\";\nimport { Ray } from \"./Ray\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport type { Animation } from \"../animate/tween/Animation\";\n/** Animatable camera props on top of the node transform. */\nexport type CameraTweenProps = NodeTweenProps & {\n fov?: number | number[];\n near?: number | number[];\n far?: number | number[];\n};\n/** Projection every host starts a scene with (creator-gl scene.cpp / the lite core agree on these). */\nexport declare const CAMERA_DEFAULTS: {\n fov: number;\n near: number;\n far: number;\n};\nexport declare class Camera extends Node {\n private _sceneId;\n /** Tween `fov` / `near` / `far` (a zoom, a dolly) and the transform — see {@link Node.animateTo}. */\n animateTo(props: CameraTweenProps & TweenMeta): Animation;\n animateFrom(props: CameraTweenProps & TweenMeta): Animation;\n /** Live projection matrix (updated by the host when the viewport/fov changes). */\n readonly projectionMatrix: Float32Array<ArrayBuffer>;\n private _fov;\n private _near;\n private _far;\n /** Stay quiet until the app actually sets something — hosts may be configured with their own\n * defaults (the headless core takes a `fov` option) and a blind push would overwrite them. */\n private _projSet;\n private _exposure;\n private _ev;\n private _exposureSet;\n /** Exposure compensation in stops (default 0): +1 doubles how bright the scene renders, −2\n * quarters it. The one exposure knob most games need — a dark interior, a flash of white, or eye\n * adaptation when the sun swings into view (drop it, and the sun stays at the display's peak\n * while everything else darkens). Scene light follows it; particle `emissive` is post-exposure\n * and does not, so a fireball keeps its on-screen brightness. Cheap to animate every frame. */\n /** The camera's EV100 with the compensation in: log2(aperture² / shutterSpeed x 100 / iso) - compensation. Sunny 16 is\n * ~15; a lit surface of luminance L lands on screen at L / (1.2 x 2^ev100). */\n get ev100(): number;\n get exposureCompensation(): number;\n set exposureCompensation(stops: number);\n /** The physical camera: `aperture` in f-stops, `shutterSpeed` in seconds, `iso`, plus the same\n * `compensation` in stops — any subset, one call. `camera.setExposure({ iso: 400 })` is two stops\n * brighter than the default f/16 · 1/125 · ISO 100. */\n setExposure(exposure: {\n aperture?: number;\n shutterSpeed?: number;\n iso?: number;\n compensation?: number;\n }): this;\n /** Hosts that predate the call keep the fixed default (older wasm / native builds). */\n private _applyExposure;\n /** Vertical field of view in degrees (default 60) — a smaller angle is a longer lens. */\n get fov(): number;\n set fov(degrees: number);\n get horizontalFov(): number;\n /** Near clip distance (default 0.01) — nothing closer than this draws. */\n get near(): number;\n set near(distance: number);\n /** Far clip distance / view range (default 1000) — geometry past it is culled. Shadows keep\n * their own (shorter) range, so a long view distance doesn't cost shadow sharpness. */\n get far(): number;\n set far(distance: number);\n /** Set any of fov / near / far in one call: `camera.setProjection({ fov: 45, far: 5000 })`. */\n setProjection(projection: {\n fov?: number;\n near?: number;\n far?: number;\n }): this;\n /** Hosts that predate the call keep the fixed defaults (older wasm / native builds). */\n private _applyProjection;\n private _following;\n /** The node the camera currently follows (`follow()`), or null. */\n get following(): Node | null;\n /**\n * Make the camera ride a node: every late frame the camera takes the node's WORLD pose (−Z =\n * view direction), so movement aspects / animation on that node are camera moves — dolly shots,\n * a cutscene path, a `CameraPlace` in a scene file. A node carrying a `CameraPlace` also hands\n * over its projection (fov / near / far). `follow(null)` releases the camera where it is.\n * One camera per scene: following a new node stops following the previous one.\n */\n follow(target: Node | {\n node: Node;\n applyTo(camera: Camera): void;\n } | null): this;\n get displaySize(): [number, number];\n /** World-space ray direction through a screen pixel. */\n getViewDirection(screenX: number, screenY: number): Vec3;\n /** A pick ray from the camera through a screen pixel. */\n getRay(screenX: number, screenY: number): Ray;\n}\n","types/gl/CameraPlace.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { FieldMeta } from \"../core/fields\";\nimport type { Camera } from \"./Camera\";\nimport type { Node } from \"./Node\";\nexport declare class CameraPlace extends Aspect<\"cameraPlace\", Node> {\n static readonly aspect = \"cameraPlace\";\n /** Vertical field of view in degrees (default 60) — smaller is a longer lens. */\n fov: number;\n /** Near clip distance. */\n near: number;\n /** Far clip distance = view range. */\n far: number;\n /** The place that drives `scene.camera` when the file declaring it RUNS. Exactly one per file;\n * ignored inside prefabs / instantiated subtrees (the host scene owns its camera). */\n active: boolean;\n /** Aspect ratio of the frustum gizmo only (the real aspect is the viewport's). */\n static fields: FieldMeta<CameraPlace>;\n static editor: {\n rebuild: boolean;\n };\n /** Copy this place's projection onto a camera (`camera.follow(place)` does it for you). */\n applyTo(camera: Camera): void;\n /** Edit mode: the frustum marker (−Z = view), anchored on the node so it follows drags live and\n * clicking it selects the node. Play mode never calls this. */\n rebuild(): void;\n}\n","types/gl/controls.d.ts":"import type { Node } from \"./Node\";\nimport type { Scene } from \"./Scene\";\nexport type ControlsOptions = {\n /** Smallest uniform scale the pinch gesture allows (default 0.08). */\n minScale?: number;\n /** Largest uniform scale the pinch gesture allows (default 2). */\n maxScale?: number;\n /** One-finger drag moves the target across the ground plane (default true). */\n pan?: boolean;\n /** Two-finger pinch scales the target (default true). */\n pinch?: boolean;\n /** Two-finger twist rotates the target around its Y axis (default true). */\n twist?: boolean;\n};\n/** Returned by `addControls` — call `remove()` to detach the gesture listeners. */\nexport type ControlsHandle = {\n remove(): void;\n};\nexport declare const attachControls: (scene: Scene, target: Node, options?: ControlsOptions) => ControlsHandle;\n","types/gl/DecalSet.d.ts":"import { Node } from \"./Node\";\nimport { Material } from \"./Material\";\nimport type { Texture } from \"./Texture\";\nimport { type Vec3Like } from \"../math/vec\";\nimport { type QuatLike } from \"../math/quat\";\nimport { type ColorInput } from \"../core/color\";\n/** Per-decal look and life — defaults come from the set's options. */\nexport type DecalOptions = {\n /** Image width and height on the surface (world units); a number = square. Default 0.2. */\n size?: number | [number, number];\n /** Projection depth (world units): how far in front of and behind the hit point the decal still\n * lands. Default = the smaller of width / height. */\n depth?: number;\n /** Atlas cell (row-major from the top-left) for a set with a `sheet`; `\"random\"` picks one.\n * Default 0. */\n frame?: number | \"random\";\n /** Tint multiplied into the image. Default white. */\n tint?: ColorInput;\n /** 0..1 on top of the tint's alpha. Default 1. */\n opacity?: number;\n /** Seconds until the decal is gone; 0 = stays until recycled. Default 0. */\n life?: number;\n /** Seconds to fade in after spawning. Default 0. */\n fadeIn?: number;\n /** Seconds of fade at the end of `life` (ignored with life 0). Default 0. */\n fadeOut?: number;\n /** Opacity multipliers at the image's BOTTOM and TOP edge (−Y / +Y), interpolated along it — a\n * tire mark that darkens as the slide deepens. Default `[1, 1]`. */\n gradient?: [number, number];\n /** Tilt of the image's bottom and top edge, as a unit-space slope (Δy per Δx across the box):\n * the edge pivots on the corner of the side it keeps and cuts INTO the box on the other, so two\n * boxes can meet on one shared line — what `DecalTrail` uses to mitre its joints. `0` = square.\n * Default `[0, 0]`. */\n caps?: [number, number];\n};\nexport type DecalSetOptions = DecalOptions & {\n /** The material — `Material.decal({ map })` by default (`map` below is its shortcut). A custom\n * material must keep decal.mat's vertex contract. */\n material?: Material;\n /** Atlas texture for the default material. */\n map?: Texture;\n /** Tangent-space normal atlas (same cell grid) → a RELIEF decal that bends the surface's\n * lighting instead of painting a colour (`Material.decal` `normalMap`). Footprints and dents\n * need only this; a bullet hole gives `map` too and its colour multiplies in. */\n normalMap?: Texture;\n /** Relief strength for `normalMap`. Default 1. Default material only. */\n bump?: number;\n /** Atlas grid of the map: columns, or [columns, rows]. Default 1 (the whole texture). */\n sheet?: number | [number, number];\n /** Slot budget — the most decals alive at once. Default 256. */\n max?: number;\n /** Soft fraction (0..1) of the box's half depth at both ends, so an oblique surface leaves the\n * box gently. Default 0.3. Default material only. */\n edge?: number;\n /** Surfaces turned more than this away from the projection axis fade out — the cosine of the\n * angle (0.3 ≈ 72°) keeps a floor hit off the wall it meets; 0 = project onto anything.\n * Default 0.3. Default material only. */\n angleFade?: number;\n /** HDR boost of the image (0 = none). Default material only. */\n emissive?: number;\n name?: string;\n /** Coarse draw order, 0 (first) … 7 (last) — see `Mesh.renderPriority`. Default 3: a decal is\n * part of the surface it sits on, so it draws before every other blended thing (meshes 4,\n * particles 5) — the engine's depth sort compares object centres, and a set spread over the\n * level has no useful centre. */\n renderPriority?: number;\n};\n/** `spawn` placement: where the image sits on the surface. */\nexport type DecalSpawnOptions = DecalOptions & {\n /** World direction the image's top points along the surface (projected onto it) — a footprint's\n * travel direction. Default: a random spin. */\n up?: Vec3Like;\n /** Extra spin around the normal, radians. Default: random when `up` is not given, else 0. */\n rotation?: number;\n};\n/** `place` / `update` placement: a full frame, like a node looking INTO the surface (its −Z is the\n * projection direction, +Y the image's top). */\nexport type DecalPlacement = DecalOptions & {\n position: Vec3Like;\n /** A quaternion, or Euler degrees (YXZ) like `Node.eulerAngles`. Default identity = projecting\n * down −Z. */\n rotation?: QuatLike | Vec3Like;\n};\nexport declare class DecalSet extends Node {\n private _material;\n private readonly _max;\n private readonly _cols;\n private readonly _rows;\n private readonly _defaults;\n private readonly _rec;\n private readonly _slots;\n private static _warned;\n constructor(options?: DecalSetOptions);\n get material(): Material;\n /** Decals alive right now. */\n get count(): number;\n /** The slot budget the set was created with. */\n get max(): number;\n /** Coarse draw order, 0 … 7 — see `Mesh.renderPriority`. Write-only. */\n set renderPriority(v: number);\n /** Stamp a decal on a surface: `point` on it, `normal` out of it (a raycast hit, a foot plant\n * with `Vec3.up`). Returns the slot for `update` / `remove` (−1 when the host draws none). */\n spawn(point: Vec3Like, normal: Vec3Like, options?: DecalSpawnOptions): number;\n /** Place a decal by a full frame (an editor-placed stain, a moving marker). Returns the slot. */\n place(placement: DecalPlacement): number;\n /** Move / restyle a placed decal; fields left out keep the values it was placed with. Its birth\n * time (the life clock) is kept. */\n update(slot: number, placement: Partial<DecalPlacement>): this;\n remove(slot: number): this;\n clear(): this;\n private _writePlacement;\n}\n/** A `DecalTrail`'s look: the strip's width, and what every segment carries. */\nexport type DecalTrailOptions = Omit<DecalOptions, \"size\" | \"caps\" | \"gradient\"> & {\n /** Width of the strip on the surface, world units. */\n width: number;\n};\n/**\n * A continuous strip of decals along a path — a tire's skid mark, a dragged body, a tread track.\n * Feed it points (`add`) as the thing moves; every new point becomes one box-decal SEGMENT from the\n * previous point, its image's up along the travel, and the joints between segments are MITRED: each\n * box is cut along the bisector it shares with its neighbour (`caps`), so the strip has no overlaps\n * darkening the outside of a bend and no wedges of gap on the inside. The opacity given with each\n * point is interpolated along the segment (`gradient`), so a mark can darken as a slide deepens and\n * fade as it ends. Segments are the set's decals — same ring, same `max` budget: a set of 900 holds\n * 900 segments across every trail drawn from it.\n *\n * The previous segment is REWRITTEN when the next point arrives (its far cap becomes the shared\n * mitre), through `DecalSet.update`'s path — a recycled slot is simply left alone by the engine.\n */\nexport declare class DecalTrail {\n private _prev;\n private _seg;\n readonly set: DecalSet;\n readonly options: DecalTrailOptions;\n constructor(set: DecalSet, options: DecalTrailOptions);\n /** Extend the strip to `point` on a surface with `normal`, `opacity` (0..1) at that point. The\n * first call after a start / `end()` only anchors the strip. Returns the new segment's slot, or\n * −1 when nothing was drawn (the anchor, a point that did not move, no host support). */\n add(point: Vec3Like, normal: Vec3Like, opacity?: number): number;\n /** Finish the strip. With a `point`, one last segment runs out to it at opacity 0 — a mark that\n * tapers away instead of stopping dead. The next `add` anchors a new strip. */\n end(point?: Vec3Like, normal?: Vec3Like): this;\n private _rewrite;\n /** Write one segment's box: the strip between its joints, extended past each mitred joint by the\n * mitre's reach (w/2 · |slope|) so the tilted cap still passes through the joint's centre. */\n private _box;\n}\n","types/gl/Foliage.d.ts":"import { Model } from \"./Model\";\nimport { Node } from \"./Node\";\nexport type FoliageWind = {\n /** Direction on the ground (x, z); normalised by the engine. Default [1, 0.3]. */\n direction?: [number, number];\n /** The wind speed in m/s — the plants' permanent bend and how fast the field drifts past them. Default 8.3\n * (30 km/h, the pack's demo). 0 = still. */\n speed?: number;\n /** 0..2: the random share of the speed — how far the bend wanders off the mean wind and how much the leaves move.\n * Default 0.4. */\n turbulence?: number;\n /** 0..1: the gusts' strength — waves of extra wind that travel over the level, calm between. Default 0.35. */\n gust?: number;\n /** m/s the gust pattern travels at. Default 5.6 (20 km/h). */\n gustSpeed?: number;\n};\nexport type FoliageOptions = {\n /** The wind, or `false` for none. */\n wind?: FoliageWind | false;\n /** Metres the TOP of a small plant leans away from a bender standing at its centre; the whole plant leans\n * as one, rooted at its base. Plants over ~2 m react less, trees over ~5 m not at all (the engine\n * measures each asset). Default 0.6. 0 = no touch reaction. */\n touch?: number;\n /** 0..1: how far each copy's tint drifts from the texture (warmer/darker to cooler/lighter, by a hash\n * of its position). Default 0.35. */\n variation?: number;\n /** 0..1: wrapped sun lighting — thin leaves let light through. Default 0.5. */\n sunWrap?: number;\n /** A multiplier on every material's shiver drag (the leaves' own motion on top of the bend): 1 = as the\n * model's materials say, 0 = the leaves ride the bend alone. Default 1. */\n shiver?: number;\n /** 0..1: the sun through a thin leaf lit from behind (a back-lit crown glows). Default 0.35. */\n translucency?: number;\n /** 0..1: how much of a light's shadow a leaf card takes. A crown scatters light through itself, so its cards take the\n * shadow map partly — at 1 a distant crown is a dark silhouette lit only on its top layer. Bark always takes the\n * shadow in full. Default 0.6. */\n leafShadow?: number;\n /** 0..1: how far the baked per-vertex sky visibility (the crown's interior, the trunk under it) darkens the ambient.\n * Default 0.7. */\n skyAo?: number;\n /** 0..1: a leaf card's shading normal, from the card's own plane (0) to the crown's hull normal (1) — what hides that a\n * crown is flat quads: each card is lit as the part of the volume it sits in. Default 0.7. */\n canopy?: number;\n /** The cards' normal-map strength (a strong map brings the planes back). Default 0.5. */\n normalMap?: number;\n /** A card seen edge-on dissolves over this much of |N·V| — no paper edges on the silhouette. Default 0.15, 0 = none. */\n edgeFade?: number;\n /** Coverage held over distance: the cards' alpha × (1 + coverage × mip level), so a far crown does not thin out as its\n * atlas mips away. Default 0.25, 0 = none; past ~0.5 a crown turns into a solid mass. */\n coverage?: number;\n};\nexport declare const Foliage: {\n /** Level-wide options; each field given replaces the current value (a scene file's `env.foliage`\n * goes through here). */\n configure(options: FoliageOptions): void;\n /** The wind: fields given replace the current ones; `false` = calm. Live. */\n wind(wind: FoliageWind | false): void;\n /** A node whose live position pushes the vegetation within `radius` metres (the hero: ~0.7; a\n * boulder: its size). Any number may be registered; the 8 nearest the camera act each frame. The\n * engine also tracks the node's velocity (smoothed over ~0.2 s): a plant you run through is brushed\n * forward and settles behind you instead of flipping as you cross its centre.\n * Returns the unregister function; a destroyed node drops out on its own. */\n bend(node: Node, radius?: number): () => void;\n /** Stop a node from bending the vegetation. */\n unbend(node: Node): void;\n /** Distance fade for EVERY copy of this model's asset (present and future): the cards thin out\n * from `start` to `end` metres from the camera and past `end` the copy leaves the frame entirely.\n * Small ground cover (grass, clover, flowers) is the target; `end` 0 = no fade. */\n fade(model: Model, start: number, end: number): void;\n};\n","types/gl/Geometry.d.ts":"import { type Vec3Like } from \"../math/vec\";\nexport type MeshKind = \"triangles\" | \"vertices\" | \"edges\";\n/** A geometry file — what `lecodes assets geometry <model.glb>` writes (`<model>.geometry.json`):\n * one merged, world-space triangle buffer. `Geometry.load(asset('./casing.geometry.json'))`. */\nexport type GeometryData = {\n format?: \"lecodes-geometry\";\n version?: number;\n /** xyz per vertex. */\n vertices: ArrayLike<number>;\n /** xyz per vertex (unit length). */\n normals: ArrayLike<number>;\n /** uv per vertex. */\n uv: ArrayLike<number>;\n /** Triangle list, ≤ 65535 vertices addressed. */\n indices: ArrayLike<number>;\n};\nexport declare class Geometry {\n vertices: Float32Array;\n normals: Float32Array;\n indices: Uint16Array;\n uv: Float32Array;\n /** Lightmap UV set (2 floats per vertex, non-overlapping, inside the unit square) — the\n * `Lightmap` atlas samples a Mesh through it. The box and cylinder builders fill it (their `uv`\n * tiles per face, which would fold every face onto the same texels); absent = the host reuses\n * `uv`, which is right for a plane. */\n uv1?: Float32Array;\n /** Per-vertex COLOURS: 4 bytes (r, g, b, a) per vertex, 0..255. A material that declares\n * `requires: [color]` reads them through `getColor()` — one mesh, many colours, no material per\n * shade (a debug drawer, a gradient along a curve). Absent = every vertex white, which is what\n * the built-in materials expect. */\n colors?: Uint8Array;\n constructor(vertices: Float32Array, normals: Float32Array, indices: Uint16Array, uv: Float32Array);\n translate(x: number, y: number, z: number): this;\n scale(x: number, y: number, z: number): this;\n scaleUV(x: number, y: number): this;\n set kind(kind: MeshKind);\n /** A box; `size` (default 1) scales the vertices AND lays the lightmap chart out in proportion to\n * the faces' areas (a floor's top face gets the texels, not its 1 m side strips). */\n static box(size?: Vec3Like | number): Geometry;\n static sphere(options?: SphereOptions): Geometry;\n static cylinder(options?: CylinderOptions): Geometry;\n /** A capsule along Y, centred at the origin: a cylinder `length` long (between the two cap centres)\n * with a hemisphere of `radius` on each end — one closed surface, smooth across the seams. */\n static capsule(options?: CapsuleOptions): Geometry;\n static plane(options?: PlaneOptions): Geometry;\n /** A Geometry from a geometry file's contents (`GeometryData` — see `Geometry.load`). The arrays\n * are copied into typed buffers, so the source object can be dropped. */\n static fromData(data: GeometryData): Geometry;\n /** Load a geometry file: `lecodes assets geometry casing.glb` → `casing.geometry.json` →\n * `await Geometry.load(asset('./casing.geometry.json'))`. A GLB's triangles as a plain buffer,\n * for `Particles({ mesh })` debris (shell casings, rubble) and `Mesh.from`.\n * A `.json` project file is INLINED by the compiler — `asset('./x.json')` is the parsed data, not\n * a URL — so that form (and `import data from './x.json'`) is read directly, no fetch; a string\n * (a URL, a non-`.json` asset such as `.geo`) is fetched. */\n static load(source: string | GeometryData): Promise<Geometry>;\n}\nexport type SphereOptions = {\n radius?: number;\n widthSegments?: number;\n heightSegments?: number;\n};\nexport type CapsuleOptions = {\n radius?: number;\n /** Distance between the two cap centres (the straight part); 0 = a sphere. Default 1. */\n length?: number;\n /** Segments around the axis. */\n widthSegments?: number;\n /** Rings per hemisphere (pole to equator). */\n capSegments?: number;\n};\nexport type CylinderOptions = {\n radius?: number;\n radiusTop?: number;\n radiusBottom?: number;\n edges?: number;\n smooth?: boolean;\n};\nexport type PlaneOptions = {\n normal?: Vec3Like;\n};\n","types/gl/InstancedMesh.d.ts":"import { Mat4, type Mat4Like } from \"../math/mat4\";\nimport { type QuatLike } from \"../math/quat\";\nimport { type Vec3Like } from \"../math/vec\";\nimport type { Geometry } from \"./Geometry\";\nimport { Material } from \"./Material\";\nimport type { MeshOptions } from \"./Mesh\";\nimport { Node } from \"./Node\";\n/** One instance's placement, local to the InstancedMesh node. Omitted fields mean identity. */\nexport type InstanceTransform = {\n position?: Vec3Like;\n /** Quaternion; wins over `eulerAngles`. */\n rotation?: QuatLike;\n /** Degrees (YXZ), like `Node.eulerAngles`. */\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n};\nexport declare class InstancedMesh extends Node {\n /** Instance capacity, fixed at construction. Unset instances are hidden. */\n readonly count: number;\n private _geometry;\n private _material;\n private _data;\n private _lo;\n private _hi;\n constructor(geometry: Geometry, count: number, options?: MeshOptions);\n get geometry(): Geometry;\n get material(): Material;\n set material(m: Material);\n /** Shadow flags for all instances (both at once — the engine sets them per draw). */\n setShadows(cast: boolean, receive?: boolean): this;\n private _touch;\n /** Place instance `i`. Pending until `commit()`. */\n setAt(i: number, t: InstanceTransform): this;\n /** Place instance `i` from a 4×4 column-major matrix (local to this node). */\n setMatrixAt(i: number, m: Mat4Like): this;\n /** Hide instance `i` (a zero matrix — no geometry is emitted for it). */\n hideAt(i: number): this;\n /** Bulk write: `matrices` holds 16 floats per instance, starting at instance `offset`. */\n setMatrices(matrices: ArrayLike<number>, offset?: number): this;\n /** The 4×4 of instance `i` as stored (a copy). */\n matrixAt(i: number): Mat4;\n /** Upload every change since the last commit (one bridge call covering the dirty range). */\n commit(): this;\n /** Whether edits are waiting for `commit()`. */\n get dirty(): boolean;\n}\n","types/gl/Light.d.ts":"import { type ColorInput } from \"../core/color\";\nimport type { Vec3Like } from \"../math/vec\";\nimport { Node, type NodeTweenProps } from \"./Node\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport type { Animation } from \"../animate/tween/Animation\";\n/** Animatable light props on top of the node transform. */\nexport type LightTweenProps = NodeTweenProps & {\n intensity?: number | number[];\n color?: ColorInput | ColorInput[];\n};\nexport type SunOptions = {\n /** Light direction (points where the light travels). Defaults to a typical key-light angle. */\n direction?: Vec3Like;\n /** Luminous intensity. */\n intensity?: number;\n color?: ColorInput;\n /**\n * Shadow quality (default 1):\n * 0 - no shadows\n * 1 - 1024 map, hard edges (one filtered tap; the cheap level, ~3 % of a frame on an iGPU)\n * 2 - 1024 map, soft edges (variance shadows + blur; ~+15 % of a frame on an iGPU)\n * 3 - 2048 map, contact-hardening soft edges (PCSS: sharp where the caster touches, softer\n * away; discrete-GPU territory, ~+60 % of a frame on an iGPU)\n * A lightmapped level already carries every static shadow, so 0 is a legitimate choice there.\n * On a level with a baked light grid the variance / PCSS filters cannot be used (they need every\n * receiver in the shadow map, and the baked statics are kept out of it): 3 renders as PCSS on the\n * depth map - the same contact-hardening look - and 2 renders as 1.\n */\n shadowsQuality?: 0 | 1 | 2 | 3;\n /**\n * Metres from the camera within which the sun casts shadows (default 100). Shadows fade out by\n * this distance and the shadow map covers only this range, so a shorter distance is crisper for\n * the same quality and puts fewer casters in the shadow pass. 30-40 is plenty in first person.\n */\n shadowDistance?: number;\n /**\n * How many shadow-map cascades split `shadowDistance` (default 1). One map over the whole range gives a tall\n * tree 5-10 cm shadow texels on its own trunk; 3 cascades put a tight map on the first metres and coarser\n * ones behind, fit to their texel grids so the shadow does not swim as the camera moves. Each cascade is\n * another caster pass, so it costs in proportion to what casts: forests, not a lightmapped level.\n */\n shadowCascades?: 1 | 2 | 3 | 4;\n};\nexport type PointOptions = {\n /**\n * Luminous POWER in lumens — the same physical scale as the sun's lux and `environmentIntensity`,\n * so a light keeps its look when the scene's exposure changes. A candle is ~12 lm, a bare 60 W\n * bulb ~800, a car headlight ~1500, a fireball millions. Default 1000.\n */\n intensity?: number;\n color?: ColorInput;\n /**\n * Metres of influence — past it the light contributes nothing. This is the performance knob:\n * overlapping point lights are the expensive case, so keep it as small as the look allows.\n * Default 10.\n */\n range?: number;\n /** Point-light shadows are a cubemap render per light; off by default. */\n castShadows?: boolean;\n /**\n * Whether `lecodes lightmap bake` bakes this light into the level's lightmap. A baked lamp lights the statics\n * from the atlas and the MOVERS from the level's light grid, and is held dark in real time while that grid is\n * loaded (without a grid it keeps lighting the movers live); a light\n * that must reach the statics live too — a flicker, a lamp the player can shoot out, a muzzle flash —\n * says `baked: false`: it is kept out of the bake and put on the statics' light channel. Default true.\n */\n baked?: boolean;\n /**\n * THE BAKE'S SHAPE of this lamp: `[width, height]` in metres = an AREA light - a rectangle in the light's local XZ\n * plane, emitting along its local -Y (down, for an unrotated node) with the same lumens: a ceiling panel. The bake\n * lights from the whole rectangle (soft shadows, light from where the panel is and not from a point inside the\n * fixture). Real time it is still the point light above. Ignored with `baked: false`.\n */\n bakeArea?: readonly [number, number];\n};\nexport type SpotOptions = {\n /**\n * Luminous power in lumens, as a point light's. The cone does not change the brightness: widen it and the\n * same lumens light a larger patch at the same level. On its axis a spot is 4x brighter than a point light of\n * the same lumens (its light is not spread over the whole sphere). Default 1000.\n */\n intensity?: number;\n color?: ColorInput;\n /** Metres of influence along the cone, the performance knob as for a point light. Default 10. */\n range?: number;\n /** The cone's full angle in degrees, up to 180: past it the light contributes nothing. Default 45. */\n angle?: number;\n /** The full angle in degrees of the cone's fully lit core; the light fades from it out to `angle`. Default 0.75 x `angle`. */\n innerAngle?: number;\n /** A spot's shadow is one 2D shadow map (a point light's is a cubemap); off by default. */\n castShadows?: boolean;\n};\nexport declare class Light extends Node {\n private _intensity;\n /** Tween `intensity` / `color` (a flash, a sunrise) and the transform — see {@link Node.animateTo}. */\n animateTo(props: LightTweenProps & TweenMeta): Animation;\n animateFrom(props: LightTweenProps & TweenMeta): Animation;\n /** The most recently created sun. */\n static lastSun: Light | null;\n _shadowDistance: number;\n _shadowCascades: number;\n /** A directional sun light. */\n static sun(options?: SunOptions): Light;\n /**\n * A point light — a lamp, a muzzle flash, a fireball. Position it like any node.\n */\n static point(options?: PointOptions): Light;\n _innerAngle: number;\n /**\n * A spot light — a flashlight, a headlight, a stage light. It shines along the node's forward (-Z): position\n * it like any node and aim it with `lookAt`. Real time only: the lightmap bake takes no spot lights, so a spot\n * lights the baked statics live too.\n */\n static spot(options?: SpotOptions): Light;\n /** A spot's full cone angle in degrees — live (a flashlight's focus). */\n get angle(): number;\n set angle(value: number);\n /** A spot's fully lit core, full angle in degrees — live. Setting `angle` scales it along. */\n get innerAngle(): number;\n set innerAngle(value: number);\n /** Live intensity (sun: lux, point / spot: lumens) — animate a flash without rebuilding the light. */\n get intensity(): number;\n set intensity(value: number);\n _holdDark(dark: boolean): void;\n destroy(): void;\n set color(value: ColorInput);\n get color(): ColorInput;\n /** Sun direction as created (the engine keeps it; a settings menu rebuilds a sun from it). */\n get direction(): [number, number, number];\n /** Sun shadow options as created — creation-time in the engine, so a change means a new sun. */\n get shadowsQuality(): number;\n get shadowDistance(): number;\n}\n","types/gl/Lightmap.d.ts":"import { Node } from \"./Node\";\nimport type { Scene } from \"./Scene\";\nexport type LightmapLoadOptions = {\n /** A DEBUG multiplier on the atlas' lux (default 1): the atlas is physical, so this is a knob for looking,\n * not a look. */\n lightScale?: number;\n /** The level's own radiance of emission 1.0 for the BAKE (cd / m², `BakeConfig.emissiveNits`): an imported pack's\n * emissive values are tuned for a look, not for light - this is where the level says how much its panels really give.\n * The CLI's `--emissive-nits` wins over it; without either the camera's exposure decides. */\n emissiveNits?: number;\n /** `false` = the emissive surfaces light NOTHING in the bake (the level is lit by its lamps, the panels are decoration)\n * while `emissiveNits` still says how bright their glow is drawn. Default true. */\n emissiveBake?: boolean;\n /** FOR THE BAKE: materials that let light THROUGH them, by their glTF name (`\"name*\"` = every name with that start):\n * the share of a shadow ray that passes, tinted by the material's base colour x map - an awning's warm, patterned light\n * on the sand. The surface itself stays opaque: baked, drawn as before, a real-time shadow caster.\n * A number = the share that goes STRAIGHT through (the gaps of a weave: it draws the map's picture on the ground);\n * `{ through, diffuse }` adds the share the fibres SCATTER - the cloth's underside glows like a matte panel and lights\n * what is under it by the solid angle it fills, with no picture. Dense canvas: `{ through: 0.08, diffuse: 0.25 }`. */\n transmit?: Record<string, LightmapTransmit>;\n};\n/** one `transmit` entry (LightmapLoadOptions.transmit): the straight share, or both shares */\nexport type LightmapTransmit = number | {\n through?: number;\n diffuse?: number;\n};\nexport type LightmapInfo = {\n size: number;\n texel: number;\n /** Atlas pages the bake took (`light` / `aux` list them in order). */\n pages: number;\n /** keys applied / keys in the file / registered statics without a rect */\n applied: number;\n total: number;\n missing: string[];\n};\nexport type LightmapFiles = {\n data: string;\n /** The irradiance atlas — one page, or every page in order for a bake that took several. */\n light: string | string[];\n /** The aux atlas (sun / sky visibility + light direction), pages like `light`. */\n aux: string | string[];\n /** DEBUG: the direct-light-only pages a `--split` bake wrote (`<stem>-direct[_n].ktx2`), for the \"direct\" view. */\n direct?: string | string[];\n /** DEBUG: the bounce-only pages of a `--split` bake (`<stem>-indirect[_n].ktx2`), for the \"indirect\" view. */\n indirect?: string | string[];\n /** The reflection probes (`<stem>-probes.ktx2`), when the bake placed some (`lecodes lightmap bake --probe-spacing`). */\n probes?: string;\n /** THE LIGHT GRID for movers (`<stem>.lgrid`, `lecodes lightmap bake --volume`): the baked ambient light of every\n * place a mover can be. Absent = movers keep the scene's IBL. */\n volume?: string;\n};\n/** The lightmap material's data views (`Lightmap.debug`); \"direct\" / \"indirect\" bind a `--split` bake's pages instead. */\nexport type LightmapDebugMode = \"off\" | \"irradiance\" | \"albedo\" | \"normal\" | \"shadingNormal\" | \"share\" | \"skyVis\" | \"atlas\" | \"direction\" | \"lux\" | \"relief\" | \"direct\" | \"indirect\" | \"probe\" | \"probeMap\" | \"skyPath\" | \"probePath\";\nexport type LightmapDebugParams = {\n /** `lux`: the false-colour ramp's log10 range (default 0..5, i.e. 1 lux .. 100 000). */\n luxRange?: [number, number];\n};\n/** What `Lightmap.probe` answers: the baked texel under a screen point. */\nexport type LightmapProbe = {\n key: string;\n entity: number;\n node: string;\n material: string;\n page: number;\n /** The texel's column / row on its page. */\n texel: [number, number];\n uv1: [number, number];\n world: [number, number, number];\n distance: number;\n};\nexport declare class Lightmap {\n /** True while `lecodes lightmap bake` runs the app — skip menus and build the scene straight away. */\n static get baking(): boolean;\n private static entries;\n private static ordinals;\n private static warned;\n /** The bake bound last (`load`): what `probe` reads rects from. */\n private static bound;\n /** Register static geometry — a Model, a Mesh, or any node whose subtree holds them. Statics are\n * both receivers and occluders in the bake. `key` names the entry in the .bake (default:\n * the node's name + a running number, `container#3`); pass one when names are not stable. */\n static add(node: Node, key?: string): Node;\n private static next;\n private static movers;\n private static volumeOn;\n /** A MOVER takes its ambient light from the level's baked LIGHT GRID (`env.lightmap.volume`) at the place it is at,\n * every frame — whatever its shader: the standard glTF one or a custom lit material. Every Model / Mesh under `node`\n * is marked (a character, a weapon with its parts). A scene file does this itself for every node a Physics aspect or\n * a CharacterController moves; call it for what CODE spawns — an enemy, a pickup, a projectile. `on = false` hands\n * the subtree back to the scene's IBL. Safe before the level's bake has loaded. */\n static track(node: Node, on?: boolean): void;\n private static loadVolume;\n /** Forget every registration (a scene rebuild). */\n static clear(): void;\n /** THE MOVERS' SUN SHADOWS ON THE BAKED STATICS (a bot, a barrel, the player's rifle darkening the ground under\n * it): the lightmap shader reads the real-time shadow map and the bake's sun map for it, per pixel. Off, a baked\n * surface takes no real-time shadow at all — the cheapest lighting tier (some 4 ms of a 16 ms 720p frame on an\n * integrated GPU, the yard 2026-09-26); a mover still shades ITSELF and the other movers. Live: it rebinds the\n * level's material instances at once. */\n static get moverShadows(): boolean;\n static set moverShadows(on: boolean);\n private static _moverShadows;\n /** The loaded bake's sun (TO the sun ×3, its illuminance rgb, the sun map's levels), null without a sun map. */\n private static sunArgs;\n private static applySun;\n /** Apply a bake — or, under `lecodes lightmap bake`, run it. Resolves to null when nothing was\n * applied (no bake yet, a host without the feature, bake mode). */\n private static scene;\n static load(scene: Scene, files: LightmapFiles, options?: LightmapLoadOptions): Promise<LightmapInfo | null>;\n /** The bake's `<key>#k` instances by their base key: the parts of a GLB unwrapped in groups (k = extras.lightmapGroup). */\n private static groupsOf;\n /** Switch every lightmapped surface to a DATA view (or back with `\"off\"` / 0). Level-wide, instant —\n * except \"direct\" / \"indirect\", which load that page set the first time (a `--split` bake listed in the scene). */\n static debug(mode: LightmapDebugMode | number, params?: LightmapDebugParams): void;\n /** Bind another page set of the bound bake to every surface (the \"direct\" / \"indirect\" views). */\n private static show;\n private static balls;\n /** DEBUG: a mirror ball at every reflection probe of the bound bake (`on`), or none (`off`) — a ball reflects the\n * probes around its point unoccluded (at a probe's own position that is the probe itself), so a probe inside a\n * wall, a black one or a leak across a wall shows at a glance. Metallic, roughness 0; view \"probe\" shows the\n * probes alone. */\n static debugProbes(on: boolean, radius?: number): number;\n /** The view names in `lightmapDebug`'s order — for a knob that cycles them. */\n static get debugModes(): readonly LightmapDebugMode[];\n /** The baked texel under a screen point (logical px): its instance key, page and texel column / row,\n * so the value can be looked up in the bake's debug layers (`lecodes lightmap inspect`). null when\n * nothing baked is under the point or the host has no triangle pick. */\n static probe(screenX: number, screenY: number): LightmapProbe | null;\n /** A material's colour uniform as \"#rrggbbaa\" (the float4 uniform path sets its alpha); white without one. */\n private static colorUniform;\n /** The lightmap material for a static Mesh, from whatever lit material it carried (colour, map, roughness, metallic). */\n private static meshMaterial;\n private static bake;\n}\n","types/gl/Material.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type FetchResponse } from \"../runtime/fetch\";\nimport { Texture } from \"./Texture\";\nimport type { Canvas } from \"../canvas/Canvas\";\ntype UniformValue = string | Texture | number | boolean | number[] | Float32Array | null;\nexport type MaterialColorOptions = {\n color?: ColorInput;\n map?: Texture | Canvas | null;\n};\n/** How a stencil test / write on a material compares and what it writes. `test` runs against the\n * scene's stencil buffer (`Scene.stencil` must be on); the ops say what the buffer gets when the\n * fragment passes / fails the stencil test / fails the depth test (`replace` writes `ref`). */\nexport type StencilTest = \"always\" | \"never\" | \"less\" | \"lessEqual\" | \"greater\" | \"greaterEqual\" | \"equal\" | \"notEqual\";\nexport type StencilOp = \"keep\" | \"zero\" | \"replace\" | \"increment\" | \"decrement\" | \"invert\";\nexport type MaterialStencil = {\n /** Write the stencil buffer at all. Default `false`. */\n write?: boolean;\n /** The reference value, 0..255. Default 0. */\n ref?: number;\n /** Default `\"always\"`. */\n test?: StencilTest;\n onPass?: StencilOp;\n onFail?: StencilOp;\n onDepthFail?: StencilOp;\n readMask?: number;\n writeMask?: number;\n};\n/** Render state a material instance can override at run time (Filament keeps the defaults in the\n * shader package; these are per-instance overrides on top). */\nexport type MaterialStateOptions = {\n /** Test against the scene's depth buffer. `false` draws over everything already drawn — an\n * editor gizmo, a marker that must never hide behind a wall. Pair it with a high\n * `Mesh.renderPriority` so nothing drawn later covers it. Default `true`. */\n depthTest?: boolean;\n /** Write to the depth buffer. Leave it on for something drawn over the scene whose own parts must\n * still occlude each other (a gizmo's cone in front of its shaft). Unset = the shader's default\n * (on for opaque, off for a blended one). */\n depthWrite?: boolean;\n /** Draw both faces (no back-face culling): a plane seen from behind, a ribbon, cloth, a flat\n * marker. Default `false` = the shader's culling (back faces dropped). */\n doubleSided?: boolean;\n /** A stencil test / write for this material — see `MaterialStencil`. The selection-outline\n * recipe: the object writes `{ write: true, ref: 1, onPass: \"replace\" }`, and a slightly larger\n * copy of it draws with `{ test: \"notEqual\", ref: 1 }` + `depthTest: false` in `renderPriority` 7. */\n stencil?: MaterialStencil;\n};\n/** @deprecated the name before doubleSided / stencil joined it — the same type */\nexport type MaterialDepthOptions = MaterialStateOptions;\n/** `Material.unlit` options. */\nexport type UnlitMaterialOptions = MaterialColorOptions & MaterialStateOptions & {\n /** Alpha-blend this material instead of drawing it opaque. Opaque is the default: a blended draw\n * writes no depth, is sorted back-to-front and casts no shadow, which is rarely what a flat\n * colour wants. Turn it on for anything that must show what is behind it — a glass pane, a\n * fading marker, a sprite whose texture has cut-out alpha. Only then does `color`'s own alpha\n * (`\"#ffffff80\"`) mean anything; the opaque material has no alpha channel at all. */\n transparent?: boolean;\n};\n/** `Material.decal` options — the projected-decal material a `DecalSet` draws with. */\nexport type DecalMaterialOptions = {\n /** The atlas (a `DecalSet`'s `sheet` cuts it into cells). */\n map?: Texture;\n /** A tangent-space normal atlas (same cell grid; +X = the image's right, +Y = its top; LINEAR —\n * `Texture.fromPixels(…, { srgb: false })`). Turns the decal into a RELIEF decal: instead of\n * painting a colour it bends the surface's lighting, so a footprint or a dent shows on any\n * surface without a colour of its own. With `map` too, the colour multiplies in (a crater\n * darkens by the map's alpha). The sun term applies in shadow as well (no shadow read). */\n normalMap?: Texture;\n /** Relief strength — the normal map's xy scale. Default 1. */\n bump?: number;\n /** Soft fraction (0..1) of the box's half depth at both ends. Default 0.3. */\n edge?: number;\n /** Cosine of the surface angle past which the decal fades (0.3 ≈ 72°); 0 = project onto\n * anything. Default 0.3. */\n angleFade?: number;\n /** HDR boost of the image (0 = none). */\n emissive?: number;\n};\n/** `Material.particles` options — the default point-sprite material for particle systems. */\nexport type ParticlesMaterialOptions = {\n /** Sprite texture — a single image or a flipbook sheet of frames. Unset = soft round dot. */\n map?: Texture | null;\n /** Flipbook grid: `N` = an N×N sheet, `[cols, rows]` = a non-square one. Frames run\n * left-to-right, top-to-bottom; drive the index via `particles.frame`. Default 1. */\n sheet?: number | [number, number];\n /** Extra brightness multiplier for a glow look (0 = off). */\n emissive?: number;\n /** (`render` quad / stretch) a second sheet on the same grid, ADDED as `emissiveMap × emissiveColor`\n * — keyed by `map`'s alpha, not tinted by the particle colour. A fireball = a smoke `map` whose\n * colour curve goes dark + a fire `emissiveMap` that keeps glowing while alpha lasts. */\n emissiveMap?: Texture | null;\n /** Multiplier for `emissiveMap`; an `[r, g, b]` array may exceed 1 (HDR glow). Default 0 (off). */\n emissiveColor?: ColorInput;\n /** (`render` quad / stretch) crossfade each flipbook frame into the next by the fractional frame\n * index instead of snapping — smooth sheet playback at any frame rate. Default false. */\n frameBlend?: boolean;\n /** Compositing: `\"alpha\"` (default — smoke, dust) or `\"add\"` (fire, sparks, magic). */\n blend?: \"alpha\" | \"add\";\n /** Soft radial falloff toward the sprite edge. Defaults to true without a map, false with one. */\n soft?: boolean;\n /** Soft particles: fade each sprite out over this many metres as it cuts into the scene geometry\n * behind it (Unity's \"Soft Particles Factor\"), so smoke and dust no longer slice through the\n * ground and walls with a hard edge. 0 = off (default). Reads the scene's depth buffer, which the\n * engine keeps bound while any soft system is on screen — the extra depth pass is only paid then.\n * Filament hosts (desktop / web / Android / Apple); web-lite draws such sprites unfaded. */\n depthFade?: number;\n /** How each particle is drawn: `'point'` (default — GPU point sprites, cheapest), `'quad'`\n * (real camera-facing quads — no driver size cap, geometric rotation), or `'stretch'`\n * (quads stretched along velocity — sparks, rain, speed streaks). `'ribbon'` is what `Trail`\n * uses internally. */\n render?: \"point\" | \"quad\" | \"stretch\" | \"ribbon\";\n /** (`render: 'stretch'`) extra sprite length in world units per unit of speed:\n * length = size + stretch·|velocity|. Default 0.05. */\n stretch?: number;\n};\n/** `Material.lit` options — PBR scalars on top of the color/map pair. */\nexport type LitMaterialOptions = MaterialColorOptions & MaterialStateOptions & {\n /** Perceptual roughness, 0 (mirror) … 1 (matte). Unset = the shader's default. */\n roughness?: number;\n /** Metallic factor, 0 (dielectric) … 1 (metal). Unset = the shader's default. */\n metallic?: number;\n};\nexport declare class Material {\n readonly shader: FetchResponse | \"unknown\";\n readonly uniforms: Record<string, UniformValue>;\n private _colorKey;\n constructor(shader: FetchResponse | Handle | number);\n /** Set a uniform (chainable). */\n set(key: string, value: UniformValue): this;\n set color(c: ColorInput);\n /** Depth test against the scene (write-only; see `MaterialDepthOptions`). A host that predates\n * the call leaves the material as the shader has it. */\n set depthTest(on: boolean);\n /** Depth write (write-only; see `MaterialStateOptions`). */\n set depthWrite(on: boolean);\n /** Both faces drawn (write-only; see `MaterialStateOptions`). */\n set doubleSided(on: boolean);\n /** The stencil test / write (write-only; `null` = back to none). See `MaterialStencil`. */\n set stencil(s: MaterialStencil | null);\n set map(value: Texture | Canvas | null);\n /** The material an instance handle is of; a host that carries none under `name` is an error naming it. */\n private static _builtin;\n /** PBR lit material. */\n static lit(options?: LitMaterialOptions): Material;\n /** Unlit (flat) material — opaque unless `transparent` asks for alpha blending. */\n static unlit(options?: UnlitMaterialOptions): Material;\n /** Default particle material — camera-facing point sprites with tint/opacity/rotation/flipbook\n * driven by the particle curves. Uniforms all default to 0 on a fresh instance, so every look\n * knob is primed here; JS writes after construction override them. */\n static particles(options?: ParticlesMaterialOptions): Material;\n /** Projected-decal material (`DecalSet`): samples the atlas where the decal's box meets the opaque\n * scene behind it. Blended, no depth write, no shadows — the engine keeps the scene depth bound\n * while a set with live decals is on screen. */\n static decal(options?: DecalMaterialOptions): Material;\n /** Material that samples a VideoPlayer's texture. */\n static video(map?: Texture): Material;\n /** The lightmap material (engines/bake): a lit PBR material whose whole DIFFUSE light is the\n * baked irradiance atlas on UV1 (`lightmapLight`, lux) — the real-time sun, lamps and diffuse IBL do not\n * touch it; the specular IBL stays, occluded by the baked sky visibility. Models take it through\n * `Model.load(…, { lightmap: true })`; a static Mesh gets one from here. Parameters use gltfio's names\n * (`baseColorFactor`, `baseColorMap`, `roughnessFactor`, `metallicFactor`) plus `lightmapLight`, `lightmapAux`,\n * `lightmapST`, `lightScale` (the level-wide value `Lightmap.load` sets) and the debug view knobs. */\n static lightmap(): Material;\n /** `Material.lightmap()`'s masked twin (`blending: masked`, same shader and parameters): what the engine\n * gives a lightmapped model's alpha-MASK materials. The cutoff comes from the glTF material. */\n static lightmapMasked(): Material;\n /** THE LIGHTMAP SHADER TIER, engine-wide: `\"full\"` = the target's own blob (desktop: the bicubic atlas fetch, eight\n * probe corners, the sun's highlight on metal), `\"lite\"` = the blob the phones ship (bilinear fetch, one probe\n * corner, no sun highlight; the movers' shadows on the statics stay) — on an integrated GPU some 30 % less per\n * pixel on a baked level, the picture a phone shows. Read when a lightmap material is FIRST made, which\n * `Model.load({ lightmap })` does once per world: set it BEFORE the level loads (a graphics preset applied at\n * boot, like `Texture.maxSize`); a change afterwards takes the next level. A host without the lite material\n * (a phone: its own blob is that shader already) takes the full one. */\n static lightmapShading: \"full\" | \"lite\";\n /** The lite tier's instance, or — said once — that this host has none and the full shader is used. */\n private static _liteTier;\n private static _liteWarned;\n /** The terrain splat material (docs/terrain-plan.md §1.5): four albedo (+ normal-map) layers blended by\n * a control map on the terrain's own grid, per-layer `tiling` (metres per repeat) / `roughness` /\n * `normalScale` / `triplanar`. `Terrain` builds and owns one per terrain; the uniforms are primed here so an\n * unset layer is white. Lit real-time; a BAKED terrain takes `Material.terrainLightmap()`. */\n static terrain(): Material;\n /** `Material.terrain()` for a BAKED terrain (terrain-lightmap.mat): the same layers and uniforms, shaded like\n * `Material.lightmap()` — the whole diffuse light is the baked atlas on the terrain's UV1 (one rect), which\n * `Lightmap.load` binds. A scene file's `terrain:` node that is a lightmap static is built with it; without a\n * bound bake it draws black, like any lightmapped static. No reflection probes (the sampler budget): it reflects the\n * sky through the baked sky visibility. */\n static terrainLightmap(): Material;\n private static _lmTemplate;\n private static _lmMaskedTemplate;\n /** The FOLIAGE tier (`Model.load(…, { foliage: true })`, see `Foliage`): an unlit shader with its own cheap\n * lighting plus a vertex shader that sways in the wind, bends away from benders and thins out with distance,\n * and a per-copy tint. glTF parameters like `Material.lightmap()` plus `wind` / `sway` / `fade` / `benders`,\n * which the engine writes itself. Not baked by the rewritten bake yet. */\n static foliage(): Material;\n /** `Material.foliage()`'s masked twin (`blending: masked`): what the engine gives a foliage model's alpha-MASK\n * materials — the cards. */\n static foliageMasked(): Material;\n /** the glTF-side identity values every provider-handed material starts from */\n private static _glbDefaults;\n private static _lightmapDefaults;\n private static _folTemplate;\n static _foliageMaskedTemplate(): Material | null;\n private static _folMaskedTemplate;\n private static _glbTemplate;\n /** Shadow-catcher material (transparent except where shadows fall). */\n static shadow(color?: ColorInput): Material;\n /** Load a custom compiled shader (.mat URL) as a material. */\n static load(url: string): Promise<Material>;\n}\nexport {};\n","types/gl/Mesh.d.ts":"import { type Vec3Like } from \"../math/vec\";\nimport { Geometry, type CapsuleOptions, type CylinderOptions, type PlaneOptions, type SphereOptions } from \"./Geometry\";\nimport { Material } from \"./Material\";\nimport { Node } from \"./Node\";\n/** Common transform/render options every primitive factory accepts. */\nexport type MeshOptions = {\n material?: Material;\n position?: Vec3Like;\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n name?: string;\n castShadows?: boolean;\n receiveShadows?: boolean;\n /** Coarse draw order, 0 (first) … 7 (last); default 4. See `Mesh.renderPriority`. */\n renderPriority?: number;\n};\nexport declare class Mesh extends Node {\n private _geometry?;\n constructor(geometry?: Geometry, material?: Material);\n get geometry(): Geometry | undefined;\n /** Replace the geometry in place — the node, its transform and its material stay, the vertex and\n * index buffers are rebuilt. What an editor overlay or a debug drawer redraws with. */\n setGeometry(geometry: Geometry): this;\n private _renderPriority?;\n private _culling?;\n private _castShadows?;\n private _receiveShadows?;\n /** A Mesh always carries a material (slot 0) — see Node.setMaterial for the slot API. */\n get material(): Material;\n set material(m: Material);\n set culling(v: boolean);\n /** Coarse draw order within the frame: 0 draws first, 7 last, 4 is the default (Filament's\n * renderable priority; within one priority opaque draws sort front-to-back, blended back-to-front).\n * Something drawn over the scene with `Material.depthTest = false` goes in 7, so nothing drawn\n * after it can cover it. Write-only; a host that predates the call ignores it. */\n set renderPriority(v: number);\n private static _warnedPriority;\n set castShadows(v: boolean);\n set receiveShadows(v: boolean);\n static box(options?: MeshOptions & {\n size?: Vec3Like | number;\n }): Mesh;\n static sphere(options?: MeshOptions & SphereOptions): Mesh;\n static cylinder(options?: MeshOptions & CylinderOptions): Mesh;\n /** A capsule along Y (`radius`, `length` between the cap centres) — a character's or a collider's shape in one mesh. */\n static capsule(options?: MeshOptions & CapsuleOptions): Mesh;\n static plane(options?: MeshOptions & PlaneOptions): Mesh;\n /** Wrap a custom Geometry. */\n static from(geometry: Geometry, options?: MeshOptions): Mesh;\n}\n","types/gl/Model.d.ts":"import { type FetchResponse } from \"../runtime/fetch\";\nimport { Node } from \"./Node\";\nimport { Animator, type LodMode } from \"./animation/Animator\";\n/** One polygon under a screen point — what `Model.pickTriangle` returns. `bones` are the vertex's raw\n * JOINTS_0 / WEIGHTS_0 pairs (weight > 0; empty = unweighted), `bind` its position in mesh space,\n * `world` its skinned position this frame. */\nexport interface TrianglePick {\n /** the Model's root entity, and the mesh node's own entity (0 when the host has no entity for it) */\n entity: number;\n node: number;\n nodeName: string;\n mesh: string;\n primitive: number;\n material: string;\n /** the node's lightmap group (scene-file extras), when it has one */\n lightmapGroup?: number;\n /** triangle index within the primitive (index-buffer order), and whether the ray came from behind */\n triangle: number;\n backface: boolean;\n distance: number;\n point: [number, number, number];\n bary: [number, number, number];\n /** the lightmap uv (TEXCOORD_1) at the hit, when the primitive carries one */\n uv1?: [number, number];\n skin: string;\n vertices: {\n index: number;\n bind: [number, number, number];\n world: [number, number, number];\n bones: {\n name: string;\n weight: number;\n }[];\n }[];\n}\nexport declare class Model extends Node {\n /** The model's Animator — always present, its clip table = the GLB's embedded clips. Configure\n * more (external clips, blend spaces, layers) with `model.aspect(Animator, {...})`. */\n readonly anim: Animator;\n constructor(internalId: number | Handle);\n /** Does this model cast a real-time shadow? Unlike Mesh (one renderable) a GLB is a whole\n * hierarchy, so the flag goes to EVERY renderable of the instance. A first-person viewmodel —\n * arms, weapon, attachments — sets it false: it lives in front of the camera and its shadow\n * is never wanted. */\n get castShadows(): boolean;\n set castShadows(v: boolean);\n /** Is this model lit by other casters' shadows? Same instance-wide reach as castShadows. */\n get receiveShadows(): boolean;\n set receiveShadows(v: boolean);\n /** Frustum culling for the whole instance: a model the camera cannot see skips the draw and the\n * shadow pass. ON by default where the host keeps a skinned mesh's bounds honest — the engine refits\n * them to the joints every frame, so a walking, kneeling or ragdolled body is never culled while on\n * screen (`_creator.skinnedCullingSupported`); OFF (always draw) on hosts without that, where\n * Filament would cull an animated body by its bind-pose box. `false` = always draw (a skybox-sized\n * mesh, a debugging aid); `true` forces it on regardless of the host. */\n get culling(): boolean;\n set culling(v: boolean);\n /** Level of detail (docs/lod-plan.md). `'auto'` (default): the engine shows the `_LOD<n>` mesh level\n * that fits the model's size on screen (`lecodes assets doctor --lod` makes them) and scales the\n * animation rate with it; a number 0–3 pins that level for both — `0` = always full detail (a hero,\n * a showcase), `2`/`3` = always cheap (a crowd filler). `model.anim.lod = 'full'` keeps the animation\n * exact while the mesh still switches. No-op on hosts without the LOD pass. */\n get lod(): LodMode;\n set lod(v: LodMode);\n private static _cullDefault;\n /** DEBUG: the closest polygon of this model under a screen point (logical px — `Input.mouse.position`,\n * a touch event's clientX/Y), tested against the CPU-skinned CURRENT pose, both faces. Names the\n * triangle, its three vertices (bind + skinned positions) and their raw bone weights, so a stretched\n * or misbound polygon can be traced to its binding. One full CPU skin of the model per call: click-rate\n * only. null = miss, or a host without the pick (desktop today). */\n pickTriangle(screenX: number, screenY: number): TrianglePick | null;\n /** Duplicate this model — a deep copy of the GLB (meshes, skeleton, animation clips), attached to\n * the same parent and scene and sharing this model's current transform. The clone has its own\n * independent animation state (reach it via clone.anim). Mirrors this model's culling flag. */\n clone(): Model;\n /** Load a GLB model. Returns its root as a Model; play its baked clips via model.anim. */\n static load(source: string | FetchResponse, options?: {\n /** Frustum culling — see `culling` (default: on where the host refits skinned bounds, else off). */\n culling?: boolean;\n onProgress?: (p: {\n loaded: number;\n total?: number;\n }) => void;\n /** Baked lighting (engines/bake). `true` = a STATIC: loads through the lightmap material so\n * `Lightmap.load` can bind its atlas rect (the GLB needs TEXCOORD_1 — `lecodes assets doctor\n * --lightmap-uv`) and takes nothing from the real-time lights once the bake applies. Omitted / `false` =\n * the standard shader, lit real-time (movers). Hosts without lightmap support ignore it. */\n lightmap?: boolean;\n /** Vegetation: load through the FOLIAGE tier (see `Foliage`) — wind, touch bending, distance fade,\n * per-copy tint. Hosts without the tier fall back to the standard shader. */\n foliage?: boolean;\n }): Promise<Model>;\n}\n","types/gl/nav/NavAgent.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { NavCrowd } from \"./NavMesh\";\nimport type { Node } from \"../Node\";\nexport type NavAgentState = \"idle\" | \"moving\" | \"arrived\" | \"blocked\" | \"offmesh\";\nexport type NavAgentAvoidance = \"off\" | \"low\" | \"medium\" | \"high\";\nexport type NavAgentDrive = \"position\" | \"controller\";\nexport type NavAgentEvents = {\n /** Reached the target (within `stopDistance`). */\n arrive: () => void;\n /** The target cannot be reached — the agent stopped at the closest point (or nowhere near). */\n blocked: () => void;\n};\nexport declare class NavAgent extends Aspect<\"agent\", Node, NavAgentEvents> {\n static readonly aspect = \"agent\";\n /** The crowd advances first, then every agent applies its slot. */\n static after: (typeof NavCrowd)[];\n static fields: FieldMeta<NavAgent>;\n private _radius;\n private _height;\n private _speed;\n private _acceleration;\n private _avoidance;\n private _separation;\n private _include;\n private _exclude;\n /** deg/s the node turns toward its velocity; 0 = never touch the rotation. */\n turnSpeed: number;\n /** How the node follows its slot. */\n drive: NavAgentDrive;\n /** Reached = within this many metres (along the corridor) of the target. */\n stopDistance: number;\n /** Agent radius (metres). Defaults to the navmesh's. */\n get radius(): number;\n set radius(v: number);\n get height(): number;\n set height(v: number);\n /** Top speed (m/s). */\n get speed(): number;\n set speed(v: number);\n get acceleration(): number;\n set acceleration(v: number);\n /** Local (agent-vs-agent) avoidance quality. */\n get avoidance(): NavAgentAvoidance;\n set avoidance(v: NavAgentAvoidance);\n /** Separation force weight (0 = none). */\n get separation(): number;\n set separation(v: number);\n /** Area names this agent may walk (default: all). */\n get include(): string[] | undefined;\n set include(v: string[] | undefined);\n /** Area names this agent never enters. */\n get exclude(): string[] | undefined;\n set exclude(v: string[] | undefined);\n state: NavAgentState;\n /** The current velocity after avoidance (m/s). */\n readonly velocity: Vec3;\n /** The velocity the corridor asked for, before avoidance. */\n readonly desiredVelocity: Vec3;\n /** Metres left along the corridor (-1 = no target). */\n remainingDistance: number;\n /** Where the agent is going, or null. */\n get target(): Vec3 | null;\n get hasPath(): boolean;\n private _crowd;\n private _slot;\n private _target;\n /** velocity-driven (`move`) rather than target-driven */\n private _steering;\n private _dirty;\n private _faceX;\n private _faceZ;\n private _retryAt;\n private _lastSeen;\n private _still;\n private _near;\n private _slow;\n onAttach(): void;\n onReconfigure(): void;\n onDetach(): void;\n /** Walk to a point. False = no walkable polygon near it (or no navmesh) — the current target stays. */\n goTo(target: Vec3Like): boolean;\n /** Drop the target and decelerate to a stop. */\n stop(): void;\n /**\n * Steer by velocity instead of a target — a player on WASD, a scripted push: the crowd keeps\n * the node on the mesh and avoids the other agents, no path and no arrival. Call it every fixed\n * step (the last velocity holds until the next call); `move(0, 0)` stops. Cancels `goTo`.\n * False = no navmesh / off the mesh.\n */\n move(vx: number, vz: number): boolean;\n /** Teleport (a spawn, a respawn). The target, if any, is kept. */\n warp(p: Vec3Like): void;\n private params;\n updateFixed(dt: number): void;\n private finish;\n private face;\n}\n","types/gl/nav/NavMesh.d.ts":"import { System } from \"../../core/Aspect\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\nimport type { Scene } from \"../Scene\";\nexport declare const NAV_AGENT: {\n readonly RADIUS: 0;\n readonly HEIGHT: 1;\n readonly MAX_SPEED: 2;\n readonly MAX_ACCELERATION: 3;\n readonly COLLISION_QUERY_RANGE: 4;\n readonly PATH_OPTIMIZATION_RANGE: 5;\n readonly SEPARATION_WEIGHT: 6;\n readonly AVOIDANCE: 7;\n readonly INCLUDE_FLAGS: 8;\n readonly EXCLUDE_FLAGS: 9;\n readonly ANTICIPATE_TURNS: 10;\n readonly OPTIMIZE_VIS: 11;\n readonly OPTIMIZE_TOPO: 12;\n readonly COUNT: 13;\n};\nexport declare const NAV_READ: {\n readonly POS_X: 0;\n readonly POS_Y: 1;\n readonly POS_Z: 2;\n readonly VEL_X: 3;\n readonly VEL_Y: 4;\n readonly VEL_Z: 5;\n readonly DVEL_X: 6;\n readonly DVEL_Y: 7;\n readonly DVEL_Z: 8;\n readonly STATE: 9;\n readonly TARGET_STATE: 10;\n readonly REMAINING: 11;\n readonly PARTIAL: 12;\n readonly STRIDE: 13;\n};\n/** The agent size a navmesh is built for (and the crowd's defaults). */\nexport type NavAgentSize = {\n /** metres — polygons are eroded by it. Default 0.4 */\n radius?: number;\n /** metres. Default 1.8 */\n height?: number;\n /** the highest step walked over, metres. Default 0.4 */\n climb?: number;\n /** the steepest walkable slope, degrees. Default 50 */\n slope?: number;\n};\nexport type NavMeshLoadOptions = {\n /** `asset('./assets/nav/<scene>.navmesh')` — what `lecodes navmesh bake` writes. */\n data: string;\n /** The agent size the bake uses (the file records it; the crowd reads it back). */\n agent?: NavAgentSize;\n /** Named areas → traversal cost (1 = plain ground). Ids are assigned in this order (1..15); the\n * bake stores the names, queries and agents refer to them (`include` / `exclude`, `cost`). */\n areas?: Record<string, number>;\n};\n/** The file header `lecodes navmesh bake` wrote. */\nexport type NavMeshInfo = {\n version: number;\n agent: {\n radius: number;\n height: number;\n climb: number;\n slope: number;\n };\n cell: number;\n cellHeight: number;\n tileSize: number;\n bounds: [[number, number, number], [number, number, number]];\n stats: {\n tiles: number;\n polys: number;\n verts: number;\n triangles: number;\n volumes: number;\n links: number;\n };\n meta: {\n scene?: string;\n areas?: Record<string, number>;\n costs?: Record<string, number>;\n [k: string]: unknown;\n } | null;\n};\n/** A straight path: the corners to walk, plus whether it stops short of the target. */\nexport type NavPath = Vec3[] & {\n partial: boolean;\n};\nexport type NavQueryOptions = {\n /** Only these areas (names). Default: every area. */\n include?: string[];\n /** Never these areas (names). */\n exclude?: string[];\n /** Search half-extents around each endpoint (how far off the mesh a point may be). Default [2, 4, 2]. */\n extents?: Vec3Like;\n};\nexport type NavRaycastHit = {\n hit: boolean;\n point: Vec3;\n normal: Vec3;\n};\n/** The crowd behind a scene's agents — a system `NavMesh.load` attaches to the scene so the whole\n * crowd advances once per fixed step, BEFORE every `NavAgent` applies its slot (`static after`). */\nexport declare class NavCrowd extends System<\"navCrowd\"> {\n static readonly aspect = \"navCrowd\";\n updateFixed(dt: number): void;\n onDetach(): void;\n}\nexport declare class NavMesh {\n /** True while `lecodes navmesh bake` runs the app — skip menus and build the level straight away. */\n static get baking(): boolean;\n /** The navmesh agents bind to (the last one loaded; one per world at a time). */\n static active: NavMesh | null;\n private static byScene;\n private static overrides;\n private static warned;\n private static baked;\n /** Leave a static body out of the bake (`nav: false` in a scene file). */\n static exclude(node: Node): void;\n /** A static body nobody may walk on (`nav: 'unwalkable'`): its footprint is cut out. */\n static unwalkable(node: Node): void;\n /** A static body's surface belongs to a named area (`navArea: 'road'`; names from `load`'s `areas`). */\n static area(node: Node, name: string): void;\n /** Forget every override (a scene rebuild). */\n static clear(): void;\n static of(scene: Scene): NavMesh | null;\n /** Load the level's navmesh — or, under `lecodes navmesh bake`, dump the collision geometry for\n * it. Resolves null when nothing was loaded (no bake yet, a host without navigation, bake mode). */\n static load(scene: Scene, opts: NavMeshLoadOptions): Promise<NavMesh | null>;\n readonly scene: Scene;\n readonly info: NavMeshInfo;\n /** The agent size the mesh was built for. */\n readonly agent: {\n radius: number;\n height: number;\n climb: number;\n slope: number;\n };\n /** Named areas → ids (from the bake; `load`'s `areas` when the file has none). */\n readonly areas: Record<string, number>;\n private _debug;\n private _seed;\n private _disposed;\n private constructor();\n private static areaIds;\n /** The include/exclude flag mask for a list of area names (undefined = every area). */\n flags(names?: string[]): number;\n private masks;\n /** Traversal cost of a named area (1 = plain ground; > 1 = avoided when a cheaper way exists). */\n cost(area: string, cost: number): void;\n /** The straight (string-pulled) path from → to. Empty when an endpoint is off the mesh;\n * `.partial` when the target is unreachable (the path ends at the closest polygon). */\n findPath(from: Vec3Like, to: Vec3Like, opts?: NavQueryOptions & {\n maxCorners?: number;\n }): NavPath;\n /** The closest point on the mesh (within `extents` of `p`), or null. */\n nearest(p: Vec3Like, opts?: NavQueryOptions): Vec3 | null;\n /** Can an agent walk straight from → to? `hit` = a wall in between (at `point`, facing `normal`). */\n raycast(from: Vec3Like, to: Vec3Like, opts?: NavQueryOptions): NavRaycastHit;\n /** A random reachable point — within walking distance `radius` of `center`, or anywhere on the\n * mesh. Deterministic: the sequence depends only on the calls made (a seeded generator). */\n randomPoint(center?: Vec3Like, radius?: number, opts?: NavQueryOptions): Vec3 | null;\n /** Draw the polygon mesh (a flat unlit surface 3 cm above the walkable area). */\n get debug(): boolean;\n set debug(on: boolean);\n /** Release the host handles (a scene teardown). Agents fall back to inert. */\n dispose(): void;\n private static bake;\n}\n","types/gl/Node.d.ts":"import { AspectHost } from \"../core/Aspect\";\nimport { Vec3, type Vec3Like } from \"../math/vec\";\nimport { Quat, type QuatLike } from \"../math/quat\";\nimport { Mat4, type Mat4Like } from \"../math/mat4\";\nimport type { Geometry } from \"./Geometry\";\nimport { Material } from \"./Material\";\nimport type { CompAxis, CompWriter } from \"../core/compWrite\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport type { Animation } from \"../animate/tween/Animation\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\n/** Animatable transform props of a 3D node: a value tweens from the current one, an ARRAY OF\n * VALUES is a keyframe list (`position: [[0,0,0], [0,2,0]]`). */\nexport type NodeTweenProps = {\n position?: Vec3Like | Vec3Like[];\n scale?: number | Vec3Like | (number | Vec3Like)[];\n quaternion?: QuatLike | QuatLike[];\n /** Degrees, YXZ; interpolated per axis without shortest-arc, so `[0, 720, 0]` spins twice. */\n eulerAngles?: Vec3Like | Vec3Like[];\n};\nexport type NodeEvents = {\n click: (ev: ClickEvent<Node | null>) => void;\n touchstart: (ev: TouchStartEvent<Node | null>) => void;\n /** AR anchors only (`scene.root` / `scene.createAnchor()`): the anchor began tracking. */\n track: () => void;\n /** AR anchors only: the anchor lost tracking. */\n untrack: () => void;\n /** A physics contact/trigger overlap began (the other body's node). Needs a Shape + Physics/Trigger. */\n enter: (other: Node) => void;\n /** A physics contact/trigger overlap ended. */\n exit: (other: Node) => void;\n};\nexport declare class Node extends AspectHost<NodeEvents> implements CompWriter {\n /** Native entity id. */\n get id(): number;\n /** AR anchors only — whether the anchor is currently being tracked. Kept in step with the\n * 'track' / 'untrack' events; `false` for any non-anchor node. */\n isTracked: boolean;\n private _matrix?;\n private _worldMatrix?;\n private _boneCache?;\n /** Materials assigned through setMaterial, by primitive slot (a Mesh fills slot 0 itself). */\n protected _materials?: Material[];\n constructor(internalId?: number | Handle);\n /** Geometry, if this node is a Mesh (used by physics auto-shape). Overridden by Mesh. */\n get geometry(): Geometry | undefined;\n get name(): string;\n set name(value: string);\n get visible(): boolean;\n set visible(value: boolean);\n private _sync;\n get matrix(): Mat4;\n set matrix(m: Mat4Like);\n get worldMatrix(): Mat4;\n set worldMatrix(m: Mat4Like);\n private _setOwnedPosition;\n private _setOwnedRotation;\n get position(): Vec3;\n set position(v: Vec3Like);\n get x(): number;\n set x(v: number);\n get y(): number;\n set y(v: number);\n get z(): number;\n set z(v: number);\n _writeComp(_prop: string, axis: CompAxis, v: number): void;\n get scale(): Vec3;\n set scale(v: Vec3Like | number);\n get quaternion(): Quat;\n set quaternion(v: QuatLike);\n /** Tween the transform to the given values — `node.animateTo({ position: [0, 2, 0], duration: 800,\n * easing: 'inOutCubic' })`; arrays of values are keyframes. Runs on the game clock (pauses with\n * the game) unless `clock: 'ui'`. Returns the {@link Animation} handle. Phase 1: plain nodes —\n * a physics-owned node (a body / character) is not routed through its engine object yet. */\n animateTo(props: NodeTweenProps & TweenMeta): Animation;\n /** Tween FROM the given values to the node's current transform (an entrance). */\n animateFrom(props: NodeTweenProps & TweenMeta): Animation;\n get eulerAngles(): Vec3;\n set eulerAngles(v: Vec3Like);\n get forward(): Vec3;\n get worldPosition(): Vec3;\n get worldScale(): Vec3;\n get worldQuaternion(): Quat;\n get worldEulerAngles(): Vec3;\n get parent(): Node | null;\n get children(): Node[];\n get childCount(): number;\n getChild(index: number): Node | null;\n /** Parent the given nodes under this one. */\n add(...children: Node[]): this;\n setParent(parent: Node | null, worldPositionStays?: boolean): this;\n traverse(callback: (node: Node) => void): void;\n /** The material assigned to slot 0 through this API (null before one is set — a GLB part's own\n * glTF material stays native-side). */\n get material(): Material | null;\n set material(m: Material);\n /** Replace the material of one primitive slot (`index` = the primitive's order in the glTF\n * mesh; a primitive-shape Mesh has one slot). */\n setMaterial(material: Material, index?: number): this;\n /** The material previously assigned to `index` (null when none was — see Mesh for the probe). */\n getMaterial(index?: number): Material | null;\n /** Find a descendant by name — bones of a loaded Model included (`hero.bone('RightHand').add(sword)`).\n * Same rule the Animator binds clips with: exact name first, then the part after the last `:` / `|`\n * (Mixamo `mixamorig:Hips` matches `Hips`); a skinned joint beats a plain node of the same name.\n * Cached per name; null if absent. */\n bone(name: string): Node | null;\n /** Orient the node so the given axis (default \"-z\", \"forward\") points at a world point. */\n lookAt(point: Vec3Like, mode?: \"z\" | \"-z\" | \"x\" | \"-x\" | \"y\" | \"-y\", ortho?: Vec3Like): this;\n addEventListener<K extends keyof NodeEvents>(channel: K, callback: NodeEvents[K]): void;\n /** Destroy this node and its whole subtree. Every aspect in the subtree is detached first (its\n * `onDetach` runs: physics bodies released, updaters unregistered, listeners dropped) — native\n * `destroyEntity` frees the entity tree but knows nothing about JS-side aspects, and a destroyed\n * node's `update()` must not keep ticking. Deepest nodes go first, then this one. */\n destroy(): void;\n}\n","types/gl/Noise.d.ts":"export declare class Noise {\n private readonly _id;\n constructor();\n /** Sample 2D noise. */\n get(x: number, y: number): number;\n /** Sample 3D noise. */\n get3d(x: number, y: number, z: number): number;\n private _frequency;\n get frequency(): number;\n set frequency(v: number);\n private _octaves;\n get octaves(): number;\n set octaves(v: number);\n private _fractalLacunarity;\n get fractalLacunarity(): number;\n set fractalLacunarity(v: number);\n private _fractalGain;\n get fractalGain(): number;\n set fractalGain(v: number);\n}\n","types/gl/Particles.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Vec3Like } from \"../math/vec\";\nimport type { Geometry } from \"./Geometry\";\nimport { Material, type ParticlesMaterialOptions } from \"./Material\";\nimport { Node } from \"./Node\";\ntype Range<T> = T | {\n min: T;\n max: T;\n};\nexport declare class CurveBuilder {\n private _kind;\n private _lo;\n private _hi;\n private _stops;\n constructor(base: Range<number>, mode: \"multiply\" | \"add\");\n /** Curve value at birth (t = 0). Must come before any other stop. */\n from(v: Range<number>): this;\n /** Curve value at `t` (0..1 of the particle's life). Stops must be added in ascending t order. */\n via(t: number, v: Range<number>): this;\n /** Curve value at death (t = 1). */\n to(v: Range<number>): this;\n /** The classic opacity envelope: rise over the first `fadeIn`, fall over the last `fadeOut`. */\n fade(fadeIn?: number, fadeOut?: number): this;\n /** The PARAM_CURVE record payload (sans slot): [kind, baseLo, baseHi, n, (t, lo, hi)×n]. */\n get _data(): Float32Array;\n}\nexport declare class ColorCurveBuilder {\n private _lo;\n private _hi;\n private _stops;\n constructor(base: Range<ColorInput>);\n /** Curve color at birth (t = 0). Must come first. The curve multiplies the base color. */\n from(c: Range<ColorInput>): this;\n /** Curve color at `t` (0..1 of the particle's life), in ascending t order. */\n via(t: number, c: Range<ColorInput>): this;\n /** Curve color at death (t = 1). */\n to(c: Range<ColorInput>): this;\n /** The COLOR_CURVE record payload: [baseLo rgba, baseHi rgba, n, (t, lo rgba, hi rgba)×n]. */\n get _data(): Float32Array;\n}\n/** A value curve over each particle's lifetime. Default mode `multiply` (the curve scales the\n * base); `add` offsets it instead. */\nexport declare const curve: (base?: Range<number>, mode?: \"multiply\" | \"add\") => CurveBuilder;\n/** A color curve over each particle's lifetime — always multiplies the base color. */\nexport declare const colorCurve: (base?: Range<ColorInput>) => ColorCurveBuilder;\nexport type ParticleValue = Range<number> | CurveBuilder | {\n _data: Float32Array;\n};\nexport type ParticleColor = ColorInput | {\n min: ColorInput;\n max: ColorInput;\n} | ColorCurveBuilder | {\n _data: Float32Array;\n};\ntype VelocityValue = {\n speed?: Range<number>;\n /** Cone half-angle in radians — jitter the launch direction uniformly within it. */\n spread?: number;\n /** Asymmetric jitter: two angles (u, v — the x/y components) in radians. */\n randomizeAngle?: {\n min: Vec3Like;\n max: Vec3Like;\n };\n} & ({\n from: Vec3Like;\n} | {\n to: Vec3Like;\n} | {\n dir: Vec3Like;\n} | {});\n/** Where particles are born, in emitter space. Sphere / hemisphere / cone have an axis of +Y (the\n * hemisphere is the +Y half, the cone opens along +Y from its base disc at `center`) — aim the\n * node with `lookAt(target, 'y')`. `thickness` 0 emits from the surface only, 1 (default) from the\n * whole volume. A sphere or cone also sets the LAUNCH DIRECTION (outward / from the cone's apex)\n * when `startVelocity` gives a speed but no direction, like Unity's shapes. */\ntype Shape = {\n type: \"point\";\n v: Vec3Like;\n} | {\n type: \"box\";\n min: Vec3Like;\n max: Vec3Like;\n} | {\n type: \"circle\";\n center: Vec3Like;\n radius: number;\n} | {\n type: \"sphere\";\n center?: Vec3Like;\n radius: number;\n thickness?: number;\n} | {\n type: \"hemisphere\";\n center?: Vec3Like;\n radius: number;\n thickness?: number;\n} | {\n type: \"cone\";\n center?: Vec3Like;\n radius: number; /** half-angle, radians */\n angle?: number; /** emit this far up the axis too */\n length?: number;\n thickness?: number;\n};\n/** Extra velocity over each particle's life — evaluated from the curves every frame and ADDED as a\n * displacement (not accumulated like `acceleration`): `radial` pushes outward along the particle's\n * birth direction (a burst that decays: `curve(4).to(0)`), `x`/`y`/`z` drift in the simulation\n * space (rising smoke: `y: curve(2).from(0).to(1)`). Unity's velocityOverLifetime. */\nexport type VelocityOverLife = {\n radial?: ParticleValue;\n x?: ParticleValue;\n y?: ParticleValue;\n z?: ParticleValue;\n};\ntype Noise = {\n strength?: number;\n frequency?: number;\n speed?: number;\n /** How much of the displacement a particle earns with AGE (default 0 = all of it from birth).\n * The field is sampled by position, so at 0 every particle born at the same spot is pushed the\n * same way and a plume's root wanders off its emitter by up to `strength` metres; at 1 a particle\n * is born exactly where the emitter put it and drifts into the field over its life — what you\n * want whenever the source is visible (an exhaust pipe, a contact patch, a muzzle). */\n ramp?: number;\n};\n/** Ground plane for bouncing particles (all render modes). `height` is in the simulation space:\n * world y with `space: 'world'`, emitter-local y otherwise. */\nexport type ParticleGround = {\n /** Plane height (default 0). */\n height?: number;\n /** Contact radius — particles stop `radius` above the plane (a mesh's half-extent; default 0). */\n radius?: number;\n /** Fraction of the vertical speed kept on impact, 0..1 (default 0.3). */\n bounce?: number;\n /** Tangential damping while in contact, per second — like `drag` (default 8). */\n friction?: number;\n};\nexport type ParticlesOptions = ParticlesMaterialOptions & {\n /** Draw every particle as this mesh — lit, tumbling 3D debris (shell casings, rubble, leaves,\n * shrapnel) in one draw call. The system switches to the mesh render mode; the default\n * material becomes `Material.lit()` (pass `material` for color/roughness/metallic — the\n * sprite look options are ignored). `size` scales the mesh (default 1); `rotation`/`opacity`/\n * `frame` don't apply. See `angularVelocity` and `ground`. */\n mesh?: Geometry;\n /** (mesh) Spin, radians per second about the particle's own axes — a vector, or a per-component\n * `{ min, max }` range randomized at spawn. Particles are born in the emitter's orientation. */\n angularVelocity?: Vec3Like | {\n min: Vec3Like;\n max: Vec3Like;\n };\n /** A ground plane the particles bounce on and come to rest on (any render mode); `null`\n * disables it. */\n ground?: ParticleGround | null;\n /** Custom draw material. Unset = the default point-sprite material, configured by the\n * `ParticlesMaterialOptions` sugar (map/sheet/emissive/blend/soft) — which is ignored\n * when an explicit material is passed. */\n material?: Material;\n /** Particle pool capacity (default 1000). */\n maxParticles?: number;\n /** Particles emitted per second. */\n rate?: number;\n /** Simulation space. `'local'` (default) — particles ride the node's transform; `'world'` —\n * each particle stays where it was born as the emitter moves on (trails: drift smoke, mud,\n * wake). Switching at runtime resets live particles. */\n space?: \"local\" | \"world\";\n /** Fraction (usually 0..1) of the emitter's own velocity added to each particle at spawn —\n * smoke \"thrown\" off a moving car. Takes effect with `space: 'world'`. */\n inheritVelocity?: number;\n /** Particles emitted per world unit the emitter MOVES, on top of `rate`, with spawn points\n * spread evenly along the path — trail density independent of speed, no per-frame clumps.\n * Meant for `space: 'world'`. */\n rateOverDistance?: number;\n /** Spread those spawn points along a CURVE through the emitter's recent path instead of the\n * straight line between where it was last frame and where it is now. A straight line cuts the\n * corner by however far the path bows inside one frame, which grows with the frame TIME — so a\n * fast curving emitter looks faceted, and looks worse the slower the machine. Default false\n * (the straight line); costs three stored positions and one curve evaluation per spawn.\n *\n * The curve needs a point one frame AHEAD, so each frame's spawns are placed provisionally and\n * nudged into place on the next frame, once it exists. Nothing else observes them in between. */\n smooth?: boolean;\n /** Draw order among blended systems at the same depth — higher draws later, i.e. on top (Unity's\n * sortingOrder). Systems are depth-sorted by their node, so the emitters of one effect tie and\n * without this the engine picks who covers whom per frame (smoke popping over a fireball).\n * Default 0; a fireball wants 2, its smoke 1, a smoke trail -1. */\n order?: number;\n /** Sprites take the light of the PLACE each one is in — the level's baked light grid (`env.lightmap.volume`).\n * A sprite is unlit: its colour is the picture, which is right for fire and wrong for dust — a puff kicked up\n * under an awning glows as if it stood in the sun. With `lit` every particle's colour is multiplied by the light\n * where it is, relative to the level's OPEN ground: exactly the authored colour out in the sun, the ambient's\n * share of it (tinted the way the shade is) under a roof — per particle, so a trail of puffs laid from the sun\n * into the shade is lit along its length. Author the colour for the open; nothing else to tune. Without a grid\n * — a level with no bake, a host that has none — the colours are drawn as authored. Points, quads, stretch and\n * `Trail`; mesh particles are lit by their material. Default false. */\n lit?: boolean;\n /** Coarse draw order among ALL blended draws, 0 (first) … 7 (last) — see `Mesh.renderPriority`.\n * Default 5: meshes sit at 4 and decals at 3, so smoke covers a car's glass and its skid marks\n * whatever the camera does (the engine's depth sort compares object centres, and an emitter's\n * centre says nothing about where its cloud is). `order` breaks ties inside one priority. */\n renderPriority?: number;\n shape?: Shape;\n /** Extra velocity over life (radial burst that decays, axis drift) — see `VelocityOverLife`. */\n velocityOverLife?: VelocityOverLife;\n startVelocity?: Vec3Like | VelocityValue;\n /** Downward acceleration, world units/s² — positive pulls particles DOWN (sugar for\n * `acceleration: [0, -g, 0]`). */\n gravity?: number;\n /** Constant acceleration vector (gravity, wind, …). Wins over `gravity` when both are set. */\n acceleration?: Vec3Like;\n drag?: number;\n lifetime?: Range<number>;\n color?: ParticleColor;\n /** World-unit diameter (alias of custom[0]). Default 1. */\n size?: ParticleValue;\n /** Radians (alias of custom[1]). */\n rotation?: ParticleValue;\n /** Per-particle opacity 0..1 (alias of custom[2]). Default 1. */\n opacity?: ParticleValue;\n /** Flipbook frame index (alias of custom[3]). With `sheet` set and no explicit frame, the\n * default is one full sheet cycle over each particle's lifetime, starting at `startFrame`. */\n frame?: ParticleValue;\n /** Where the default flipbook cycle begins: `'random'` (default — desynchronized loops like\n * fire/smoke) or a frame index (`0` plays the sheet in order — explosions, one-shot bursts).\n * Only shapes the default; an explicit `frame` wins. */\n startFrame?: number | \"random\";\n noise?: Noise | null;\n /** Fixed random seed for deterministic tests. */\n seed?: number;\n};\nexport declare class Particles extends Node {\n private _material;\n /** Custom curve-param slots (0..3); size/rotation/opacity/frame alias slots 0-3. */\n readonly custom: ParticleValue[];\n constructor(options?: ParticlesOptions);\n /** Emit `count` particles immediately (a burst). */\n spawn(count: number): this;\n private _send;\n set rate(val: number);\n /** `'world'` leaves particles behind where they were born (trails). Switching resets live ones. */\n set space(val: \"local\" | \"world\");\n set inheritVelocity(val: number);\n set rateOverDistance(val: number);\n /** Lay a frame's spawns along a curve through the emitter's path, not the straight chord. */\n set smooth(val: boolean);\n set order(val: number);\n /** Colours × the baked light where each particle is — see `ParticlesOptions.lit`. */\n set lit(val: boolean);\n /** Coarse draw order, 0 … 7 — see `Mesh.renderPriority`. Write-only. */\n set renderPriority(v: number);\n set velocityOverLife(v: VelocityOverLife);\n set shape(shape: Shape);\n /** (mesh mode) Replace the particle mesh; live particles keep flying as the new shape. */\n set mesh(g: Geometry);\n set angularVelocity(v: Vec3Like | {\n min: Vec3Like;\n max: Vec3Like;\n });\n set ground(g: ParticleGround | null);\n set startVelocity(val: Vec3Like | VelocityValue);\n /** Positive pulls particles down — sugar for `acceleration = [0, -g, 0]`. */\n set gravity(val: number);\n set acceleration(a: Vec3Like);\n set drag(val: number);\n set seed(val: number);\n set lifetime(val: Range<number>);\n set size(val: ParticleValue);\n set rotation(val: ParticleValue);\n set opacity(val: ParticleValue);\n set frame(val: ParticleValue);\n set color(value: ParticleColor);\n get material(): Material;\n set material(material: Material);\n set noise(noise: Noise | null);\n}\n/** `Trail` options. The look options (map/sheet/emissive/blend/soft) come from\n * `ParticlesMaterialOptions`, same as `Particles`. */\nexport type TrailOptions = Omit<ParticlesMaterialOptions, \"render\" | \"stretch\"> & {\n /** Seconds each trail point lives — the trail's length in time. Default 0.5. */\n time?: number;\n /** Strip width in world units; a curve tapers it over each point's life (head → tail).\n * Default 0.1. */\n width?: ParticleValue;\n /** Minimum emitter movement (world units) between recorded points. Default 0.05. */\n minDistance?: number;\n /** Point capacity (default 128). A spawn that does not fit is DROPPED, so a fast emitter at a\n * small `minDistance` wants headroom: a sword tip covers metres inside one `time` window. */\n maxPoints?: number;\n /** Follow a CURVE through the emitter's recent path instead of the straight line between frames.\n * A trail is where this shows most — the strip is the path — and it shows worse the lower the\n * frame rate, since a longer frame bows further off its own chord. Default false; see\n * `ParticlesOptions.smooth`. */\n smooth?: boolean;\n /** The strip takes the baked light of the place each of its points is at — `ParticlesOptions.lit`. Smoke and\n * dust trails; leave it off for a glowing one. Default false. */\n lit?: boolean;\n /** Which way the strip's WIDTH points.\n *\n * `'camera'` (default) rolls the strip about its own length to stay flat to the viewer — it can\n * never disappear, which is why it is the default, but it bears no relation to the thing that drew\n * it. An AXIS (`'x'`/`'y'`/`'z'`) uses that axis of the emitter's own transform, as it was when\n * each point was laid: on a node riding a sword's blade, `'z'` (the blade) makes the strip the\n * surface the blade actually swept, and `width` stops being a made-up number — it is the blade. */\n orient?: \"camera\" | \"x\" | \"y\" | \"z\";\n /** With `orient` on an axis: the floor under the strip's APPARENT width, 0..1 of its real width,\n * below which it rolls back toward the camera. An honestly oriented strip goes edge-on — and\n * vanishes — whenever the swing happens in the plane of view; this is the hybrid that keeps it\n * readable. 0 = never roll (honest, and it will vanish), 1 = always (the same as `'camera'`).\n * Default 0.4: a sweep still reads as a sweep, and a swing toward the camera still shows. */\n faceCamera?: number;\n color?: ParticleColor;\n /** Opacity along the trail. Defaults to fading the tail out (`curve().to(0)`). */\n opacity?: ParticleValue;\n};\n/** A ribbon strip that follows this node through the world — sword swings, skid marks, missile\n * trails. Attach it to (or under) the moving node and just move; points are laid down per\n * `minDistance` of movement, live for `time` seconds, and the strip stays glued to the node at\n * its head. Width/opacity/color accept the same curves as `Particles`, evaluated over each\n * point's life — i.e. along the trail from head (fresh) to tail (dying). */\nexport declare class Trail extends Node {\n private _material;\n private _rateDistance;\n private _orient;\n private _faceCamera;\n constructor(options?: TrailOptions);\n private _send;\n /** Trail length in seconds — how long each laid-down point lives. */\n set time(val: number);\n set width(val: ParticleValue);\n set opacity(val: ParticleValue);\n set color(value: ParticleColor);\n set minDistance(val: number);\n /** Follow a curve through the emitter's path instead of the straight chord between frames. */\n set smooth(val: boolean);\n set lit(val: boolean);\n /** Which way the strip's width points — see `TrailOptions.orient`. Keeps the current `faceCamera`. */\n set orient(val: \"camera\" | \"x\" | \"y\" | \"z\");\n /** The hybrid's floor — see `TrailOptions.faceCamera`. */\n set faceCamera(val: number);\n /** Pause/resume laying down points — existing ones still age out, so the trail fades naturally\n * after e.g. a sword swing ends. */\n set emitting(val: boolean);\n get material(): Material;\n}\nexport {};\n","types/gl/physics/CharacterController.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec2Like, type Vec3Like } from \"../../math/vec\";\nimport type { CompWriter } from \"../../core/compWrite\";\nimport type { Node } from \"../Node\";\n/** Where the character's feet are, as reported by the solver after the last step. */\nexport type GroundState = \"ground\" | \"slope\" | \"unsupported\" | \"air\";\nexport declare class CharacterController extends Aspect<\"controller\", Node> implements CompWriter {\n static readonly aspect = \"controller\";\n static fields: FieldMeta<CharacterController>;\n private _charId;\n private _gravityScale;\n private _maxSlope;\n onAttach(): void;\n onDetach(): void;\n /** Native character id (0 until attached / no physics support). */\n get id(): number;\n /**\n * This frame's movement command, in world units/s — NOT normalized, NOT a per-frame displacement\n * (that is what Unity's `Move` takes; passing `v * dt` here gives a character 60× too slow).\n *\n * Two components = horizontal `(x, z)`, the everyday call. Three = the whole velocity, for free mode\n * (`gravityScale = 0`); with gravity on, the vertical component fights the ballistic one and the\n * character barely falls, so that combination warns.\n *\n * Sticky only within the frame: the command expires once the engine consumes it. It also **takes the\n * axis back from a latched `velocity`** — commanding is claiming ownership, which is what keeps the\n * two horizontal sources from ever fighting.\n */\n move(x: number, z: number): void;\n move(v: Vec2Like | Vec3Like): void;\n /** Vertical velocity (world units/s) — LATCHED: gravity works on it, you seed it. `= 7` to jump,\n * `+= 3` to stack an explosion on top of the current motion. No ground check: guard it yourself\n * with `grounded` (or don't, for a double jump). Overridden every frame by a 3-component `move()`.\n * `velocity.y = 7` is the same channel — pick whichever reads better. */\n get velocityY(): number;\n set velocityY(v: number);\n /** Multiplier over the world gravity (`Physics.configure({ gravity })`); default 2, for the snappier\n * fall games want. **0 = free mode**: no gravity, no stick-to-floor, no stair stepping — a swimmer\n * or a drone, driven by the 3-component `move()`. */\n get gravityScale(): number;\n set gravityScale(v: number);\n /** Max ground slope (degrees) the character treats as walkable; default 45. Live. */\n get maxSlope(): number;\n set maxSlope(v: number);\n /**\n * True while a requested collider resize hasn't taken — you asked to stand up and there is something\n * overhead. Resizing goes through the `Shape` aspect itself:\n *\n * hero.aspect(Shape, { capsule: CROUCHED }) // always fits — you are shrinking\n * hero.aspect(Shape, { capsule: STANDING }) // may be refused under a low ceiling\n * if (hero.controller.resizing) … // still crouched; call it again next frame\n *\n * A refusal changes nothing, so the retry is just the same call again — and it is an exact headroom\n * test against the real capsule, unlike a hand-rolled raycast (a ray is a line; a capsule has girth).\n * The FEET stay planted across a resize, so the character neither hovers nor sinks.\n */\n get resizing(): boolean;\n /** True while standing on walkable ground. */\n get grounded(): boolean;\n /** Where the feet are after the last step: on walkable ground, on too-steep ground, touching\n * something that can't support it, or in the air. */\n get groundState(): GroundState;\n /**\n * READ — the velocity the solver ended up with after the most recent step (world units/s, fresh\n * Vec3): what HAPPENED, not what you asked for. Walking into a wall reads ~0, sliding along one\n * reads the tangent. Unlike Unity's synchronous `Move`, our step runs later in the frame, so a read\n * is up to one frame old — irrelevant for animation speed, fall damage or \"am I blocked\", which is\n * what it is for. (Exact wall contact would need a contact normal; the engine has none yet.)\n *\n * WRITE — LATCH the whole velocity: a knockback, a wall jump, a launch pad. Unlike `move()` it does\n * not expire, so the character keeps flying, and gravity still pulls the vertical down into a real\n * ballistic arc. It stays until `move()` takes the axis back — so a game simply doesn't call\n * `move()` while the throw lasts, and ends it on its own terms:\n *\n * hero.controller.velocity = [dir.x * 12, 6, dir.z * 12] // hit by the blast\n * // …in the loop:\n * if (thrown) { if (hero.controller.grounded) thrown = false } // landing ends it\n * else hero.controller.move(ix * SPEED, iz * SPEED) // …and this reclaims the axis\n *\n * Note nothing clears the latch by itself, landing included — so a thrown character that never gets\n * a `move()` keeps sliding along the ground (a kinematic controller has no friction).\n *\n * Reading is not the inverse of writing: `c.velocity = c.velocity` is NOT a no-op, because the read\n * reports the measured result (against a wall it is ~0 and would cancel the throw). In flight the\n * two agree closely, so read-modify-write mid-air behaves as expected.\n *\n * `c.velocity.y = 7` (the direct spelling) is a jump — the compiler routes it to the exact\n * `velocityY` channel via `_writeComp` below, no vector allocated — and `c.velocity.x = 3` latches\n * the whole vector with the measured velocity filling in the other two, i.e. the read-modify-write\n * above spelled naturally. A STORED copy is still a copy: `const v = c.velocity; v.y = 7` does nothing.\n */\n get velocity(): Vec3;\n set velocity(v: Vec3Like);\n /** Compile-time list (chisel reads it, then strips it): the getters whose `c.<getter>.<axis> = v`\n * spelling is routed to `_writeComp` below. See core/compWrite.ts. */\n static _comps: string[];\n}\n","types/gl/physics/Physics.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport type { CompAxis, CompWriter } from \"../../core/compWrite\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { type Node } from \"../Node\";\nexport type MotionType = \"static\" | \"dynamic\" | \"kinematic\";\nexport interface PhysicsConfig {\n /** Gravity in world units/s² (Y-up: down is negative). Default [0, -9.81, 0]. */\n gravity?: Vec3Like;\n /** Max simultaneous bodies (resizes the world; only before any body exists). Default 4096. */\n maxBodies?: number;\n}\n/** Closest raycast hit. */\nexport interface RayHit {\n node: Node | null;\n point: Vec3;\n normal: Vec3;\n fraction: number;\n}\n/**\n * What a body's friction already is the moment the host creates it. This is part of the ABI, not an\n * assumption: bridges.d.ts states it, so every host owes us this value. Knowing it lets attach skip\n * a bridge call per body whenever nobody named a surface.\n */\nexport declare const DEFAULT_FRICTION = 0.6;\nexport declare class Physics extends Aspect<\"physics\", Node> implements CompWriter {\n static readonly aspect = \"physics\";\n /** Render interpolation of body transforms between the fixed 60 Hz steps (global; default on). Turn\n * off to save per-frame transform writes when you have many moving bodies / don't need >60 Hz\n * smoothness — bodies then advance in discrete steps. */\n private static _interpolation;\n static get interpolation(): boolean;\n static set interpolation(on: boolean);\n /** Default \"dynamic\". */\n motion: MotionType;\n /** Mass in kg for dynamic bodies (default 1). Ignored for static/kinematic. */\n mass: number;\n /**\n * Surface friction: 0 = ice, ~1 = grippy asphalt, and values above 1 are allowed (rubber on\n * tarmac).\n *\n * The engine COMBINES the two touching bodies as `sqrt(a * b)`, so the LOWER value dominates and\n * the floor caps everything standing on it. The default **0.6** is a neutral solid surface (the\n * raw Jolt default of 0.2 is ice by game standards); dry tarmac a car should corner on wants a\n * `1`, ice `0.02`. A Vehicle's tires read the GROUND body's value, so this is the single number\n * that decides how well a car corners.\n *\n * Change it at runtime by re-configuring — `floor.aspect(Physics, { friction: 0.02 })` (an ice\n * patch) — or by assigning `floor.physics.friction = 0.02`; either way the setter pushes the new\n * surface to the live body at once. (chisel keeps an instance setter whose name appears as an\n * object-literal key anywhere in the bundle, so the config-object route survives tree-shaking\n * even when no code reads `.friction`.)\n */\n get friction(): number;\n set friction(v: number);\n private _friction;\n /** Scene-editor inspector: `motion` as a dropdown (a string default alone infers a text box). */\n static fields: FieldMeta<Physics>;\n private _bodyId;\n private static _refusedWarned;\n onAttach(): void;\n onDetach(): void;\n /** Native Jolt body id. 0 until attached, or if the build has no physics support. */\n get id(): number;\n /** Linear velocity in world units/second (fresh Vec3 on read; `velocity.y = 5` written directly on\n * the aspect is compiled to a component write — see `_writeComp`). */\n get velocity(): Vec3;\n set velocity(v: Vec3Like);\n /**\n * Angular velocity — **degrees/second about each world axis** (the SDK's angle unit everywhere;\n * the engine works in radians and converts here). Fresh Vec3 on read.\n *\n * This is the only handle on a body's spin, and placing an object usually needs it: a `position`\n * write is a pure teleport, so a crate that was tumbling keeps tumbling at its new home. Putting\n * something down is `body.velocity = [0,0,0]; body.angularVelocity = [0,0,0]; node.position = p`.\n */\n get angularVelocity(): Vec3;\n set angularVelocity(v: Vec3Like);\n _writeComp(prop: string, axis: CompAxis, v: number): void;\n /** Apply an instantaneous impulse (kg·m/s) and wake the body. */\n applyImpulse(v: Vec3Like): this;\n /** The same impulse applied at a WORLD-SPACE point instead of the centre of mass: the lever arm\n * becomes angular impulse, so the body spins as well as moves (a bullet hitting a crate off\n * centre, a blast lifting it by its base). Falls back to the central impulse on an older host. */\n applyImpulseAt(v: Vec3Like, point: Vec3Like): this;\n /** Configure gravity / limits. Call once before creating bodies. */\n static configure(config?: PhysicsConfig): void;\n /** Whether this build has physics support (CREATOR_GL_PHYSICS). */\n static get supported(): boolean;\n /** Closest pickable body hit by the ray from `origin` along `dir` (up to `maxDist`), or null. */\n static raycast(origin: Vec3Like, dir: Vec3Like, maxDist?: number): RayHit | null;\n}\n","types/gl/physics/physicsEvents.d.ts":"export declare const ensurePhysicsEvents: () => void;\n","types/gl/physics/Ragdoll.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport { Node } from \"../Node\";\nexport interface RagdollHinge {\n /** The hinge axis in the MODEL's space (its rest pose: +Z forward, +Y up, +X the model's left in\n * glTF). Perpendicular to the bone; the engine drops any component along it. */\n axis: Vec3Like;\n /** The bend range about `axis` in degrees, relative to the pose the ragdoll was built in — a knee\n * is `{ axis: [1, 0, 0], min: 0, max: 140 }`: it folds one way only. */\n min: number;\n max: number;\n}\nexport interface RagdollPart {\n /** The bone the body sits on — its origin is the joint. */\n bone: string;\n /** The bone the capsule points at (the next joint down). Omitted = a leaf: `length` along the line\n * from the parent part's origin (a head, a hand, a foot without toes). */\n to?: string;\n /** The bone of the part this one hangs from (default: the previous part in the list). The root\n * has none. */\n parent?: string;\n /** Capsule radius in metres (default 0.05). */\n radius?: number;\n /** Length in metres: a leaf's, or an override of the distance to `to`. */\n length?: number;\n /** This part's share of the ragdoll's `mass` (relative weight, default 1). */\n mass?: number;\n /** Cone half-angle in degrees the part may swing off its parent (default 30). Ignored with `hinge`. */\n swing?: number;\n /** Twist half-angle in degrees about its own axis (default 20). */\n twist?: number;\n /** A one-way joint instead of the cone. */\n hinge?: RagdollHinge;\n}\n/** How the body lies: on its back (the chest points up), prone (the chest points down), or on a side. */\nexport type RagdollFacing = \"up\" | \"down\" | \"side\";\nexport interface RagdollActivateOptions {\n /** A LAUNCH added to every part's own motion (world m/s) — an explosion, a throw. The bones' own\n * motion (the run, the swinging arms) is measured by the engine and needs no help. */\n velocity?: Vec3Like;\n /** The motors' strength from the first step (default: the current `strength`). */\n strength?: number;\n /** The root anchored to the animation from the first step (default: the current `anchored`). */\n anchored?: boolean;\n}\nexport interface RagdollDeactivateOptions {\n /** Seconds the animator takes to transition OUT of the fallen pose into whatever plays next (a\n * get-up take started right after, or the loop). 0 (default) = a cut. Move the model node under\n * the hips before this call: the bones are handed back against its new transform. */\n blend?: number;\n}\nexport interface RagdollHitOptions {\n /** How long the body stays powered before the bones go back to the animator (s, default 0.6). */\n duration?: number;\n /** The transition out of the reaction's last physical pose (s, default 0.25). */\n blend?: number;\n /** The motors' strength during the reaction (default 1). */\n strength?: number;\n}\nexport declare class Ragdoll extends Aspect<\"ragdoll\", Node> {\n static readonly aspect = \"ragdoll\";\n /** The parts: `'humanoid'` (default) finds the standard bones by name; a list places bodies on any\n * bones — parents before children. */\n parts: RagdollPart[] | \"humanoid\";\n /** Total mass in kg (default 70), split between the parts by their `mass` shares. */\n mass: number;\n /** Friction of every part (default 0.6 — the physics default). */\n friction: number;\n /** Linear / angular damping of every part; 0 = Jolt's own 0.05. More angular damping settles a\n * flailing body sooner. */\n linearDamping: number;\n angularDamping: number;\n /** What the parts collide with. `'static'` (default): the static geometry and other such ragdolls\n * only — dynamic bodies, character controllers and vehicles pass through a fallen body, which then\n * never shoves or blocks anything and costs nothing when they meet. `'all'`: a regular dynamic\n * body that bumps into everything (and gets kicked awake by everything). */\n collide: \"static\" | \"all\";\n /** Once every part of a LIMP body has come to rest the parts turn static where they lie (default\n * true): the pose holds, nothing can wake a settled body and it costs the solver nothing —\n * `deactivate()` / `activate()` still work (activate makes it dynamic again). A driven or anchored\n * body never freezes. */\n freeze: boolean;\n /** Seconds limp after which the body freezes whatever it is doing — a twitch on a slope or a pile\n * never sleeps on its own. 0 (default) = no cap. */\n freezeAfter: number;\n /** The joint motors: the position spring's frequency in Hz (default 6 — higher = a stiffer, quicker\n * return to the animated pose) and damping ratio (default 1 = critical, no overshoot). */\n driveFrequency: number;\n driveDamping: number;\n /** The motors' torque limit at strength 1, in N·m per kg of the part (default 12: ~180 N·m at the\n * hips of an 80 kg body, ~25 at a forearm). Lower = a hit displaces a limb more before the\n * animation wins it back. */\n driveTorque: number;\n /** Joint friction in N·m per kg of the part (default 0.3): a torque that resists any joint motion,\n * motor or not — a limp body folds instead of flopping like jelly. */\n jointFriction: number;\n /** Where the joint limits come from. `'clips'` (default): measured from the animation — at the first\n * activation that finds clips on the model's animator, every joint's swing and twist range over\n * every bound clip becomes its limit (plus `limitsMargin` on each side), so the motors never\n * target a pose the limits forbid and a limp body settles into poses the clips use; until clips\n * are bound the part table's cones apply. `'table'`: the part table's cones and hinges only. */\n limits: \"clips\" | \"table\";\n /** Degrees added on each side of a learned range (default 10). */\n limitsMargin: number;\n static fields: FieldMeta<Ragdoll>;\n private _id;\n private _active;\n private _bones;\n private _strength;\n private _anchored;\n private _hipsFwd;\n private _hipsUp;\n private _ramp;\n private _release;\n onAttach(): void;\n onDetach(): void;\n /** Hand the bones to physics from the pose they are in right now, each moving as it did over the\n * last two frames (the engine measures: a runner keeps travelling, a swinging arm keeps swinging). */\n activate(opts?: RagdollActivateOptions): boolean;\n /** Take the bones back: the animator's pose shows again from the next frame — through a `blend`\n * out of the fallen pose when asked (play the get-up take right after, with its own fade: it\n * starts from where the body lies). */\n deactivate(opts?: RagdollDeactivateOptions): void;\n /** Physics owns the bones right now. */\n get active(): boolean;\n /** Active and every part asleep (or frozen) — the body has come to rest. */\n get settled(): boolean;\n /** The joint motors' strength, 0..1: how hard every joint is pulled toward the pose the animator\n * shows (0 = off — a limp body). Kept across activations. */\n get strength(): number;\n set strength(v: number);\n /** The hips follow the animation kinematically (the body stands in its clip while physics moves the\n * limbs — hit reactions, a stagger). Off = the hips are a free body (a fall). */\n get anchored(): boolean;\n set anchored(v: boolean);\n /** The joints give way: the strength ramps to 0 over `seconds` and the anchor comes off — a body\n * shot mid-stride keeps its pose for a moment and then collapses, instead of switching off. */\n goLimp(seconds?: number): void;\n /** A flinch: the body powers up anchored to its animation (if it is not already active), the struck\n * part gets the impulse (N·s, at a world point), and after `duration` the bones go back to the\n * animator through `blend`. On a limp body (a corpse) it is just the impulse. */\n hit(bone: string, v: Vec3Like, at?: Vec3Like, opts?: RagdollHitOptions): boolean;\n /** The root part's bone (the hips): where the body is. */\n get root(): Node | null;\n /** How the body lies: `'up'` on its back (the chest points up), `'down'` prone, `'side'` otherwise.\n * Read while it is down, to pick the get-up take. */\n get facing(): RagdollFacing;\n /** Where the head points along the ground, as a yaw in degrees (the model node's `eulerAngles` y\n * that faces that way): where a get-up take that rises head-first ends up facing. A body still\n * upright answers with the way its chest faces. */\n get heading(): number;\n /** The bones that carry a part, in order. */\n get bones(): string[];\n /** The rigid-body id of a part (0 if none) — for the plain body calls. */\n bodyOf(bone: string): number;\n /** Push one part: an impulse in N·s, at a world point (a hit) or through its centre. Wakes the body. */\n impulse(bone: string, v: Vec3Like, at?: Vec3Like): boolean;\n /** The strength ramp (goLimp) and the hit reaction's hand-back. */\n update(dt: number): void;\n}\n","types/gl/physics/Shape.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport { type Vec3Like } from \"../../math/vec\";\nimport type { Node } from \"../Node\";\n/** Which geometry a Shape uses — the one-of the fields below encode (see `_build`'s order). */\nexport type ShapeKind = \"auto\" | \"box\" | \"sphere\" | \"cylinder\" | \"capsule\" | \"mesh\" | \"convex\" | \"heightfield\";\n/** A node-local AABB, in the node's OWN frame (its own transform excluded), before world scale. */\nexport type ShapeBounds = {\n min: [number, number, number];\n max: [number, number, number];\n};\n/** Dimensions measured from a node's rendered geometry — what `Shape.fit` writes, and the numbers\n * the scene editor's \"Fit to mesh\" button puts in the file. Exactly one dimension key is set (none\n * for a mesh/convex kind, whose geometry is the mesh itself); `origin` centres it on the art. */\nexport type ShapeFit = {\n box?: [number, number, number];\n sphere?: number;\n cylinder?: {\n halfHeight: number;\n radius: number;\n };\n capsule?: {\n halfHeight: number;\n radius: number;\n };\n origin: [number, number, number];\n};\nexport declare class Shape extends Aspect<\"shape\", Node> {\n static readonly aspect = \"shape\";\n /** Box half-extents [hx, hy, hz] (world units). */\n box?: Vec3Like;\n /** Sphere radius. */\n sphere?: number;\n /** Cylinder aligned on Y: half-height + radius. */\n cylinder?: {\n halfHeight: number;\n radius: number;\n };\n /** Capsule aligned on Y: half-height of the cylinder section + radius. */\n capsule?: {\n halfHeight: number;\n radius: number;\n };\n /** The node's own triangles (a Mesh's geometry or a Model's GLB, world scale applied).\n * `true` = exact triangle mesh — static/kinematic bodies, triggers, characters' ground and picking\n * only (a dynamic body can't be a triangle mesh; Physics throws). `'convex'` = convex hull of the\n * vertices, works for dynamic bodies too. A Model uses its bind pose (skinned parts skipped). */\n mesh?: boolean | \"convex\";\n /** The node's terrain (`Terrain.create(...).node`) as a Jolt height field — the exact drawn grid,\n * holes included (docs/terrain-plan.md). Static / kinematic / picking / character ground only,\n * like `mesh: true`. `terrain.commit()` pushes edits into the live shape. */\n heightfield?: boolean;\n /**\n * The shape's centre, relative to the node's origin — world units in the node's ROTATED frame\n * (the node's scale is ignored, exactly like the explicit dimensions above). Default [0, 0, 0].\n *\n * A model's pivot is rarely its centre of volume (a character stands ON its origin, a wheel hangs\n * off its axle), so a collider centred on the pivot is half sunk into the floor. `origin` lifts it\n * without moving the node: `{ capsule: { halfHeight: 0.6, radius: 0.3 }, origin: [0, 0.9, 0] }`.\n * `fit()` and the scene editor's \"Fit to mesh\" fill it in from the rendered bounds.\n *\n * On a DYNAMIC body the offset also moves the centre of mass, so a lopsided collider tips the way\n * you would expect. With no `origin` an auto shape (`{}`) still centres itself on the node's own\n * mesh bounds — only explicit dimensions sit on the pivot by default.\n */\n origin?: Vec3Like;\n /** Whether pointer rays can hit this shape (click / touchstart). Default true. */\n raycast: boolean;\n private _shapeId;\n private _bodyId;\n /** Centre the \"auto\" box measured for itself — used when `origin` isn't set explicitly. */\n private _autoOrigin;\n /** Geometry props as of the last build (see onReconfigure). */\n private _sig;\n onAttach(): void;\n onDetach(): void;\n /** Re-configuring (`node.aspect(Shape, { origin })`) rebuilds the geometry when a dimension, the\n * kind or the origin changed, and re-applies pickability. The body keeps its id and velocity. */\n onReconfigure(): void;\n /**\n * Measure the node's rendered geometry and size the collider to it — the code half of the scene\n * editor's \"Fit to mesh\". Keeps the current kind unless one is passed; `auto` becomes an explicit\n * box, and a mesh/convex shape only has its `origin` cleared (its geometry IS the mesh).\n *\n * crate.aspect(Shape, {}).shape.fit() // box around what the model actually draws\n * hero.aspect(Shape, {}).shape.fit('capsule') // capsule of the same height + girth\n *\n * A model loads asynchronously, so fit AFTER its `load()` resolves — an empty subtree measures as\n * nothing and the call is a no-op (it warns). Rebuilds the live shape, keeping the body.\n */\n fit(kind?: ShapeKind): this;\n /** Which geometry this shape currently uses (the `_build` dispatch, as a name). */\n get kind(): ShapeKind;\n /**\n * The node's subtree AABB in its OWN local frame (its own transform excluded), or null when there\n * is nothing to measure. Reads the engine's bounds — which cover a loaded GLB and every child —\n * and falls back to a Mesh node's own CPU geometry on hosts without them.\n */\n static boundsOf(node: Node): ShapeBounds | null;\n /**\n * Dimensions + origin that make `kind` hug what `node` renders — world units, so the node's world\n * scale is baked in exactly as the Shape fields expect. Null when the node has no geometry (a\n * model that hasn't loaded, an empty).\n */\n static fitTo(node: Node, kind?: ShapeKind): ShapeFit | null;\n /**\n * The measuring itself, over plain numbers: a node-local AABB + the node's world scale in, shape\n * dimensions out. Separate from `fitTo` so the scene-editor harness can measure a node from\n * ANOTHER bundle without touching accessors the bundler may have shaken out of it.\n *\n * A sphere takes the LARGEST half-extent and a cylinder/capsule the larger of X/Z, so the fit\n * reads as the object's silhouette rather than as an enclosing ball; adjust from there.\n */\n static fitBounds(bounds: ShapeBounds, scale: Vec3Like, kind?: ShapeKind): ShapeFit;\n private _createPickBody;\n private _rebuild;\n private _build;\n private _applyOrigin;\n private _signature;\n private _buildHeightField;\n private _buildMesh;\n private _buildAutoBox;\n}\n","types/gl/physics/Trigger.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { Node } from \"../Node\";\nexport declare class Trigger extends Aspect<\"trigger\", Node> {\n static readonly aspect = \"trigger\";\n private _bodyId;\n /** Native body id (0 if no physics support). */\n get id(): number;\n onAttach(): void;\n onDetach(): void;\n}\n","types/gl/Plane.d.ts":"import { Vec3, type Vec3Like } from \"../math/vec\";\nimport type { Ray } from \"./Ray\";\nexport declare class Plane {\n /** Unit normal. */\n readonly normal: Vec3;\n /** Scalar offset: dot(normal, point). */\n readonly d: number;\n constructor(normal: Vec3Like, point: Vec3Like);\n static fromPoints(a: Vec3Like, b: Vec3Like, c: Vec3Like): Plane;\n static fromCoefficients(a: number, b: number, c: number, d: number): Plane;\n /** Ray-plane parameter t (≥0), or null on a miss (parallel / behind origin). */\n intersectRay(ray: Ray): number | null;\n /** Like intersectRay but allows hits behind the origin (line-plane). */\n intersectLine(ray: Ray): number | null;\n /** Signed distance from a point (positive on the normal's side). */\n signedDistance(point: Vec3Like): number;\n /** Project a point onto the plane. */\n projectPoint(point: Vec3Like): Vec3;\n}\n","types/gl/Ray.d.ts":"import { Vec3, type Vec3Like } from \"../math/vec\";\nexport declare class Ray {\n readonly origin: Vec3;\n readonly dir: Vec3;\n constructor(origin: Vec3Like, dir: Vec3Like);\n /** The world-space point origin + t·dir. */\n getPoint(t: number): Vec3;\n}\n","types/gl/scenarios.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport type { FieldMeta } from \"../core/fields\";\nimport type { InspectorUI } from \"../core/InspectorUI\";\nimport { Node } from \"./Node\";\nimport { Model } from \"./Model\";\ntype LoopMode = \"once\" | \"loop\" | \"pingpong\";\n/** Travel from the node's starting position to a target node in `duration` seconds. */\nexport declare class MoveTo extends Aspect<\"moveTo\"> {\n /** Where to travel — place an Empty node and pick it. */\n target: Node | null;\n /** Seconds for the full trip. */\n duration: number;\n /** Seconds to wait before starting. */\n delay: number;\n /** once = stop at the target · loop = restart from the start point · pingpong = back and forth. */\n mode: LoopMode;\n /** Motion curve. */\n easing: \"smooth\" | \"linear\";\n static readonly aspect = \"moveTo\";\n static editor: {\n rebuild: boolean;\n };\n static fields: FieldMeta<MoveTo>;\n private _t;\n private _start;\n update(dt: number): void;\n /** Editor-only path line (edit mode; play mode never calls this). */\n rebuild(): void;\n}\n/** Travel through the children of a path node (add an Empty per waypoint) in `duration` seconds.\n * `loop` runs the circuit closed (last → first); `pingpong` goes back and forth along the open\n * path; `once` stops at the last waypoint. */\nexport declare class FollowPath extends Aspect<\"followPath\"> {\n /** A node whose CHILDREN are the waypoints, in file order. */\n path: Node | null;\n /** Seconds for one full pass of the path. */\n duration: number;\n /** Seconds to wait before starting. */\n delay: number;\n mode: LoopMode;\n /** Turn to face the direction of travel. */\n orient: boolean;\n /** Which local axis leads when orienting. */\n forward: \"-z\" | \"z\" | \"x\" | \"-x\";\n static readonly aspect = \"followPath\";\n static editor: {\n rebuild: boolean;\n };\n static fields: FieldMeta<FollowPath>;\n private _t;\n private _points;\n update(dt: number): void;\n /** Editor-only waypoint polyline (edit mode; play mode never calls this). */\n rebuild(): void;\n}\n/** Continuous rotation about one of the node's local axes, degrees per second. */\nexport declare class Spin extends Aspect<\"spin\"> {\n /** Degrees per second. */\n speed: number;\n /** Local axis to spin around. */\n axis: \"x\" | \"y\" | \"z\";\n static readonly aspect = \"spin\";\n static fields: FieldMeta<Spin>;\n update(dt: number): void;\n}\n/** Keep the node facing a target node (a turret tracking, a signpost, a camera aimed at a hero).\n * Accessor `node.facing` — NOT `lookAt`, which would shadow the `Node.lookAt()` method. */\nexport declare class LookAt extends Aspect<\"facing\"> {\n /** The node to face. */\n target: Node | null;\n /** Which local axis points at the target. */\n forward: \"-z\" | \"z\" | \"x\" | \"-x\";\n /** 0 = snap instantly; otherwise seconds of turn lag (bigger = slower, smoother). */\n smoothing: number;\n static readonly aspect = \"facing\";\n static editor: {\n rebuild: boolean;\n };\n static fields: FieldMeta<LookAt>;\n update(dt: number): void;\n /** Editor-only sight line (edit mode; play mode never calls this). */\n rebuild(): void;\n}\n/** Start a GLB animation clip when the scene runs. Attach to a `model:` node; the inspector card\n * lists the model's clips live and can preview them while editing. */\nexport declare class PlayAnimation extends Aspect<\"playAnimation\", Model> {\n /** Clip name; empty = the model's first clip. */\n clip: string;\n loop: boolean;\n /** Playback rate (1 = authored speed). */\n speed: number;\n static readonly aspect = \"playAnimation\";\n static fields: FieldMeta<PlayAnimation>;\n private _preview?;\n onAttach(): void;\n static inspector(ui: InspectorUI, a: PlayAnimation): void;\n}\nexport {};\n","types/gl/Scene.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Aspect, type AspectCtor, type FieldOf, type TargetOf } from \"../core/Aspect\";\nimport { Presentable, type DismissOptions, type PresentOptions } from \"../ui/presentable\";\nimport { type UIWidgetContent } from \"../ui/UILayer\";\nimport type { ClickEvent, TouchStartEvent } from \"../runtime/touch\";\nimport type { FetchResponse } from \"../runtime/fetch\";\nimport { Camera } from \"./Camera\";\nimport { SceneAudio } from \"./audio/SceneAudio\";\nimport { type ControlsHandle, type ControlsOptions } from \"./controls\";\nimport { Material } from \"./Material\";\nimport { Node } from \"./Node\";\nexport type AmbientOcclusionOptions = {\n /** Strength of the darkening (default 1). */\n intensity?: number;\n /** How far the occlusion reaches, in metres (default 0.3). */\n radius?: number;\n /** Falloff contrast; >1 tightens it into the crease (default 1). */\n power?: number;\n /** Sample count + filtering (default 'medium'). Not the buffer resolution — that stays half. */\n quality?: \"low\" | \"medium\" | \"high\" | \"ultra\";\n};\n/** `SceneOptions.taa` / `scene.setAntialias(\"taa\", 4, taa)`: the temporal anti-aliasing knobs. */\nexport type TaaOptions = {\n /** Render the 3D at this fraction (0.5–1) and TAA-upscale it to the viewport; 1 = none. */\n upscale?: number;\n /** The history's share, 0 (max smoothing) … 1 (none); 0.12 default. */\n feedback?: number;\n /** Post-TAA sharpen 0–1; defaults to 0.5 with `upscale` below 1, else 0. */\n sharpness?: number;\n /** A first-person viewmodel: everything closer than this many metres to the camera is treated as\n * fixed on screen — its history is read at the same pixel, not reprojected by the camera's motion,\n * which would trail the weapon on every turn (TAA has no per-object motion vectors). 1 covers arms\n * and weapon at eye height; 0 (the default) = off. A wall walked into within the band smears a little. */\n viewmodel?: number;\n};\nexport type FogOptions = {\n /** A TINT on the in-scattered ambient, not an absolute colour: the engine multiplies it by the\n * environment luminance, so white (the default) means \"fog as bright as the ambient\" and the fog\n * brightens with `environmentIntensity`. Do NOT expect the same hex to look like it does in\n * `skybox` — that one IS an absolute radiance and reads roughly an order of magnitude brighter.\n * Tint towards the sky's hue; leave it white to sit at the ambient level. */\n color?: ColorInput;\n /** Metres from the camera before the fog starts (default 0). */\n start?: number;\n /** Extinction per metre at `height`; 0.01 ≈ clearly visible over ~100 m (default 0.01). */\n density?: number;\n /** The fog's \"sea level\" in world Y (default 0). */\n height?: number;\n /** How fast it thins with altitude, 1/m. 0 = uniform everywhere; higher = a ground-hugging layer\n * you can see over (default 0). */\n heightFalloff?: number;\n /** Cap on how opaque it can get, 0–1 — keeps far shapes readable (default 1). */\n maxOpacity?: number;\n /** Metres after which fog stops applying; 0 = everywhere (default 0). */\n cutoff?: number;\n /** Take the colour from the environment in the view direction, tinted by `color`, instead of a\n * flat `color`. Convincing when the IBL is a real sky (default false). */\n fromEnvironment?: boolean;\n};\nexport type SceneOptions = {\n /** Image-based ambient lighting (default on). `false` turns it off; a STRING is the scene's own\n * probe - `ibl: asset('../assets/ibl-interior.ktx')` - and is how two levels in one project get\n * different environments. Without it the host looks for a project-wide `ibl.ktx`, which is one\n * probe for every scene: swapping that file to suit an interior level silently relights the\n * outdoor one. A named probe also travels through `asset()`, so a build only carries the\n * environments its own entry point reaches. */\n ibl?: boolean | string;\n /** IBL intensity (default 20000). */\n environmentIntensity?: number;\n /** Camera exposure compensation in stops (default 0) - the same knob as\n * `scene.camera.exposureCompensation`, next to the rest of the scene's lighting so a LEVEL can\n * carry its own. The camera is a physical one at EV100 15 (f/16 - 1/125 - ISO 100), i.e. metered\n * for bright sun; an interior lit at real levels needs +7..+9 to read at all. Expose the camera\n * rather than inflating the lights: scaling lamps past what they physically emit gives bright\n * fixtures in a black room, because it changes the RATIO, not the level. */\n exposureCompensation?: number;\n /** Bloom post-processing. */\n bloom?: boolean;\n bloomIntensity?: number;\n /** Tone mapping operator. `'aces'` (default, filament's ACES legacy) desaturates bright colours\n * towards white — HDR fire reads pale; `'neutral'` (Khronos PBR Neutral) keeps hue and\n * saturation until very bright; `'linear'` clips each channel (what an engine without a\n * tonemapper shows — saturated, Unity-without-post-processing look); `'filmic'` (Uncharted). */\n toneMapping?: \"aces\" | \"neutral\" | \"linear\" | \"filmic\";\n /** The sky. Three forms:\n * - a colour — a flat clear colour;\n * - `{ texture }` — a KTX1 **cubemap**, the sharp `<name>_skybox.ktx` that filament's `cmgen`\n * produces from an equirectangular .hdr/.exr. This is the one to use for a real sky. Pass an\n * `asset('../assets/sky.ktx')` handle or a bare staged filename;\n * - `'environment'` — reuse the scene's IBL cubemap. Cheapest (no second texture) but that file\n * is prefiltered for roughness, so the sky comes out soft; fine as a fallback, not as the goal.\n *\n * Either texture form draws through filament's own skybox pass: a full-screen pass in device\n * space after the opaque queue. No geometry, no meridian seam, no pole distortion — do NOT build\n * a sky dome or a fullscreen equirect material by hand, both are strictly worse. */\n skybox?: ColorInput | \"environment\" | {\n texture: string;\n };\n /** Screen-space ambient occlusion — the contact darkening in creases and where props meet the\n * ground. Without it an IBL lights a crease exactly as brightly as an open face, so everything\n * reads as pasted onto the floor rather than standing on it. `true` takes defaults tuned for\n * human-scale props; `radius` is world-space metres and is the one knob that must follow the\n * scene's scale (~0.3 for objects on a table, ~0.6-1 for a yard of crates and containers). */\n ambientOcclusion?: boolean | AmbientOcclusionOptions;\n /** Distance fog / aerial perspective: distant geometry loses contrast so the eye reads depth, and\n * the hard edge where a finite level ends against the skybox goes away. By default the fog applies\n * at every distance — the skybox included — so the sky itself takes the fog colour and the horizon\n * blends on its own; `cutoff` opts geometry beyond a distance back out. */\n fog?: FogOptions;\n /** Anti-aliasing: `true` = 4× MSAA, `2`/`4` = that many samples, `false` = off (FXAA takes over),\n * `\"taa\"` = temporal anti-aliasing (Filament's TAA: one full-screen history blend instead of the\n * multisampled buffers — cheaper than MSAA on an integrated GPU and it also calms specular and\n * foliage shimmer; see `taa` for its knobs). Unset keeps the host default (desktop 4×, mobile/web\n * off). The biggest single fill-rate cost after resolution — turn it down on big screens first. */\n antialias?: boolean | 2 | 4 | \"taa\";\n /** The TAA's knobs (`antialias: \"taa\"`): `upscale` = render the 3D at this fraction (0.5–1) and let\n * TAA reconstruct the full resolution — the cheap way to a lower render cost with most of the\n * detail kept (`renderScale` shrinks the buffer and stretches it instead); `feedback` = the\n * history's share, 0.12 by default (raise it toward 0.3 if fast motion ghosts); `sharpness` =\n * a post-TAA sharpen 0–1, useful with `upscale`. */\n taa?: TaaOptions;\n /** Keep a stencil buffer for this scene (off by default: it costs memory and a clear per frame).\n * Needed before any material's `stencil` test or write does anything. */\n stencil?: boolean;\n /** Render the 3D at this fraction of the viewport (0.25–1) and upscale; the UI stays at native\n * resolution. A fixed, predictable cut of per-pixel GPU work — `0.75` is ~45 % cheaper and\n * barely visible in motion, `0.5` quarters it. Headless renders ignore it. */\n renderScale?: number;\n /** Let the engine shrink the 3D buffers under `renderScale` only when frames run over budget\n * (Filament dynamic resolution, sharpened upscale) down to `min` (default 0.5). Off by default:\n * it makes the output frame-time dependent, so flow tests / headless renders never enable it. */\n dynamicResolution?: boolean | {\n min?: number;\n };\n /** Anisotropic filtering, 1 (off) … 16. Default 2. What it buys is detail on surfaces seen at a\n * GRAZING angle — a first-person weapon, a floor, a wall — where the sample footprint is far\n * longer in one axis than the other and isotropic filtering has to pick a mip for the long one,\n * several levels coarser than the short axis deserves. Measured on a weapon seen from the side\n * (local contrast): 8.18 at 1× → 10.02 at 2× → 10.84 at 4× → 11.29 at 8×. The default is 2\n * because it is where the curve is steepest per unit of memory bandwidth; raise it if you have\n * the headroom.\n *\n * It is an ENGINE-WIDE default, not a property of this scene: a sampler is baked when its\n * texture is bound, so this reaches the models a scene loads AFTER it (which is every model in a\n * scene file — `env` is applied before the nodes build) and leaves already-loaded ones alone.\n * On the desktop host `CREATOR_TEXTURE_ANISOTROPY` overrides it, for tuning without a rebuild. */\n anisotropy?: number;\n /** Engine-wide cap on texture size, 0 / unset = none (see `Texture.maxSize`): a KTX2 above it\n * loses its top mip levels on load, a glTF image is downsampled. Applied before this scene's\n * assets load; like `anisotropy` it does not touch textures already loaded. */\n maxTextureSize?: number;\n /** The look on an HDR display (a screen with headroom above SDR white — Apple XDR panels, the\n * macOS host today); ignored on SDR. `strength` 0..1 is how much of the picture reaches for the\n * display's headroom (0 only what SDR clipped, 1 nearly everything; default 0.35). `paperWhite`\n * 1..8 is where white lands as a multiple of SDR white — the \"HDR brightness\" of a console\n * calibration screen, where 1.5–2 is the norm; default 1 keeps a white wall at the UI's white,\n * faithful but dim next to what \"HDR on\" is expected to look like. Engine-wide like `anisotropy`;\n * `device.hdr` is the runtime form and tells you whether the display has any headroom at all. */\n hdr?: {\n strength?: number;\n paperWhite?: number;\n };\n};\nexport declare class Scene implements Presentable {\n readonly camera: Camera;\n /** The listener + global 3D audio knobs (docs/audio-plan.md). */\n readonly audio: SceneAudio;\n readonly _touchStartListeners: Array<(ev: TouchStartEvent<Node | null>) => void>;\n private _material?;\n private static _active;\n static get active(): Scene | null;\n constructor(options?: SceneOptions);\n /** Runtime form of `renderScale` / `dynamicResolution` (a graphics-settings menu). `renderScale`\n * 0.25–1; older hosts without the method ignore it. */\n setRenderOptions(renderScale: number, dynamicResolution?: boolean | {\n min?: number;\n }): void;\n /** Scene occlusion material: an unlit instance in the occluder blue (the built-in `unlit`, which\n * every runtime carries) — one per scene, made on first use. */\n get occlusionMaterial(): Material;\n set skybox(sky: ColorInput | \"environment\" | {\n texture: string;\n });\n /** Runtime form of `ambientOcclusion` (a graphics-settings menu). `false` turns it off. */\n setAmbientOcclusion(options: boolean | AmbientOcclusionOptions): void;\n /** Runtime form of `fog` (weather, entering a building). `false` turns it off. */\n setFog(options: FogOptions | false): void;\n setMaterialGlobalParameter(i: number, x: number, y: number, z: number, w: number): void;\n setAntialias(mode: boolean | 2 | 4 | \"taa\", scale?: number, taa?: TaaOptions): void;\n /** Depth-reading effects on / off (a graphics-settings menu): soft particles and projected decals\n * read the scene depth, which costs a depth pre-pass of every opaque draw (~12 % of a fill-bound\n * frame). Off = hard-edged particles, no decals, no pre-pass. Engine-wide, live. */\n setDepthEffects(enabled: boolean): void;\n /** LOD distance (a graphics-settings menu): the engine's LOD thresholds × `bias`. 2 = every level\n * switches at half the distance (a model must look twice as big on screen to keep its detail),\n * 0.5 = full detail twice as far, 1 = the defaults. Engine-wide, live. Only GLBs that carry\n * `_LOD<n>` meshes (`lecodes assets doctor --lod`) have levels to switch. */\n setLodBias(bias: number): void;\n /** Runtime form of `bloom` / `bloomIntensity` (a graphics-settings menu). */\n setBloom(enabled: boolean, intensity?: number): void;\n /**\n * How bright the environment (IBL) lights the scene, in lux — `SceneOptions.environmentIntensity`\n * after the fact. Live: it changes the probe's intensity, not the probe, so it costs nothing and\n * can be dragged. (`setDefaultIbl`, the call that installs a probe, rebuilds the cubemap from the\n * ktx every time — never drive a slider through a scene option that has to re-open.)\n *\n * `lecodes lightmap bake` reads the same number off the live probe, so a scene dimmed here bakes\n * dimmed. Hosts without the call keep whatever the scene opened with, and the getter still\n * reports what was asked for.\n */\n get environmentIntensity(): number;\n set environmentIntensity(lux: number);\n private static _warnedEnvIntensity;\n /** The scene's stencil buffer on / off (see `SceneOptions.stencil`). */\n setStencil(enabled: boolean): void;\n add(...list: Node[]): this;\n remove(...list: Node[]): this;\n /** Attach (and configure) a system, or reconfigure it if already present. Returns the scene typed\n * as now-having it (`scene.system(Hud).hud`). A `System<'x', Scene2D>` is rejected here. */\n system<Self extends TargetOf<A>, A extends Aspect<any, any, any>>(this: Self, ctor: AspectCtor<A>, opts?: Partial<A>): Self & FieldOf<A>;\n /** Safe access — undefined if the system isn't attached. */\n get<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): A | undefined;\n /** Existence check AND type guard: inside `if (scene.has(Hud))`, `scene.hud` is present. */\n has<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this is this & FieldOf<A>;\n /** Detach a system (runs its onDetach). Chainable. */\n removeSystem<A extends Aspect<any, any, any>>(ctor: AspectCtor<A>): this;\n /** Tear the scene down: every system detaches (last-attached first) and the scene closes. Nodes\n * are yours — destroy the ones you own; the native scene object itself is not released. */\n destroy(): void;\n createOverlay(options?: SceneOptions): Scene;\n warmRender(): Promise<void>;\n /** Precompile the scene's shader variants so nothing is compiled mid-game. Every material the host\n * knows is queued for the sun / shadow / fog / skinning variants and the dynamic-light key — the\n * first point light (a muzzle flash, an explosion) would otherwise rebuild every lit shader in view\n * on that frame. Call it once the sun and fog are set, typically under a loading screen; materials\n * loaded later are queued in the background as they are created. Resolves at once on a host\n * without the bridge. */\n precompileShaders(): Promise<void>;\n readonly cl: (() => void)[];\n _backButtonCallback?: () => void;\n private _vd?;\n /** Fires when the scene becomes the visible destination (incl. a pop revealing it). */\n onOpen(callback: () => void): this;\n /** Fires when the scene stops being visible (closed, replaced, or covered by a push). */\n onClose(callback: () => void): this;\n /** Hardware/system back while the scene is current. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n /** The UI over the scene — widgets (a HUD, a dialog), laid out over the scene while it is\n * presented; touches outside a widget's box reach the scene. `scene.setContent([hud])`. */\n setContent(content: UIWidgetContent): this;\n /** Make this the active scene — shows it as the current destination (replaces a screen /\n * another scene; only the active scene renders). The runtime activates the engine as part of\n * presenting the destination. */\n open(options?: PresentOptions): void | Promise<void>;\n close(options?: DismissOptions): void;\n addEventListener(channel: \"click\", callback: (ev: ClickEvent<Node | null>) => void): void;\n addEventListener(channel: \"touchstart\", callback: (ev: TouchStartEvent<Node | null>) => void): void;\n removeEventListener(channel: \"click\" | \"touchstart\", callback: (ev: any) => void): void;\n}\nexport type ARMode = \"default\" | \"markers\" | \"arcore\" | \"detached\";\nexport declare class ARScene<T extends ARMode = \"default\"> extends Scene {\n readonly mode: T;\n useWarmRender: boolean;\n private _root?;\n constructor(options?: SceneOptions & {\n mode?: T;\n });\n /** Root anchor node (not available in marker mode). */\n get root(): Node;\n /** Create an anchor from a tracking source (e.g. an image target). */\n createAnchor(source: FetchResponse, physicalWidth?: number): Node;\n /**\n * Let the user place & manipulate a node with touch gestures — the staple AR object-placement\n * interaction: ONE finger drags it across the floor (relative to where the camera looks), TWO fingers\n * pinch to scale and twist to rotate. Returns a handle; call `.remove()` to detach. Tunable via\n * options (min/max scale, and toggles for `pan` / `pinch` / `twist`).\n */\n addControls(target: Node, options?: ControlsOptions): ControlsHandle;\n open(options?: PresentOptions): Promise<void>;\n close(options?: DismissOptions): void;\n}\n/**\n * A 3D scene rendered in a VR headset (OpenXR — e.g. Meta Quest). The headset drives the camera:\n * every frame both eyes are rendered from the tracked head pose, so `scene.camera` position/lookAt\n * have no effect while the scene is open. The world origin is at floor level (stage space) —\n * author content with the ground at y = 0 and the user standing at the origin.\n *\n * `open()` rejects on hosts without a VR runtime (\"VR is not supported on this device\").\n */\nexport declare class VRScene extends Scene {\n open(options?: PresentOptions): Promise<void>;\n close(options?: DismissOptions): void;\n}\n","types/gl/state.d.ts":"import type { Scene } from \"./Scene\";\nexport declare const glState: {\n activeScene: Scene | null;\n};\n","types/gl/terrain/Terrain.d.ts":"import { Node } from \"../Node\";\nimport { Material } from \"../Material\";\nimport { Texture } from \"../Texture\";\nimport { Geometry } from \"../Geometry\";\nimport { type ColorInput } from \"../../core/color\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nexport type TerrainLayer = {\n /** Albedo texture (a URL / `asset()` handle, or a loaded Texture). Unset = white. Its ALPHA is the layer's roughness\n * map (`lecodes assets terrain-pack --roughness` puts it there): an opaque albedo reads 1. */\n albedo?: string | Texture;\n /** Metres per texture repeat. Default 8. */\n tiling?: number;\n /** Perceptual roughness of the layer — a factor on the albedo's alpha (its roughness map), the whole value when the\n * albedo is opaque. A terrain has no metallic: ground is a dielectric. Default 1. */\n roughness?: number;\n /** Normal-map strength (0 = the layer's slot of the pack is not read). Default 0 — set 1 when the\n * layer has a normal map in `normals`. */\n normalScale?: number;\n /** Sample this layer triplanar in world space (cliff rock): no stretching on steep slopes; its\n * normal map is then skipped. Default false. */\n triplanar?: boolean;\n};\nexport type TerrainOptions = {\n /** Samples per side (square). 257 / 513 / 1025 are the usual sizes. Default 129. */\n size?: number;\n sizeX?: number;\n sizeZ?: number;\n /** Metres between samples. Default 1. */\n cellSize?: number;\n /** Cells per chunk side (≤ 255). Default 64. */\n chunk?: number;\n /** Heights in metres: an array of sizeX × sizeZ (row-major, z rows), or a function of the sample's\n * LOCAL position in metres. Default flat 0. */\n heights?: Float32Array | ((x: number, z: number) => number);\n /** A byte per sample, 1 = hole (a triangle needs its three samples valid). */\n holes?: Uint8Array;\n /** RGBA layer weights per sample (normalised in the shader). Default: all layer 0. */\n control?: Uint8Array;\n layers?: TerrainLayer[];\n /** The two normal-map packs: `[layers 0+1, layers 2+3]` — XY of the even layer in RG, the odd in BA. */\n normals?: [string | Texture | undefined, (string | Texture)?];\n /** Multiplier on every layer's albedo. */\n tint?: ColorInput;\n name?: string;\n /** A material to use instead of `Material.terrain()` (a custom terrain shader with the same uniforms). */\n material?: Material;\n};\n/** A region of the terrain in LOCAL metres (XZ). `node` = the XZ footprint of a node's triangles. */\nexport type TerrainRegion = {\n circle: {\n x: number;\n z: number;\n r: number;\n };\n} | {\n rect: {\n x: number;\n z: number;\n w: number;\n h: number;\n };\n} | {\n polygon: readonly (readonly [number, number])[];\n} | {\n node: Node;\n};\nexport type ConformOptions = {\n /** How far below the target surface the ground sits (keeps bilinear terrain strictly under a\n * curved road between samples). Default 0.05. */\n offset?: number;\n /** Metres over which the surrounding ground blends back to its old height. Default 4; 0 = hard edge. */\n falloff?: number;\n /** `both` (default) cuts and fills; `lower` only cuts; `raise` only fills. */\n mode?: \"both\" | \"lower\" | \"raise\";\n};\nexport type RibbonOptions = {\n /** Width in metres. */\n width: number;\n /** Metres of ribbon per texture repeat along its length. Default = width. */\n uvScale?: number;\n};\n/** A brush dab for `sculpt` — LOCAL metres. */\nexport type SculptOptions = {\n x: number;\n z: number;\n /** Brush radius in metres. */\n radius: number;\n /** `raise` / `lower` by `amount` metres at full weight; `smooth` blends toward the 3×3 average\n * (`amount` 0…1 = how far); `flatten` pulls toward `target` (default: the height under the\n * centre) by `amount` 0…1. Default raise. */\n mode?: \"raise\" | \"lower\" | \"smooth\" | \"flatten\";\n amount?: number;\n /** 0…1 — the share of the radius at full weight; the rest feathers out (default 0.5). */\n hardness?: number;\n target?: number;\n};\n/** `snapshot()` — the three sample arrays, copied; `restore()` puts them back (undo, a level reset). */\nexport type TerrainSnapshot = {\n heights: Float32Array;\n holes: Uint8Array;\n control: Uint8Array;\n};\n/** A ray hit on the terrain (`raycast` local, `raycastWorld` world). */\nexport type TerrainHit = {\n point: Vec3;\n normal: Vec3;\n distance: number;\n};\nexport type AutoPaintRules = {\n /** The layer everything starts as. Default 0. */\n base?: number;\n /** Slope rule: the layer takes over between `from` and `to` degrees of slope. */\n slope?: {\n layer: number;\n from: number;\n to: number;\n };\n /** Height rule: the layer takes over between `from` and `to` metres (snow line). */\n height?: {\n layer: number;\n from: number;\n to: number;\n };\n /** Low rule: the layer takes over BELOW `to` metres, fading in from `from` (valley floors). */\n low?: {\n layer: number;\n from: number;\n to: number;\n };\n};\n/** What Shape { heightfield } reads off a terrain node (`node._terrain`). */\nexport type TerrainData = {\n sizeX: number;\n sizeZ: number;\n cellSize: number;\n heights: Float32Array;\n holes: Uint8Array | null;\n};\nexport declare class Terrain {\n /** The node the terrain hangs off: transform it to place the ground; add it to the scene. */\n readonly node: Node;\n readonly sizeX: number;\n readonly sizeZ: number;\n readonly cellSize: number;\n readonly chunk: number;\n /** sizeX × sizeZ heights in metres, row-major (z rows). Edit, then `commit()`. */\n readonly heights: Float32Array;\n /** A byte per sample, 1 = hole. */\n readonly holes: Uint8Array;\n /** RGBA layer weights per sample. */\n readonly control: Uint8Array;\n /** The splat material (`Material.terrain()` unless one was passed). */\n readonly material: Material;\n /** Resolves when every layer texture has loaded (the terrain renders white until then). */\n readonly ready: Promise<void>;\n layers: TerrainLayer[];\n private _native;\n private _chunkMeshes;\n private _controlTex;\n private _dirty;\n private _holesTouched;\n private _controlDirty;\n private _anyHole;\n private _cast;\n private _receive;\n private constructor();\n /** Build a terrain from data / a generator (synchronous; `ready` resolves once its textures loaded). */\n static create(opts?: TerrainOptions): Terrain;\n /** The terrain a node carries (the node `Terrain.create` returned), or null. */\n static of(node: Node | null | undefined): Terrain | null;\n /** Load a `.terrain` file (`Terrain.serialize` / the editor / `lecodes terrain import`); layer textures\n * are not in the file — pass them in `opts` (they are asset handles the file cannot hold). */\n static load(url: string, opts?: Omit<TerrainOptions, \"size\" | \"sizeX\" | \"sizeZ\" | \"heights\" | \"holes\" | \"control\">): Promise<Terrain>;\n private get _grid();\n /** Height at a local (x, z) on the drawn triangles; NaN in a hole or outside the grid. */\n heightAt(x: number, z: number): number;\n /** The drawn triangle's normal at a local (x, z) (unit Vec3, +Y up). */\n normalAt(x: number, z: number): Vec3;\n /** The LAYER WEIGHTS at a local (x, z) — what the splat shader blends there: the control map read bilinearly\n * between its samples and normalised to sum 1 (`[1, 0, 0, 0]` where the map is empty, as the shader has\n * it). Index = the layer's in `layers`. Outside the grid the edge answers. This is how a game asks WHAT the\n * ground is under a point — footprints in the sand and none on the cobble, a footstep sound per layer, dust\n * by surface — and the blend is already in the numbers, so a transition is a fade and not a line. */\n weightsAt(x: number, z: number): [number, number, number, number];\n /** The heaviest layer's index at a local (x, z) — `weightsAt` when only \"which one\" is asked. */\n layerAt(x: number, z: number): number;\n /** The smooth (vertex) normal at integer sample (ix, iz). */\n sampleNormal(ix: number, iz: number): Vec3;\n /** Extent in local metres: `[width, depth]`. */\n get extent(): [number, number];\n /** Min / max height over the grid. */\n get heightRange(): [number, number];\n /** A world-space point into the terrain's local frame. */\n toLocal(p: Vec3Like): Vec3;\n /** A local point into world space. */\n toWorld(p: Vec3Like): Vec3;\n /** The ground's WORLD height under a world (x, z): NaN off the grid / in a hole. */\n worldHeightAt(x: number, z: number): number;\n /** Nearest hit of a LOCAL ray on the drawn triangles (holes let it through), null on a miss.\n * Exact against what is rendered — the editor's brush and a host without physics pick with it. */\n raycast(origin: Vec3Like, dir: Vec3Like, maxDistance?: number): TerrainHit | null;\n /** `raycast` in WORLD space — through the node's transform (rotation + uniform scale). */\n raycastWorld(origin: Vec3Like, dir: Vec3Like, maxDistance?: number): TerrainHit | null;\n /** Write a rectangle of samples (`src` = w × h heights, row-major). */\n setHeights(x0: number, z0: number, w: number, h: number, src: ArrayLike<number>): this;\n /** Apply `fn(oldHeight, weight, x, z)` over a region; `weight` is 1 inside, fading to 0 over\n * `falloff` metres outside it. The building block of flatten / raise / hole. */\n shape(region: TerrainRegion, fn: (h: number, w: number, x: number, z: number) => number, falloff?: number): this;\n /** Flatten a region to `height` (a plateau / a building pad), blending over `falloff` metres. */\n flatten(region: TerrainRegion, height: number, opts?: {\n falloff?: number;\n }): this;\n /** Raise (or lower, negative) a region by `delta` metres, blending over `falloff` metres. */\n raise(region: TerrainRegion, delta: number, opts?: {\n falloff?: number;\n }): this;\n /** Copies of heights / holes / control — an undo point or a level reset. */\n snapshot(): TerrainSnapshot;\n /** Put a `snapshot()` back (same grid size) — everything marked dirty for the next `commit()`. */\n restore(s: TerrainSnapshot): this;\n /** One brush dab: raise / lower / smooth / flatten a disc of `radius` metres around (x, z), feathered\n * by `hardness` — the editor's sculpt tool and runtime deformation (craters, digging) share it. */\n sculpt(opts: SculptOptions): this;\n /** Cut a hole (no triangles, no collision, no navmesh) — or fill one back with `on = false`. */\n hole(region: TerrainRegion, on?: boolean): this;\n /**\n * Conform the ground to a mesh — the terrain takes the target's TOP surface minus `offset` under\n * its footprint (a road sits exactly on it, nothing pokes through), and blends back to the old\n * ground over `falloff` metres around it. `target` = a node (a Mesh, a Model, or a node holding\n * them — every triangle in the subtree counts), a Geometry in local coordinates, or a raw soup\n * (9 floats per triangle, local). Call again after the target moves.\n */\n conform(target: Node | Geometry | Float32Array, opts?: ConformOptions): this;\n /** `conform` to a ribbon along `points` (world/local metres, see `ribbon`) — the road stamp. */\n conformPath(points: readonly Vec3Like[], opts: ConformOptions & RibbonOptions): this;\n /**\n * A flat ribbon Geometry along a polyline (the road mesh AND the conform target): `width` metres,\n * vertices take the points' own Y, UV0 = (across 0…1, along / uvScale). Build it from heights you\n * sampled with `heightAt` and smoothed, then `Mesh.from(geometry, { material })` + `conform`.\n * It also carries a lightmap UV (uv1: along 0…1 × across 0…width/length — the strip's true aspect,\n * so `lecodes lightmap bake` gives it uniform texels), which makes the road a bake receiver.\n */\n static ribbon(points: readonly Vec3Like[], opts: RibbonOptions): Geometry;\n /** Write RGBA layer weights for a rectangle of samples (`rgba` = w × h × 4 bytes). */\n paint(x0: number, z0: number, w: number, h: number, rgba: ArrayLike<number>): this;\n /** Paint `layer` over a region with `strength` (0…1), feathered over `falloff` metres. */\n paintLayer(region: TerrainRegion, layer: number, strength?: number, falloff?: number): this;\n /** Paint the whole terrain from slope / height rules (grass on the flats, rock on cliffs, snow on\n * the peaks, dirt in the valleys) — the CPU pass a procedural level starts from. */\n paintAuto(rules?: AutoPaintRules): this;\n private _blendLayer;\n /** Push every pending edit to the engine: chunk renderables + the height-field collider for the\n * dirty rectangle, the control texture. Call once after a batch of edits. */\n commit(): this;\n set castShadows(v: boolean);\n get castShadows(): boolean;\n set receiveShadows(v: boolean);\n get receiveShadows(): boolean;\n /** The whole terrain as a `.terrain` file (LTER: heights quantised to 16 bits, holes, control). */\n serialize(): ArrayBuffer;\n /** Decode a `.terrain` file into create() options (heights back in metres). */\n static parse(buf: ArrayBuffer): {\n sizeX: number;\n sizeZ: number;\n cellSize: number;\n chunk: number;\n heights: Float32Array;\n holes: Uint8Array;\n control: Uint8Array;\n layers: TerrainLayer[];\n };\n private _build;\n private _buildFallbackChunk;\n private _rebuildFallbackChunks;\n private _applyShadows;\n private _uploadControl;\n private _applyLayers;\n /** Re-push layer scalars after editing `layers` (textures given as Texture apply too). */\n applyLayers(): Promise<void>;\n private _touch;\n private _touchControl;\n /** The sample rectangle a region (+ falloff) touches, or null when it misses the grid. */\n private _regionRect;\n /** Per-sample weights over `r`: 1 inside the region, smooth 1→0 across `falloff` metres outside. */\n private _regionWeights;\n /** World matrix of the node (column-major). */\n private _world;\n /** A target's triangles in the terrain's LOCAL frame, 9 floats per triangle. */\n private _triangles;\n}\n","types/gl/terrain/terrainMesh.d.ts":"import { Geometry } from \"../Geometry\";\nexport type TerrainGrid = {\n sizeX: number;\n sizeZ: number;\n cellSize: number;\n /** sizeX × sizeZ heights, row-major (z rows). */\n heights: Float32Array;\n /** One byte per sample, 1 = hole; null = no holes. */\n holes: Uint8Array | null;\n};\n/** The sample at integer (x, z), clamped to the grid. */\nexport declare const sampleAt: (g: TerrainGrid, x: number, z: number) => number;\nexport declare const isHole: (g: TerrainGrid, x: number, z: number) => boolean;\n/** Surface normal at a sample from central differences (one-sided at the borders). Writes `out` (xyz). */\nexport declare const normalAt: (g: TerrainGrid, x: number, z: number, out?: Float32Array | number[]) => typeof out;\n/**\n * Height at a LOCAL (x, z) in metres, interpolated on the drawn triangles (the i00–i11 diagonal), so a\n * character's feet and a raycast agree with what is rendered to the millimetre. NaN inside a hole\n * triangle or outside the grid.\n */\nexport declare const heightAt: (g: TerrainGrid, x: number, z: number) => number;\n/** The geometric normal at a LOCAL (x, z): the drawn triangle's normal (not the smoothed vertex one). */\nexport declare const faceNormalAt: (g: TerrainGrid, x: number, z: number, out?: Float32Array | number[]) => typeof out;\n/** Chunks along X and Z for a grid: a chunk covers `chunk` cells (chunk + 1 samples). */\nexport declare const chunkCounts: (g: TerrainGrid, chunk: number) => [number, number];\n/**\n * One chunk as a Geometry (positions, smooth normals, UV0 = local XZ metres, UV1 = the terrain's unit\n * square, u16 indices), or null when every cell of it is a hole.\n */\nexport declare const buildTerrainChunk: (g: TerrainGrid, cx: number, cz: number, chunk: number) => Geometry | null;\nexport type GridHit = {\n x: number;\n y: number;\n z: number;\n distance: number;\n nx: number;\n ny: number;\n nz: number;\n};\n/**\n * Nearest hit of a LOCAL ray (origin + direction, metres) on the drawn triangles — the same\n * i00–i11 split and hole rule as `heightAt`, so a pick lands on what is rendered. Walks the cells\n * the ray crosses (2D DDA on XZ), testing each cell's two triangles; holes let the ray through.\n * Null when it misses (or never enters the grid within `maxDistance`).\n */\nexport declare const gridRaycast: (g: TerrainGrid, ox: number, oy: number, oz: number, dx: number, dy: number, dz: number, maxDistance?: number) => GridHit | null;\n","types/gl/Texture.d.ts":"import { type FetchResponse, type File } from \"../runtime/fetch\";\n/** `Texture.load` options. */\nexport type TextureLoadOptions = {\n /** `true` (default): colour, stored sRGB. `false`: data (normal map, mask, heightmap) — kept linear. */\n srgb?: boolean;\n /** Ignore `Texture.maxSize` for this texture (a lightmap page, a lookup table). */\n fullSize?: boolean;\n};\nexport declare class Texture {\n static _maxSize: number;\n /** Engine-wide cap on texture size (a \"texture quality\" setting), 0 = none. A KTX2 wider or\n * taller than this loses its top mip levels on load (nothing resampled, less memory and\n * bandwidth), a glTF PNG/JPEG is downsampled. Reaches textures loaded AFTER it is set — a loaded\n * level keeps its textures — so set it up front (`SceneOptions.maxTextureSize`, or before the\n * level loads) and apply a menu change on the next level load. Lightmap pages are exempt\n * (`TextureLoadOptions.fullSize`). A host may pin it (desktop `CREATOR_TEXTURE_MAX_SIZE`). */\n static _anisotropy: number;\n /** Engine-wide anisotropic filtering, 1 (off) … 16 (default 2; `SceneOptions.anisotropy` sets it up\n * front). A sampler is baked when its texture is bound, so like `maxSize` this reaches textures\n * loaded AFTER it — set it before the level loads. Measured on a lightmapped interior at 720p:\n * 4× costs ~20 % of the frame over 1× on an integrated GPU. A host may pin it. */\n static get anisotropy(): number;\n static set anisotropy(level: number);\n static get maxSize(): number;\n static set maxSize(size: number);\n readonly width: number;\n readonly height: number;\n /** Horizontal wrap mode (U). */\n wrapS: number;\n /** Vertical wrap mode (V). */\n wrapT: number;\n constructor(width: number, height: number, id: Handle | number);\n static fromCanvas(canvas: {\n _bakeSurface(): number;\n width: number;\n height: number;\n pixelRatio: number;\n _tex3dId: number;\n }): Texture;\n /** A texture from raw pixels: `channels` (1–4, default 4) UBYTE per pixel, row-major, `width ×\n * height × channels` bytes; `srgb` (default true for colour) picks the sRGB internal format —\n * pass false for data (a heightmap, a mask). No mips. Throws on a host without the call. */\n static fromPixels(width: number, height: number, data: Uint8Array, opts?: {\n channels?: 1 | 2 | 3 | 4;\n srgb?: boolean;\n }): Texture;\n /** Re-upload a rectangle of a `fromPixels` texture (same channel count). */\n update(x: number, y: number, width: number, height: number, data: Uint8Array): void;\n /** Decode an image (PNG / JPG, or a KTX2 the core transcodes) into a texture. `srgb` (default\n * true) says the bytes are COLOUR, stored sRGB so the GPU linearises them on sample; pass\n * `false` for DATA — a normal map, a mask, a heightmap — which must come back as stored (a\n * flat normal read through sRGB bends by ~35°). A KTX2 decides by its own header. Image\n * textures get a mip chain (trilinear) on hosts that build one. */\n static load(source: string | FetchResponse | File, options?: TextureLoadOptions): Promise<Texture>;\n}\n","types/gl/touch.d.ts":"export declare const registerTouchStartEvent: () => void;\nexport declare const registerTouchEndEvent: () => void;\n","types/gl/vehicle/Vehicle.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3, type Vec3Like } from \"../../math/vec\";\nimport { type QuatLike } from \"../../math/quat\";\nimport { Node } from \"../Node\";\nimport { Wheel, type Point } from \"./Wheel\";\n/** Which axle the engine drives — the default for every wheel's own `driven` share. */\nexport type DriveLayout = \"rear\" | \"front\" | \"all\" | \"none\";\n/**\n * How an axle's two wheels share torque.\n * - `lsd` — limited slip (Jolt's 1.4 ratio), the sane default.\n * - `open` — fully open: a lifted or spinning wheel takes ALL the torque.\n * - `locked` — both wheels forced to the same speed. Breaks traction predictably: the drift diff.\n * A number is the raw max/min wheel-speed ratio (> 1; smaller is more locked).\n */\nexport type DifferentialMode = \"lsd\" | \"open\" | \"locked\";\nexport interface EngineConfig {\n /** Peak torque in N·m (default 500). The single biggest \"how fast is it\" knob. */\n torque?: number;\n /** Redline in RPM (default 6000) — Jolt's own clamp; a rev limiter's stutter is the game's. */\n maxRpm?: number;\n /** Idle RPM (default 1000): the engine's floor. `0` = no floor — the engine can be dragged to a\n * standstill and stall, and holding idle (a governor), cranking it, are the game's to write. */\n idleRpm?: number;\n /**\n * The engine's CHARACTER: points `{ x, y }` in NORMALISED units — x a fraction of the redline, y a\n * fraction of `torque`, x ascending. Left out, Jolt's own broad curve is used.\n *\n * `[{ x: 0, y: 0.8 }, { x: 0.66, y: 1 }, { x: 1, y: 0.8 }]` is an ordinary petrol engine (peak two\n * thirds up, falling to the redline); `[{ x: 0, y: 1 }, { x: 1, y: 1 }]` is flat, an electric motor.\n */\n curve?: Point[];\n /** Moment of inertia in kg·m² (default 0.5) — how eagerly it revs when the clutch is out. */\n inertia?: number;\n /** Engine braking: angular damping of the engine itself (default 0.2). */\n braking?: number;\n}\n/**\n * The steering wheel as a BODY the tires push back on, simulated by the engine every sub-step. With\n * it, `steer` is where the driver's hands AIM the wheel and `steerForce` how firmly they hold it;\n * where the road wheels end up is physics:\n *\n * I·θ̈ = T_hand + T_align·(1 − powerSteering) + T_stop − (damping + endStop.damping·depth)·θ̇ − parkingFriction(v) − friction\n *\n * `T_align` is the tires' self-aligning torque (`steering.caster` / `trail` / `trailAtPeak` — the\n * same torque `steerTorque` reports without a feedback body, for a force-feedback wheel). `T_hand`\n * is the driver's arms, `steering.driver`. So: heavy at speed, light when the front lets go,\n * self-centring on release, and in a slide a let-go wheel swings into opposite lock by itself.\n * Without `feedback` there is no body: `steer` is the road wheels' angle as a fraction of `maxAngle`.\n */\nexport interface SteeringFeedback {\n /** Moment of inertia of wheel + column + rack about the axis, kg·m² (default 1). Heavier = slower\n * off the mark under the hands, but a wheel whipping into counter-steer carries further. */\n inertia?: number;\n /** Viscous damping, N·m·s/rad (default 25): what keeps a let-go wheel from ringing about centre. */\n damping?: number;\n /** The column's own dry friction, N·m, at any speed (default 8) — rack and bearings: the floor a\n * free wheel's spin decays against, and what keeps a let-go wheel from creeping under a small torque. */\n friction?: number;\n /** The contact patch's dry friction while (nearly) parked, N·m (default 40), fading out by 1.5 m/s\n * — why a parked car is hard to steer, and why a wheel left turned stays turned. */\n parkingFriction?: number;\n /** Power steering, 0..1 (default 0.5): the share of the tires' aligning torque the wheel never\n * sees. It is NOT a gain on the angle: 0 is a kart (heavy, full of feel, a held key gives up its\n * lock early at speed), 1 is a dead rim that neither centres nor counter-steers. */\n powerSteering?: number;\n /** The END STOP before the lock — rubber, not a wall (default `{ band: 16, torque: 120, damping: 150 }`):\n * over the last `band` degrees the rack pushes back toward centre with the SQUARE of the depth,\n * `torque` N·m at the lock, and damps by `damping` N·m·s/rad × depth. A wheel let go on the stop\n * eases back off it a few degrees; `band: 0` = the hard clamp only. */\n endStop?: {\n band?: number;\n torque?: number;\n damping?: number;\n };\n}\n/** The driver's ARMS on a `feedback` wheel — an actuator with numbers, because a stiff hand spring\n * has to be integrated with the column every sub-step. WHAT the hands do (aim, hold, let go) is\n * the game's, per frame, through `steer` and `steerForce`. */\nexport interface SteeringDriver {\n /** The most torque the hands can put on the wheel, N·m (default 130). The ceiling on how much lock\n * a held key keeps at speed against the tires' pull. */\n maxTorque?: number;\n /** How stiff the arms are, N·m/rad of the gap between where they aim and where the wheel is (default 500). */\n stiffness?: number;\n /** The fastest the hands turn the road wheels, deg/s (default 120): the hands cannot PUSH a wheel\n * that already outruns them, they can still hold and brake it; a let-go wheel is uncapped. */\n maxRate?: number;\n /** Seconds the hands' torque takes to build to `maxTorque` (default 0.1): muscles do not step. */\n rampTime?: number;\n}\nexport interface SteeringConfig {\n /** Steering lock in degrees (default 35): what `steer = ±1` means. */\n maxAngle?: number;\n /** The front axle's GEOMETRY, the source of the tires' self-aligning torque (`steerTorque`, and\n * what a `feedback` wheel is pushed by): the mechanical caster's trail, metres (default 0.03)… */\n caster?: number;\n /** …and the pneumatic trail, metres (default 0.025) — the patch's own lever, which collapses as the\n * tire reaches its peak slip angle (the steering going light when the front lets go)… */\n trail?: number;\n /** …to this fraction of itself at the peak (default 0.5). */\n trailAtPeak?: number;\n /** Simulate the steering wheel as a body the tires push back on (`SteeringFeedback`). `true` = the\n * defaults. Without it `steer` sets the road wheels' angle directly. */\n feedback?: boolean | SteeringFeedback;\n /** The driver's arms on a `feedback` wheel (`SteeringDriver`); the defaults without it. */\n driver?: SteeringDriver;\n}\n/**\n * Aerodynamics. Both numbers are quoted the same way — **a fraction of the car's own weight at\n * 30 m/s (108 km/h)** — and both grow with the SQUARE of speed from there, so `0.5` at 30 m/s is\n * `2.0` at 60 m/s. One mental model for both, and no drag coefficients or frontal areas to invent.\n */\nexport interface AeroConfig {\n /**\n * Downforce (default 0 — a car with no wing). The knob that decides whether a car corners better\n * or worse the faster it goes: tire grip is a constant, but the force a corner demands grows with\n * v², so with no downforce every car runs out of road at speed. `0.6` roughly doubles a car's\n * cornering at 150 km/h; a road car is nearer `0.1`, a race car well past `1`.\n *\n * It presses along the CHASSIS' own down axis (that is what keeps a car planted over a crest) and\n * only while a wheel is on the ground — a car on its roof is never launched by its own wing.\n */\n downforce?: number;\n /** Air resistance (default 0.03 — an ordinary car). What gives a car a top speed at all. */\n drag?: number;\n}\nexport declare class Vehicle extends Aspect<\"vehicle\", Node> {\n static readonly aspect = \"vehicle\";\n /** Chassis mass in kg (default 1200). Wheels are massless in this model. */\n mass: number;\n /** Centre of mass height in chassis space (metres, negative = lower). Left out, it drops to halfway\n * down the chassis shape — a car with its mass at the shape's centre tips over. */\n centerOfMass?: number;\n /** Which axle the engine drives (default \"rear\") — the default for every wheel's own `driven`\n * share: 1 on that axle, 0 elsewhere. `none` = no drive at all (a trailer, a pushed cart). */\n driveAxle: DriveLayout;\n /** Differential lock across each driven axle. `locked` is the drift setup — both wheels turn\n * together, so the pair lets go as a pair. Live: re-configure the aspect to switch it mid-drive. */\n differential: DifferentialMode | number;\n /**\n * Anti-roll bars between each axle's wheels — what stops a car rolling onto its inside wheels in a\n * fast corner. `true` (default) is a bar 0.01 as stiff as the wheel's own spring; a number is that\n * ratio directly, and `0` / `false` removes the bars.\n *\n * **The numbers are far smaller than they look and the gain is steep** — Jolt's bar feeds\n * `lengthDifference × stiffness × dt` as a bias into the suspension's own soft constraint, so 4%\n * of the spring already flattens the body. Measured on a 1250 kg car: `0` → 1.3° of roll at 0.86 g,\n * `0.01` → 0.6°, `0.15` → 0.2° (flat), `0.5` → the car HOPS.\n *\n * This is the knob for how much a car visibly LEANS, not for wheel lift: bars change how far the\n * body tips, not how much load transfers. For lift, lower `centerOfMass`.\n */\n antiRoll: boolean | number;\n /** Pitch/roll limit in degrees (default 60) before the constraint rights the car. 180 turns it off. */\n maxTilt: number;\n /** Friction of the CHASSIS body itself — how it slides when it lands on its roof or side. Nothing\n * to do with the tires; those are the `Wheel`'s `tire` × the ground's friction. */\n friction: number;\n /** Strength of the clutch when fully engaged (default 10). Small values slip; large ones weld the\n * engine to the wheels. `clutch` (the input) scales it 0..1. */\n clutchStrength: number;\n /** The clutch's torque CAPACITY, N·m (default 0 = none: Jolt's viscous clutch alone, torque =\n * `clutchStrength` × slip speed, no ceiling — rigid at any real slip). Set it and the clutch\n * SLIPS at this much torque × `clutch` — a dry clutch, emulated a physics step at a time: a\n * launch can be feathered, and a dumped clutch in too high a gear drags the engine down instead\n * of lurching. A road car's is ~1.5× the engine's peak torque. */\n clutchCapacity: number;\n engine: EngineConfig;\n steering: SteeringConfig;\n aero: AeroConfig;\n /** Scene-editor inspector: the flat, tunable half. The grouped objects are edited in code. */\n static fields: FieldMeta<Vehicle>;\n static editor: {\n rebuild: boolean;\n };\n /** Driver systems tick at the default 0, so their inputs land in the SAME early pass, before this flush. */\n protected updateOrder: number;\n private _id;\n private _bodyId;\n private _builtMass;\n private _wheels;\n private _state;\n private _stateFrame;\n private _throttle;\n private _steer;\n private _steerForce;\n private _ratio;\n private _clutch;\n private _input;\n private _sent;\n private _dirty;\n private _retunePending;\n onAttach(): void;\n onDetach(): void;\n /**\n * Re-configuring an attached vehicle retunes it in place — the way a drift button switches the\n * differential without the car so much as blinking:\n *\n * car.aspect(Vehicle, { differential: drift ? 'locked' : 'lsd' })\n *\n * Live: `differential`, `engine`, `steering`, `aero`, `maxTilt`, `friction`, `clutchStrength`,\n * `clutchCapacity`, `antiRoll` (its stiffness, on axles that have a bar), and every `Wheel`'s\n * `tire`. Everything else describes the car's STRUCTURE — `mass`, `centerOfMass`, which wheels\n * exist and where, their suspension, the driven shares — and is baked into the constraint at\n * attach; to change one of those, re-attach the aspect.\n */\n onReconfigure(): void;\n /** Native vehicle id (0 until attached / no physics support). */\n get id(): number;\n /** The chassis rigid body id (for `physicsApplyImpulse`-style calls). */\n get bodyId(): number;\n /** The wheels, front axle first, in the order the engine knows them. */\n get wheels(): readonly Wheel[];\n /** Throttle 0..1 — the engine's pedal. No sign: the direction is `ratio`'s. */\n get throttle(): number;\n set throttle(v: number);\n /** Steering −1..1. Without `steering.feedback`: the road wheels' angle as a fraction of `maxAngle`,\n * applied as is (a taper with speed, a rate limit, are the game's). With it: where the hands AIM\n * the wheel; the tires decide where the road wheels end up. */\n get steer(): number;\n set steer(v: number);\n /** How firmly the hands hold a `feedback` wheel, 0..1 (default 1): the hands' torque is capped at\n * `driver.maxTorque × steerForce`. 0 = let go — the tires alone have the wheel: back to centre in\n * a grip corner, into opposite lock in a slide. Ignored without a feedback wheel. */\n get steerForce(): number;\n set steerForce(v: number);\n /** The ONE gear ratio the engine runs (default 1): engine rpm = wheel rpm × ratio × the final\n * drive (3.42). The SIGN is the direction — negative is reverse — and 0 is neutral. */\n get ratio(): number;\n set ratio(v: number);\n /** Clutch engagement 0..1 (default 1 = home). 0 = out: the engine is free of the wheels. */\n get clutch(): number;\n set clutch(v: number);\n /**\n * EARLY phase: hand this frame's inputs to the engine, before the step. The vector is sent when\n * anything changed — and every frame while a throttle, steer or brake is non-zero, because that is\n * what keeps a driven car awake (an idle car with zero input sleeps). The pending re-tune (a\n * config or tire change) goes first, so the step runs on the new numbers.\n */\n protected updateBefore(): void;\n /** Teleport upright and clear all motion (velocity, engine rpm, wheel spin). Defaults to the\n * chassis node's current pose — `reset()` alone un-flips a car where it lies. The inputs are\n * kept and re-sent on the next early pass. */\n reset(position?: Vec3Like, rotation?: QuatLike): this;\n /** Push the chassis (a boost pad, an explosion) — an instantaneous impulse in kg·m/s. */\n applyImpulse(v: Vec3Like): this;\n private _read;\n /** Speed along the car's forward axis in m/s — negative when reversing (× 3.6 for km/h). */\n get speed(): number;\n /** Engine RPM. */\n get rpm(): number;\n /** How many wheels touch the ground this frame. */\n get wheelsOnGround(): number;\n /** At least one wheel on the ground. */\n get grounded(): boolean;\n /** Chassis velocity in world space, m/s. */\n get velocity(): Vec3;\n /** Chassis angular velocity in world space, rad/s. */\n get angularVelocity(): Vec3;\n /** How fast the car is turning about the vertical, in degrees per second — positive turning RIGHT\n * (the same sense as `steer`). The signal a counter-steer assist reads. */\n get yawRate(): number;\n /**\n * The car's slip angle in degrees: the angle between where the nose points and where the car is\n * actually travelling, positive when it is travelling to the RIGHT of the nose. 0 going straight,\n * ±180 backing up, and past ~10° the rear has stepped out — a drift.\n */\n get slipAngle(): number;\n /**\n * The angle of the SLIDE, degrees, signed like `slipAngle` (positive = travelling to the right of\n * the nose), −180..180: the angle between the car's axis and where its REAR AXLE travels — the\n * mean of the non-steering wheels (every wheel if all of them steer), its velocity from the\n * body's velocity and spin. Unlike `slipAngle` (the body's, at its centre) this is 0 on a clean\n * corner at ANY speed: at walking pace and full lock the body already travels ~20° off its nose\n * while the rear axle rolls straight along it. It is the rear stepping out — what a gyro comes in\n * on, and what a drift meter should show — and unlike the tires' own `Wheel.slipAngle` it does\n * not fold at 90°: a backward entry reads 110°, not 70°. The axis it is measured from is the one\n * the DRIVETRAIN pushes along — the nose for a positive `ratio`, the tail for a negative one — so\n * honest reversing reads 0, and a car spun round in a forward gear reads past 90°. 0 at a\n * standstill: with no speed a direction is noise, so it fades in over walking pace,\n * `DRIFT_SPEED_FROM`..`DRIFT_SPEED_FULL` of the axle's ground speed.\n */\n get driftAngle(): number;\n /** Where the steered wheels actually are, in degrees, right-positive: the angle `steer` set, or\n * with `steering.feedback` where the column has come to. */\n get steerAngle(): number;\n /** The tires' self-aligning torque on the steering, N·m, positive = it pulls the wheel to the\n * RIGHT — what the driver feels: heavy at speed, light when the front lets go, and the\n * counter-steer in a slide. Reported with or without a `feedback` wheel: the signal a\n * force-feedback steering wheel is driven by. */\n get steerTorque(): number;\n /** Every Wheel under the chassis, ordered front axle first, with its axle group resolved. */\n private _collectWheels;\n /** Pack the whole configuration into the one blob the host ABI takes (see bridges.d.ts). */\n private _buildSettings;\n /** Edit mode: which way the chassis faces. Each wheel draws its own circle and travel range — see\n * `Wheel.rebuild()`. Play mode never calls this. */\n rebuild(): void;\n}\n","types/gl/vehicle/Wheel.d.ts":"import { Aspect } from \"../../core/Aspect\";\nimport type { FieldMeta } from \"../../core/fields\";\nimport { Vec3 } from \"../../math/vec\";\nimport { Node } from \"../Node\";\n/** Floats `vehicleGetState` writes before the per-wheel block: speed, rpm, contacts, vx, vy, vz, wx, wy, wz,\n * steerDeg, steerTorque. */\nexport declare const STATE_HEADER = 11;\n/** Floats per wheel: contact, slip, slipAngle, suspensionLength, steerDeg, spin, fLat, fLong, vLat, vSlip, load. */\nexport declare const WHEEL_STATE = 11;\n/** Fully compressed = this fraction of `travel` (the engine's one suspension constant, mirrored here\n * so `compression` and the resting-height maths read the same number). */\nexport declare const SUSPENSION_MIN_FRACTION = 0.4;\n/** A point on a curve — a tire's friction over slip, an engine's torque over rpm. */\nexport type Point = {\n x: number;\n y: number;\n};\nexport interface WheelSuspension {\n /** Total travel in metres, full droop to fully compressed (default 0.4). */\n travel?: number;\n /** Spring frequency in Hz — bigger is stiffer (default 1.4; a race car ~2.5, a truck ~1). It also\n * sets the ride-height sag, and the sag is how far the wheel can still extend DOWN. */\n stiffness?: number;\n /** Damping ratio 0..1 (default 0.5). Low values pogo. */\n damping?: number;\n}\n/**\n * A tire, as the engine takes it: two friction curves and two numbers. `Tire.road()` and the other\n * presets are starting points — copy one and edit, or `Tire.scale()` it.\n */\nexport interface Tire {\n /** Lateral friction over slip ANGLE: `{ x: degrees, y: friction }`, x ascending. Friction is the\n * coefficient the tire's load is multiplied by; the last value holds to 90°. The grip a wheel\n * actually gets is combined with the ground it stands on as `sqrt(tire × groundFriction)`, and a\n * body's friction defaults to 0.6 — a road a car should really corner on wants `Physics { friction: 1 }`. */\n side: Point[];\n /** Longitudinal friction over slip RATIO: `{ x: ratio, y: friction }` (0 = rolling in sync, 1 =\n * locked or spinning freely). */\n forward: Point[];\n /** The longitudinal impulse clamp as a multiple of `friction × load` — for DRIVE only; a braking\n * wheel is always clamped at the physical limit (or a locked rear would stop the car at a full g\n * and kill every handbrake turn). `1` is the physical tire; `road`'s 10 is Jolt's own sample\n * value (it keeps a driven wheel from ever spinning up). Anything a friction circle should bite\n * on wants this near 1. */\n traction?: number;\n /** Friction circle, 0..1: how much of the lateral capacity the longitudinal impulse in use takes\n * away. `0` = the two axes independent (a spinning wheel corners as well as a rolling one);\n * `1` = the full circle — wheelspin or a locked wheel lets go sideways. */\n circle?: number;\n}\n/**\n * Tire presets — fresh point lists every call (editing one never touches another), and `scale`.\n *\n * - `road` — Jolt's stock tire: lateral peak 1.2 at 3° falling to 1.0 by 20° and flat after, the\n * two axes independent, and the longitudinal clamp ×10 (Jolt's own sample runs this; it means a\n * driven wheel practically never spins up). Grippy, glued, hard to unsettle.\n * - `arcade` — the peak held all the way out on both axes: the car does not let go at all.\n * - `drift` — a tire that can be held sideways: lateral grip falls to 0.7 past 25°, the longitudinal\n * clamp is near the physical one (`traction: 2` — a launch at exactly 1 is a 0.4 g crawl; 2 keeps\n * it punchy) so the rear can be spun up, and a friction circle (`circle: 0.85` — most of it, so a\n * spinning rear loses most but not all of its lateral grip and the slide stays progressive):\n * power oversteer, and a slide the throttle keeps alive. A 600 N·m car lights its tires off the\n * line on it; that is the tire, and a traction control is the game's.\n */\nexport declare const Tire: {\n road: () => Tire;\n arcade: () => Tire;\n drift: () => Tire;\n /** Both curves multiplied by `k` — a grip slider, a cold tire, a wet road. A new tire; `t` is untouched. */\n scale: (t: Tire, k: number) => Tire;\n};\nexport declare function resolveTire(tire: Tire): ResolvedTire;\nexport declare class Wheel extends Aspect<\"wheel\", Node> {\n static readonly aspect = \"wheel\";\n /** Wheel radius in metres. Default: measured from the node's rendered bounds, else 0.35. Too small\n * and the car scrapes, too large and it floats. */\n radius?: number;\n /** Wheel width in metres. Default: measured, else 0.25. */\n width?: number;\n /** Axle group, front to back. Default: derived from Z. Set it for a car whose wheels are not in neat\n * left/right pairs — an axle's wheels are paired for the differential and the anti-roll bar. */\n axle?: number;\n /** Does this wheel steer? Default: the wheels on the front axle. */\n steer?: boolean;\n /** This wheel's SHARE of the engine's torque, 0 = not driven. Default: from the vehicle's\n * `driveAxle` (1 on that axle). An axle's share is the sum of its two wheels', the left/right\n * split their ratio, so `0.6` / `0.4` front-to-rear is `driven: 0.3` on each front wheel and\n * `0.2` on each rear. Structural: baked at attach. */\n driven?: number;\n suspension: WheelSuspension;\n /** The tire (default `Tire.road()`). Live: re-assign it or re-configure the aspect and the car\n * retunes in place — a grip slider, a tire that heats up. */\n tire: Tire;\n /** INPUT: brake torque on this wheel THIS frame, N·m (default 0). Sticky, like `Vehicle.throttle`:\n * write it every frame from a driver system's `updateBefore` — the foot brake's share, the\n * handbrake's 4500 on a rear wheel, an ABS's pulses — and the same physics step applies it. A\n * braking wheel is clamped at the physical tire limit (the `traction` boost is for drive only). */\n brake: number;\n /** Scene-editor inspector. `steer` / `driven` are deliberately absent: they are tri-state\n * (undefined = derive it from the axle), which a slider cannot express. */\n static fields: FieldMeta<Wheel>;\n static editor: {\n rebuild: boolean;\n };\n onDetach(): void;\n /** Re-configuring a wheel on a live car retunes the car: the tire is live; size, suspension, the\n * driven share and the axle are structural (re-attach the Vehicle). */\n onReconfigure(): void;\n private _state;\n /** Touching the ground this step. */\n get contact(): boolean;\n /** Longitudinal slip RATIO, signed: 0 = rolling in sync with the ground, towards +1 = spinning up\n * (wheelspin), towards −1 = locking under braking — whichever way the car travels. Smoke, tire\n * marks, wheelspin sound and traction control key off this. */\n get slip(): number;\n /** Slip ANGLE in degrees, signed: how far the tire's travel direction is off from where it points,\n * positive when the contact patch slides to the tire's RIGHT. Past the curve's peak (~3°) the tire\n * is letting go sideways. */\n get slipAngle(): number;\n /** This wheel's steer angle in degrees, right-positive. */\n get steerAngle(): number;\n /** Wheel spin in rad/s (× radius ≈ the speed the tire is laying down). Forward-positive; a model\n * turns about the right-hand axle by MINUS the integrated angle. */\n get spin(): number;\n /** The tire's lateral force this step, N, positive toward the tire's right — the road pushing the\n * patch back against its slide. */\n get sideForce(): number;\n /** The tire's longitudinal force this step, N, positive pushing the car forward. */\n get forwardForce(): number;\n /** How fast the contact patch slides sideways, m/s, positive to the tire's right. */\n get sideSlipSpeed(): number;\n /** How fast the tread runs over the road, m/s, positive spinning up, negative locking. Force ×\n * sliding speed (`|sideForce × sideSlipSpeed| + |forwardForce × slipSpeed|`) is the friction's\n * heat into the tread, W — a tire-temperature model integrates it. */\n get slipSpeed(): number;\n /** The suspension's force on the wheel this step, N — the tire's LOAD (0 in the air). What a\n * friction budget divides by: `hypot(sideForce, forwardForce) / (load × μ)`. */\n get load(): number;\n /** Suspension compression, 0 = fully extended (drooping) … 1 = fully compressed. */\n get compression(): number;\n /** Where the wheel's centre is right now, in CHASSIS space: the suspension's attachment point,\n * down by however far it hangs this step. Put a wheel model here (see the file header). */\n get position(): Vec3;\n /** Edit mode: this wheel's own circle at its resting height, its travel range, and a mark when the\n * engine drives it — enough to place a wheel without running the game. */\n rebuild(): void;\n}\n","types/inject.d.ts":"export { Mathf } from \"./math/Mathf\";\nexport { Vec2, Vec3 } from \"./math/vec\";\nexport { Quat } from \"./math/quat\";\nexport { Mat4 } from \"./math/mat4\";\nexport { Color } from \"./core/color\";\nexport { Aspect, System, type With, type SystemHost } from \"./core/Aspect\";\nexport { type EventMap } from \"./core/events\";\nexport { Time } from \"./core/time\";\nexport { StateMachine, defineStates, type StateDef, type StatesDef, type StateGuard, type StateHandler, type StateMachineEvents } from \"./core/StateMachine\";\nexport { InspectorUI } from \"./core/InspectorUI\";\nexport { signal, computed, effect, type Signal, type Computed } from \"./core/signals\";\nexport { __compWrite, __compOp, type CompAxis, type CompWriter } from \"./core/compWrite\";\nexport { Canvas, Bitmap } from \"./canvas/Canvas\";\nexport { toast, openURL, SvgSource } from \"./runtime/misc\";\nexport { app, type AppState, type OrientationLock } from \"./runtime/app\";\nexport { clipboard } from \"./runtime/clipboard\";\nexport { date, type DateValue, type DateInput, type Unit, type Locale } from \"./runtime/datetime\";\nexport { fetch, fetchLocal, FormData, File, type FetchResponse } from \"./runtime/fetch\";\nexport { localStorage } from \"./runtime/storage\";\nexport { device, type HapticStyle, type MotionOptions } from \"./runtime/device\";\nexport { Input, InputChannel, type InputKeyEvent, type InputGamepadEvent, type InputEventName, type GamepadState, type GamepadAxisName } from \"./runtime/input\";\nexport { WebSocket } from \"./runtime/net\";\nexport { Net, NetPlayer, Replicated, NetEntity, type NetMessage, type NetRole, type NetStatus, type NetEvents, type NetLaunch, type NetInput, type NetKind, type NetTransform, type NetCorrection } from \"./net\";\nexport { __rpc, __channel, __serverOnly, RpcError } from \"./runtime/rpc\";\nexport type { ChannelSubscription } from \"./server/channel\";\nexport type { StoredFile, StoredImage } from \"./server/files/models\";\nexport { AudioPlayer, VideoPlayer } from \"./runtime/media\";\nexport { Sound, type SoundOptions } from \"./audio/Sound\";\nexport { Voice, type VoiceEvents } from \"./audio/Voice\";\nexport { Bus, REVERB_PRESETS, type ReverbPreset, type ReverbParams, type EchoParams } from \"./audio/Bus\";\nexport { audio, type PlaySoundOptions, type SpatialOptions, type Rolloff, type AudioStats } from \"./audio/audio\";\nexport { openFilePicker, files, type FileData } from \"./runtime/files\";\nexport { share } from \"./runtime/share\";\nexport { ClickEvent, TouchStartEvent, LongPressEvent, MouseEnterEvent } from \"./runtime/touch\";\nexport { Scene2D } from \"./g2/Scene2D\";\nexport { Node2D } from \"./g2/Node2D\";\nexport { Camera2D } from \"./g2/Camera2D\";\nexport { Sprite } from \"./g2/Sprite\";\nexport { SpriteAnimation } from \"./g2/SpriteAnimation\";\nexport { Shape2D } from \"./g2/Shape2D\";\nexport { Physics2D } from \"./g2/Physics2D\";\nexport { Trigger2D } from \"./g2/Trigger2D\";\nexport { CharacterController2D } from \"./g2/CharacterController2D\";\nexport { OneWay2D } from \"./g2/OneWay2D\";\nexport { PhysicsGroup2D } from \"./g2/groups2d\";\nexport { Tilemap } from \"./g2/Tilemap\";\nexport { Texture2D } from \"./g2/Texture2D\";\nexport { SpriteSheet, defineSpriteSheet } from \"./g2/SpriteSheet\";\nexport type { SpriteSheetDef, SheetSprite, SpriteMakeOptions } from \"./g2/SpriteSheet\";\nexport { Tileset, defineTileset, Autotile2D } from \"./g2/Tileset\";\nexport { rawCell, isRawCell, rawIndex } from \"./g2/autotile\";\nexport { rot90, rot180, rot270, flipX, packTile, tileIndex, tileTurns, tileFlip, tileOriented } from \"./g2/autotile\";\nexport type { TilesetDef, TileMaterial, PatchMaterial, PathMaterial, PatchSlots, EdgeSlot, FillBlock, BlockEntry, TileBlock, TilePart, } from \"./g2/autotile\";\nexport { defineScene2d, Scene2dHandle } from \"./g2/defineScene2d\";\nexport type { Scene2dDef, Scene2dNodeDef, Scene2dEnv, SpriteSourceDef, TilemapSourceDef, Camera2dNodeDef, LoadedScene2d } from \"./g2/defineScene2d\";\nexport { cells, encodeCells, type CellsData } from \"./g2/cells\";\nexport { CameraFollow } from \"./g2/scenarios2d\";\nexport { UIScreen, type UIScreenStyle, UIRow, UIColumn, UIBox, type UIContainerStyle, UIText, type UITextStyle, UIButton, type UIButtonStyle, UIImage, type UIImageStyle, UIVideo, type UIVideoStyle, UIInput, UITextArea, type UIInputStyle, UIScrollable, type UIScrollableStyle, UIPager, type UIPagerStyle, UITabs, type UITabDef, defineTabs, type TabDef, type TabsHandle, UIWidget, type UIWidgetStyle, UIOverlay, type UIWidgetContent, UIModal, type UIModalStyle, UIBottomSheet, type UIBottomSheetStyle, UIPopover, type UIPopoverStyle, UISpacer, type UISpacerStyle, UIVirtualizedList, Router, NativeView, type UINativeViewStyle, registerFont, __uiMap, __UIColumn, __UIRow, __UIBox, __UIButton, __UIScreen, __UIScrollable, __UIWidget, } from \"./ui/UI\";\nexport { Presentable } from \"./ui/UI\";\nexport type { DismissOptions, PresentOptions, Transition, TransitionName, TransitionPose, TransitionSpec } from \"./ui/UI\";\nexport type { UINode, UINodeChild } from \"./ui/UINode\";\nexport { theme, type ThemeValues, type ThemeAccessors, type ThemeRoles } from \"./ui/theme\";\nexport { animate, type AnimateOptions, type AnimateValue, type AnimateOut } from \"./animate/tween/animateValue\";\nexport { cubicBezier } from \"./animate/bezier\";\nexport { Timeline, type TimelineOptions, type TimelineAddOptions, type TimelinePosition } from \"./animate/tween/Timeline\";\nexport { type Animation } from \"./animate/tween/Animation\";\nexport { type TweenMeta } from \"./animate/tween/spec\";\nexport { type EasingInput } from \"./animate/tween/easing\";\nexport { easeIn, easeOut, easeInOut } from \"./animate/easings\";\nexport { QRScanner } from \"./plugins/gen/qr-scanner/sdk/qr-scanner\";\nexport { CameraView, type CameraFacing } from \"./plugins/gen/camera/sdk/camera\";\nexport { Geolocation, type GeoPosition, type GeoOptions, type GeoWatch } from \"./plugins/gen/geolocation/sdk/geolocation\";\nexport { MapView, type MapOptions, type MapStyle, type MapStyleName, type MapCamera, type MapTap, type LngLat, type CameraMove, type FitOptions, type MapPaddingValues, type MarkerItem, type MarkerTap, type MarkerLayer, type MarkerLayerOptions, type LineLayer, type LineLayerOptions, type UserLocationOptions, } from \"./plugins/gen/map/sdk/map\";\nexport { Push, type PushPayload, type PushStatus, type PushRegisterOptions, type PushEvent } from \"./plugins/gen/push/sdk/push\";\nexport { Service } from \"./plugins/service\";\nexport { defineScene, use, ref, make, SceneHandle } from \"./scene/defineScene\";\nexport { defineMaterial, MaterialHandle } from \"./scene/material\";\nexport type { MaterialData, MaterialParamValue, ShaderMaterialDef, LitMaterialDef, UnlitMaterialDef } from \"./scene/material\";\nexport type { SceneDef, SceneNodeDef, MeshDef, LightDef, MaterialDef, CameraNodeDef, AspectEntry, MakeEntry, LoadedScene, SceneInstance } from \"./scene/defineScene\";\nexport { CameraPlace } from \"./gl/CameraPlace\";\nexport { Level } from \"./scene/level\";\nexport type { LevelSpot, LevelBuild, LevelCollider, LevelLineOptions, LevelGridOptions, LevelRingOptions, LevelScatterOptions, LevelPlaceOptions } from \"./scene/level\";\nexport type { FieldMeta } from \"./core/fields\";\nexport { Gizmos } from \"./scene/gizmos\";\nexport type { GizmoStyle, GizmoAnchor } from \"./scene/gizmos\";\nexport { MoveTo, FollowPath, Spin, LookAt, PlayAnimation } from \"./gl/scenarios\";\nexport { registerEditorWindow, registerEditorTool } from \"./scene/editorPlugins\";\nexport type { EditorApi, EditorRayHit, EditorToolHooks, EditorWindowFn } from \"./scene/editorPlugins\";\nexport { Scene, ARScene, VRScene } from \"./gl/Scene\";\nexport { Node } from \"./gl/Node\";\nexport { Mesh } from \"./gl/Mesh\";\nexport { Model } from \"./gl/Model\";\nexport { Shape } from \"./gl/physics/Shape\";\nexport { Physics } from \"./gl/physics/Physics\";\nexport { Trigger } from \"./gl/physics/Trigger\";\nexport { AudioSource, type AudioCone } from \"./gl/audio/AudioSource\";\nexport { AudioZone } from \"./gl/audio/AudioZone\";\nexport { SceneAudio } from \"./gl/audio/SceneAudio\";\nexport { CharacterController } from \"./gl/physics/CharacterController\";\nexport { Vehicle } from \"./gl/vehicle/Vehicle\";\nexport type { DriveLayout, DifferentialMode, EngineConfig, SteeringConfig, SteeringFeedback, SteeringDriver, AeroConfig } from \"./gl/vehicle/Vehicle\";\nexport { Wheel, Tire, resolveTire } from \"./gl/vehicle/Wheel\";\nexport { Ragdoll } from \"./gl/physics/Ragdoll\";\nexport type { RagdollPart, RagdollHinge, RagdollFacing, RagdollActivateOptions, RagdollDeactivateOptions, RagdollHitOptions } from \"./gl/physics/Ragdoll\";\nexport type { Point, WheelSuspension } from \"./gl/vehicle/Wheel\";\nexport { AnimationClip } from \"./gl/animation/AnimationClip\";\nexport type { ClipDef, ClipTrackDef, ClipKey } from \"./gl/animation/AnimationClip\";\nexport { Animator } from \"./gl/animation/Animator\";\nexport type { LodMode } from \"./gl/animation/Animator\";\nexport type { TrianglePick } from \"./gl/Model\";\nexport { Feet } from \"./gl/animation/Feet\";\nexport type { FeetOptions, FootState } from \"./gl/animation/Feet\";\nexport { Warp } from \"./gl/animation/Warp\";\nexport type { WarpOptions, StepWarpOptions } from \"./gl/animation/Warp\";\nexport { Playback } from \"./gl/animation/Playback\";\nexport { Loop } from \"./gl/animation/Loop\";\nexport { Layer } from \"./gl/animation/Layer\";\nexport type { PlayOptions, StopOptions, LayerOptions, LoopOptions, LoopDef, BlendPosition, BlendMember, ActiveClip, ClipInfo, ClipCycle, ClipAlign, KneeAxisReport, StepHandler, ClipEventHandler } from \"./gl/animation/core\";\nexport { IK } from \"./gl/animation/IK\";\nexport { DynamicBone, DynamicBoneCollider } from \"./gl/animation/DynamicBone\";\nexport type { DynamicBoneCurve, DynamicBoneFloor, DynamicBoneColliders } from \"./gl/animation/DynamicBone\";\nexport type { IKTwoBone, IKLookAt } from \"./gl/animation/IK\";\nexport { Light } from \"./gl/Light\";\nexport { Lightmap } from \"./gl/Lightmap\";\nexport { Foliage } from \"./gl/Foliage\";\nexport type { FoliageOptions, FoliageWind } from \"./gl/Foliage\";\nexport { Terrain } from \"./gl/terrain/Terrain\";\nexport type { TerrainOptions, TerrainLayer, TerrainRegion, ConformOptions, RibbonOptions, AutoPaintRules, SculptOptions, TerrainHit, TerrainSnapshot } from \"./gl/terrain/Terrain\";\nexport { NavMesh, NavCrowd } from \"./gl/nav/NavMesh\";\nexport type { NavMeshLoadOptions, NavMeshInfo, NavPath, NavQueryOptions, NavRaycastHit, NavAgentSize } from \"./gl/nav/NavMesh\";\nexport { NavAgent } from \"./gl/nav/NavAgent\";\nexport type { NavAgentState, NavAgentAvoidance, NavAgentDrive, NavAgentEvents } from \"./gl/nav/NavAgent\";\nexport { Locomotion } from \"./gl/animation/Locomotion\";\nexport type { LocomotionSet, LocomotionClip, LocomotionTuning, LocomotionState, LocomotionEvents, Displacement, Gait } from \"./gl/animation/Locomotion\";\nexport { Material } from \"./gl/Material\";\nexport { Geometry } from \"./gl/Geometry\";\nexport { InstancedMesh } from \"./gl/InstancedMesh\";\nexport type { InstanceTransform } from \"./gl/InstancedMesh\";\nexport { Texture } from \"./gl/Texture\";\nexport type { TextureLoadOptions } from \"./gl/Texture\";\nexport { Camera } from \"./gl/Camera\";\nexport { Ray } from \"./gl/Ray\";\nexport { Plane } from \"./gl/Plane\";\nexport { Noise } from \"./gl/Noise\";\nexport { Particles, Trail, curve, colorCurve } from \"./gl/Particles\";\nexport { DecalSet, DecalTrail } from \"./gl/DecalSet\";\nexport type { DecalOptions, DecalSetOptions, DecalSpawnOptions, DecalPlacement, DecalTrailOptions } from \"./gl/DecalSet\";\n","types/inject.editor.d.ts":"export { sceneEditor as __sceneEditor, type SceneEditorApi } from \"./scene/editor\";\n","types/math/mat4.d.ts":"import { Vec3, type Vec3Like } from \"./vec\";\nimport { Quat, type QuatLike, type EulerOrder } from \"./quat\";\nexport type Mat4Like = Mat4 | number[] | Float32Array | readonly number[];\nexport declare class Mat4 {\n /** The raw column-major elements (length 16). Public on purpose — read/write directly when you want\n * the metal: `mat.m[12] += vx * dt`. The fluent methods never mutate it (they return a new Mat4). */\n m: number[];\n constructor(src?: Mat4Like);\n set(values: ArrayLike<number>): this;\n copy(src: Mat4Like): this;\n /** `this · b` (apply `b` first in local space, then `this`). */\n mul(b: Mat4Like): Mat4;\n /** `b · this` — multiply on the other side (apply `this` first, then `b`). */\n premul(b: Mat4Like): Mat4;\n invert(): Mat4;\n transpose(): Mat4;\n determinant(): number;\n /** `this · translate(v)`. */\n translate(v: Vec3Like): Mat4;\n /** `this · scale(v)`. Accepts a vector or a uniform scalar. */\n scale(v: Vec3Like | number): Mat4;\n /** `this · rotate(axis, rad)`. */\n rotate(rad: number, axis: Vec3Like): Mat4;\n rotateX(rad: number): Mat4;\n rotateY(rad: number): Mat4;\n rotateZ(rad: number): Mat4;\n /** Transform a point (applies translation + perspective divide). */\n transformPoint(v: Vec3Like): Vec3;\n /** Transform a direction (rotation/scale only — no translation, no divide). */\n transformDirection(v: Vec3Like): Vec3;\n get position(): Vec3;\n get scaling(): Vec3;\n get rotation(): Quat;\n get eulerAngles(): Vec3;\n toEuler(order?: EulerOrder): Vec3;\n /** `{ position, rotation, scale }` in one shot. */\n decompose(): {\n position: Vec3;\n rotation: Quat;\n scale: Vec3;\n };\n /** Column basis vectors (the local X / Y / Z axes in world space). */\n get basisX(): Vec3;\n get basisY(): Vec3;\n get basisZ(): Vec3;\n clone(): Mat4;\n toArray(): number[];\n toFloat32Array(): Float32Array;\n equals(b: Mat4Like, eps?: number): boolean;\n static identity(): Mat4;\n static from(src: Mat4Like): Mat4;\n /** Translation · Rotation · Scale into one matrix. `scale` defaults to 1 and accepts a scalar. */\n static compose(position: Vec3Like, rotation: QuatLike, scale?: Vec3Like | number): Mat4;\n static fromQuat(q: QuatLike): Mat4;\n static fromTranslation(v: Vec3Like): Mat4;\n static fromScale(v: Vec3Like | number): Mat4;\n static fromEuler(x: number, y: number, z: number, order?: EulerOrder): Mat4;\n /** A view matrix that looks from `eye` toward `center` with `up`. */\n static lookAt(eye: Vec3Like, center: Vec3Like, up?: Vec3Like): Mat4;\n /** A world matrix that places something at `eye` oriented to look at `target`. */\n static targetTo(eye: Vec3Like, target: Vec3Like, up?: Vec3Like): Mat4;\n /** Perspective projection (WebGL/OpenGL clip, NDC z ∈ [−1, 1]). `fovy` is in RADIANS. */\n static perspective(fovy: number, aspect: number, near: number, far: number): Mat4;\n /** Orthographic projection (WebGL/OpenGL clip, NDC z ∈ [−1, 1]). */\n static ortho(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4;\n}\n","types/math/Mathf.d.ts":"export type Damper<T extends number | number[]> = ((target: T, dt: number) => T) & {\n /** Snap the damper's internal current value (e.g. on teleport). */\n setValue(value: T): void;\n};\ndeclare function smoothDamp(initial: number, smoothTime: number, maxSpeed?: number): Damper<number>;\ndeclare function smoothDamp(initial: number[], smoothTime: number, maxSpeed?: number): Damper<number[]>;\nexport declare const Mathf: {\n PI: number;\n TAU: number;\n EPSILON: number;\n DEG2RAD: number;\n RAD2DEG: number;\n deg2rad: (deg: number) => number;\n rad2deg: (rad: number) => number;\n clamp: (v: number, min: number, max: number) => number;\n clamp01: (v: number) => number;\n lerp: (a: number, b: number, t: number) => number;\n inverseLerp: (a: number, b: number, v: number) => number;\n remap: (v: number, inMin: number, inMax: number, outMin: number, outMax: number) => number;\n /** Move `a` toward `b` by at most `maxDelta`. */\n moveTowards: (a: number, b: number, maxDelta: number) => number;\n /** Frame-rate-independent exponential approach (good default: lambda 5..15). */\n damp: (a: number, b: number, lambda: number, dt: number) => number;\n sign: (x: number) => number;\n /** Loop a value into [0, length). */\n repeat: (t: number, length: number) => number;\n /** Ping-pong a value in [0, length]. */\n pingPong: (t: number, length: number) => number;\n random: (min?: number, max?: number) => number;\n randomInt: (min: number, max: number) => number;\n /**\n * Critically-damped follow (Unity SmoothDamp). Returns a stateful damper you call every frame:\n * const d = Mathf.smoothDamp([x, y], 0.15)\n * pos = d(targetPos, dt)\n * Works on a number or a numeric array (vec2 / vec3).\n */\n smoothDamp: typeof smoothDamp;\n};\nexport {};\n","types/math/quat.d.ts":"import { Vec3, type Vec3Like } from \"./vec\";\nexport type QuatLike = Quat | readonly [number, number, number, number] | number[] | Float32Array;\nexport type EulerOrder = \"XYZ\" | \"YXZ\" | \"ZXY\" | \"ZYX\" | \"YZX\" | \"XZY\";\n/** Read the w / 4th component of any quaternion-like (wrapper `.w`, or array-like `[3]`). */\nexport declare const cw: (q: {\n w?: number;\n} | ArrayLike<number>) => number;\nexport declare class Quat {\n x: number;\n y: number;\n z: number;\n w: number;\n constructor(x?: number | QuatLike, y?: number, z?: number, w?: number);\n set(x: number, y: number, z: number, w: number): this;\n copy(q: QuatLike): this;\n /** Hamilton product `this ⊗ b` (apply `b` first, then `this`). */\n mul(b: QuatLike): Quat;\n normalize(): Quat;\n conjugate(): Quat;\n /** Inverse rotation. For a unit quaternion this equals `conjugate()`. */\n invert(): Quat;\n dot(b: QuatLike): number;\n /** Spherical interpolation toward `b` by `t ∈ [0, 1]`. */\n slerp(b: QuatLike, t: number): Quat;\n /** Angular distance (radians) between two unit quaternions. */\n angle(b: QuatLike): number;\n /** Rotate a vector by this quaternion → a new `Vec3`. */\n rotateVec3(v: Vec3Like): Vec3;\n /** Extract euler angles (DEGREES) in the given order. */\n toEuler(order?: EulerOrder): Vec3;\n equals(b: QuatLike, eps?: number): boolean;\n /** True if the two unit quaternions represent the same rotation (±q are equal). */\n sameRotation(b: QuatLike, eps?: number): boolean;\n clone(): Quat;\n toArray(): [number, number, number, number];\n [Symbol.iterator](): Iterator<number>;\n static from(q: QuatLike): Quat;\n static get identity(): Quat;\n /** From euler angles in DEGREES (default order \"YXZ\"). Inverts `toEuler`. */\n static fromEuler(x: number, y: number, z: number, order?: EulerOrder): Quat;\n /** From a rotation `axis` and an angle in RADIANS. The axis is normalized for you. */\n static fromAxisAngle(axis: Vec3Like, rad: number): Quat;\n /** The shortest rotation that takes direction `a` onto direction `b`. */\n static fromTo(a: Vec3Like, b: Vec3Like): Quat;\n /** A rotation whose forward (−Z) points along `forward`, with `up` as the reference up axis. */\n static lookRotation(forward: Vec3Like, up?: Vec3Like): Quat;\n}\n/** Quaternion from a column-major rotation matrix (≥3×3, indices 0,1,2,4,5,6,8,9,10). gl-matrix's\n * `getRotation` algorithm — the exact inverse of building a matrix from a quaternion. */\nexport declare const quatFromColMajor: (m: ArrayLike<number>) => Quat;\n/** Euler angles (DEGREES) from a column-major rotation matrix, standard three.js extraction.\n * Element naming follows the column-major layout: mRC = m[(C-1)*4 + (R-1)]. */\nexport declare const eulerFromColMajor: (m: ArrayLike<number>, order?: EulerOrder) => Vec3;\n","types/math/vec.d.ts":"export type Vec2Like = Vec2 | readonly [number, number] | number[] | Float32Array;\nexport type Vec3Like = Vec3 | readonly [number, number, number] | number[] | Float32Array;\n/** Read the x / first component of any vector-like (wrapper, tuple, or typed array). `?? ` is safe on\n * 0 and NaN — it only falls through on `undefined` (i.e. a non-wrapper that has no `.x`). */\nexport declare const cx: (v: {\n x?: number;\n} | ArrayLike<number>) => number;\nexport declare const cy: (v: {\n y?: number;\n} | ArrayLike<number>) => number;\nexport declare const cz: (v: {\n z?: number;\n} | ArrayLike<number>) => number;\nexport declare class Vec2 {\n x: number;\n y: number;\n constructor(x?: number | Vec2Like, y?: number);\n /** Mutate the components in place. Returns `this`. */\n set(x: number, y: number): this;\n /** Copy another vector's components into this one. Returns `this`. */\n copy(v: Vec2Like): this;\n add(v: Vec2Like): Vec2;\n sub(v: Vec2Like): Vec2;\n mul(v: Vec2Like): Vec2;\n div(v: Vec2Like): Vec2;\n scale(s: number): Vec2;\n /** `this + v * s` (fused multiply-add). */\n scaleAndAdd(v: Vec2Like, s: number): Vec2;\n negate(): Vec2;\n dot(v: Vec2Like): number;\n /** 2D cross product → the scalar z of the 3D cross (signed parallelogram area). */\n cross(v: Vec2Like): number;\n length(): number;\n lengthSq(): number;\n distanceTo(v: Vec2Like): number;\n distanceSqTo(v: Vec2Like): number;\n normalize(): Vec2;\n lerp(v: Vec2Like, t: number): Vec2;\n clamp(min: Vec2Like, max: Vec2Like): Vec2;\n min(v: Vec2Like): Vec2;\n max(v: Vec2Like): Vec2;\n /** Left-hand perpendicular: (-y, x), a 90° CCW turn. */\n perp(): Vec2;\n /** Rotate by `rad` (CCW) around `origin` (default 0). */\n rotate(rad: number, origin?: Vec2Like): Vec2;\n /** The vector's heading in radians: `atan2(y, x)`. */\n heading(): number;\n /** Angle (radians) between this and `v`. */\n angle(v: Vec2Like): number;\n withX(x: number): Vec2;\n withY(y: number): Vec2;\n equals(v: Vec2Like, eps?: number): boolean;\n clone(): Vec2;\n toArray(): [number, number];\n [Symbol.iterator](): Iterator<number>;\n static from(v: Vec2Like): Vec2;\n static get zero(): Vec2;\n static get one(): Vec2;\n static get up(): Vec2;\n static get down(): Vec2;\n static get left(): Vec2;\n static get right(): Vec2;\n}\nexport declare class Vec3 {\n x: number;\n y: number;\n z: number;\n constructor(x?: number | Vec3Like, y?: number, z?: number);\n set(x: number, y: number, z: number): this;\n copy(v: Vec3Like): this;\n add(v: Vec3Like): Vec3;\n sub(v: Vec3Like): Vec3;\n mul(v: Vec3Like): Vec3;\n div(v: Vec3Like): Vec3;\n scale(s: number): Vec3;\n /** `this + v * s` (fused multiply-add). */\n scaleAndAdd(v: Vec3Like, s: number): Vec3;\n negate(): Vec3;\n dot(v: Vec3Like): number;\n cross(v: Vec3Like): Vec3;\n length(): number;\n lengthSq(): number;\n distanceTo(v: Vec3Like): number;\n distanceSqTo(v: Vec3Like): number;\n normalize(): Vec3;\n lerp(v: Vec3Like, t: number): Vec3;\n clamp(min: Vec3Like, max: Vec3Like): Vec3;\n min(v: Vec3Like): Vec3;\n max(v: Vec3Like): Vec3;\n /** Reflect this vector about a (unit) `normal`: `v - 2·(v·n)·n`. */\n reflect(normal: Vec3Like): Vec3;\n /** Vector projection of this onto `onto`. */\n project(onto: Vec3Like): Vec3;\n /** Angle (radians) between this and `v`. */\n angle(v: Vec3Like): number;\n /** Rotate this point around the X axis through `origin` (default 0) by `rad`. */\n rotateX(rad: number, origin?: Vec3Like): Vec3;\n rotateY(rad: number, origin?: Vec3Like): Vec3;\n rotateZ(rad: number, origin?: Vec3Like): Vec3;\n /** Rotate this vector by a quaternion (x, y, z, w). Accepts a `Quat` or a raw `[x,y,z,w]`. */\n rotate(q: ArrayLike<number> | {\n x: number;\n y: number;\n z: number;\n w: number;\n }): Vec3;\n /** Transform this point by a column-major mat4 (a `Mat4`, its `.m`, or a raw length-16 array),\n * applying translation and the perspective divide. */\n transform(m: ArrayLike<number> | {\n m: ArrayLike<number>;\n }): Vec3;\n withX(x: number): Vec3;\n withY(y: number): Vec3;\n withZ(z: number): Vec3;\n equals(v: Vec3Like, eps?: number): boolean;\n clone(): Vec3;\n toArray(): [number, number, number];\n [Symbol.iterator](): Iterator<number>;\n static from(v: Vec3Like): Vec3;\n static get zero(): Vec3;\n static get one(): Vec3;\n static get up(): Vec3;\n static get down(): Vec3;\n static get left(): Vec3;\n static get right(): Vec3;\n /** Forward is −Z (the engine's cameras look down −Z; `node.forward` is −Z at identity). */\n static get forward(): Vec3;\n static get back(): Vec3;\n}\n","types/net/codec.d.ts":"export type FieldKind = 0 | 1 | 2;\nexport type Field = {\n key: string;\n kind: FieldKind;\n len: number;\n step: boolean;\n};\nexport type Layout = {\n fields: Field[];\n floats: number;\n bools: number;\n bytes: number;\n sig: string;\n};\nexport declare const makeLayout: (defaults: Record<string, unknown>, what: string, discrete?: readonly string[]) => Layout;\n/** A fresh state object shaped like the defaults (arrays copied, never shared). */\nexport declare const cloneDefaults: <T extends object>(defaults: T) => T;\n/** Copy the layout's fields from `from` into `into` (array elements copied in place; unknown keys\n * ignored — a JSON spawn state or a partial `setInput`). */\nexport declare const assignState: (layout: Layout, into: any, from: any) => void;\nexport declare const packInto: (view: DataView, offset: number, layout: Layout, s: any) => number;\nexport declare const unpackFrom: (view: DataView, offset: number, layout: Layout, into: any) => number;\n/** `out = a + (b − a) · t` for the numeric fields; booleans and the discrete ones take `b`'s. */\nexport declare const lerpState: (layout: Layout, a: any, b: any, t: number, out: any) => void;\n/** FNV-1a over a string → 8 hex chars. Enough to tell two bundles' schemas apart. */\nexport declare const hashString: (s: string) => string;\n","types/net/core.d.ts":"export type Listener = (...args: any[]) => void;\nexport type NetRole = \"offline\" | \"host\" | \"client\" | \"server\";\nexport type NetStatus = \"idle\" | \"connecting\" | \"online\" | \"error\";\n/** A typed message key: `const Fire = Net.message<{ dir: number[] }>(\"fire\")`. The type lives in\n * TypeScript only; the payload is JSON. */\nexport type NetMessage<T = unknown> = {\n readonly name: string;\n readonly unreliable: boolean;\n readonly __t?: T;\n};\nexport type NetEvents = {\n /** Client: welcomed by the server. Host/server: listening. */\n connect: () => void;\n /** The connection ended (`reason` from the transport, e.g. \"timed out\", \"kicked\"). */\n disconnect: (reason: string) => void;\n /** The server refused us (`reason`: \"full\" | \"version\" | \"schema\" | a kick reason). */\n reject: (reason: string) => void;\n join: (player: NetPlayer) => void;\n leave: (player: NetPlayer, reason: string) => void;\n error: (message: string) => void;\n};\nexport type NetLaunch = {\n role: \"server\" | \"client\";\n address: string;\n port: number;\n maxClients: number;\n};\n/** Link statistics (`player.rtt` / `player.loss` read them): the bridge's `NetStats`. */\nexport type NetStats = {\n rtt: number;\n loss: number;\n sentKbps: number;\n receivedKbps: number;\n};\nexport declare const CH_RELIABLE = 0;\nexport declare const CH_UNRELIABLE = 1;\nexport declare const PROTO = 3;\nexport declare const LOCAL_SLOT = -1;\nexport declare const bridge: () => typeof _creatorNet | null;\nexport declare class NetPlayer {\n /** Session-unique id assigned by the server (1 = the host's own player when hosting). */\n readonly id: number;\n name: string;\n readonly connectedAt: number;\n /** A local bag for game facts (score, team, ready). NOT replicated — anything a client must see\n * goes through a message or replicated state. */\n data: any;\n /** Server: what this player's `Net.connect(…, { hello })` carried (the game's own: a build, a\n * token) — the value `Net.listen({ accept })` was asked about. Undefined everywhere else. */\n hello: unknown;\n private _leave;\n constructor(id: number, name: string, slot: number);\n get isMe(): boolean;\n /** Round trip to this player in ms (server side) or to the server (our own player on a client). */\n get rtt(): number;\n get loss(): number;\n /** Server → this player. */\n send<T>(msg: NetMessage<T>, data: T): void;\n kick(reason?: string): void;\n on(event: \"leave\", cb: (player: NetPlayer, reason: string) => void): this;\n off(event: \"leave\", cb: (player: NetPlayer, reason: string) => void): this;\n}\nexport declare const state: {\n role: NetRole;\n status: NetStatus;\n isServer: boolean;\n isClient: boolean;\n me: NetPlayer | null;\n players: NetPlayer[];\n nextId: number;\n /** a session is up: the phase hooks are installed and pump every frame */\n active: boolean;\n events: Map<string, Listener[]>;\n handlers: Map<string, Listener[]>;\n connectResolve: null | (() => void);\n connectReject: null | ((e: Error) => void);\n myName: string;\n /** client: the game's own part of the `$hello` (`Net.connect(…, { hello })`), opaque to the SDK */\n hello: unknown;\n /** server: the game's say in the handshake (`Net.listen({ accept })`) — a reason refuses */\n accept: null | ((hello: unknown, who: {\n name: string;\n }) => string | null | void);\n};\nexport declare const hooks: {\n frameEarly: null | ((dt: number) => void);\n frameFixed: null | ((dt: number) => void);\n frameLate: null | ((dt: number) => void);\n /** client: extra `$hello` fields (schema hash) */\n helloExtra: null | (() => Record<string, unknown>);\n /** server: a reject reason for this `$hello`, or null to accept */\n helloCheck: null | ((data: any) => string | null);\n /** server: extra `$welcome` fields (tick, kind table) */\n welcomeExtra: null | (() => Record<string, unknown>);\n /** server: right after `$welcome` + `$join` went out — send the live entities to the newcomer */\n afterWelcome: null | ((p: NetPlayer) => void);\n /** client: the `$welcome` arrived (before the connect event) */\n onWelcome: null | ((data: any) => void);\n /** client: a reserved `$` message the roster does not know (spawn / despawn) */\n clientReserved: null | ((name: string, data: any) => void);\n /** binary payloads (channel 1): inputs on the server, snapshots on the client */\n serverBinary: null | ((p: NetPlayer, channel: number, data: ArrayBuffer) => void);\n clientBinary: null | ((channel: number, data: ArrayBuffer) => void);\n /** server: a player is gone (after the leave event) */\n playerLeft: null | ((p: NetPlayer) => void);\n /** the session ends (before the state resets); `role` = the role we are leaving */\n reset: null | ((role: NetRole) => void);\n};\nexport declare const emit: (event: keyof NetEvents, ...args: any[]) => void;\nexport declare const playerBySlot: (slot: number) => NetPlayer | undefined;\nexport declare const addPlayer: (id: number, name: string, slot: number) => NetPlayer;\nexport declare const removePlayer: (p: NetPlayer, reason: string) => void;\nexport declare const ensureMe: () => NetPlayer;\nexport declare const sendRaw: (slot: number, channel: number, payload: string | ArrayBuffer) => boolean;\nexport declare const queueLocal: (fn: () => void) => void;\nexport declare const dispatchMessage: (name: string, data: unknown, from: NetPlayer | null) => void;\nexport declare const deliverTo: (p: NetPlayer, msg: NetMessage<any>, data: unknown) => void;\nexport declare const broadcastRaw: (payload: string | ArrayBuffer, except: NetPlayer | null, channel?: number) => void;\nexport declare const startPhases: () => void;\nexport declare const stopPhases: () => void;\nexport declare const resetToOffline: () => void;\nexport declare const pump: () => void;\n","types/net/index.d.ts":"import { NetPlayer, type NetEvents, type NetLaunch, type NetMessage, type NetRole, type NetStatus } from \"./core\";\nimport { NetEntity, Replicated, stats, type NetCorrection, type NetInput, type NetKind, type NetTransform } from \"./replication\";\nexport { NetPlayer, NetEntity, Replicated };\nexport type { NetEvents, NetLaunch, NetMessage, NetRole, NetStatus, NetInput, NetKind, NetTransform, NetCorrection };\ndeclare class NetImpl {\n get role(): NetRole;\n get status(): NetStatus;\n get isServer(): boolean;\n get isClient(): boolean;\n /** True on hosts that ship the transport (desktop, the 3d/full Android variants, iOS). Web: false. */\n get supported(): boolean;\n /** What the exe was launched as (`--server --port N` / `--connect ADDR`), or null. */\n get launch(): NetLaunch | null;\n get me(): NetPlayer;\n get players(): readonly NetPlayer[];\n player(id: number): NetPlayer | undefined;\n /** Our round trip to the server (client), 0 otherwise. */\n get rtt(): number;\n /** The simulation tick — one per fixed step (`updateFixed`). The server's is THE tick; a client\n * runs a few ticks ahead so its inputs arrive in time. */\n get tick(): number;\n /** The server tick this machine is SHOWING the others at: on a client, its estimate of the server's\n * clock less the interpolation delay (fractional); `tick` everywhere else, where nothing is\n * interpolated. What a client names when it tells the server \"as I saw it\". */\n get viewTick(): number;\n /** Live counters: snapshots, input lead / `ahead`, corrections, missed inputs, bytes out. */\n get stats(): typeof stats;\n /** Start serving on `port`. From offline this makes us the host (a player who is also the\n * server); on the dedicated exe (`Net.launch.role === \"server\"`) there is no local player.\n * `accept` is the game's say in the handshake: it is given what the client's `connect` passed as\n * `hello` and returns a reason to refuse (the client's `reject` event carries it), nothing to accept. */\n listen(opts?: {\n port?: number;\n maxClients?: number;\n name?: string;\n dedicated?: boolean;\n accept?: (hello: unknown, who: {\n name: string;\n }) => string | null | void;\n }): boolean;\n /** Connect to a host/server (`address` = \"ip:port\"). Resolves once the server welcomed us.\n * `hello` = anything JSON the game wants the server to see before it lets us in (its\n * `Net.listen({ accept })`, then `player.hello`); the SDK only carries it. */\n connect(target: {\n address: string;\n }, opts?: {\n name?: string;\n hello?: unknown;\n }): Promise<void>;\n /** Client → offline. Host/server → everyone is dropped, back to offline. */\n disconnect(): void;\n /** Declare a message type once; the name is the wire id. `unreliable` = channel 1 (fire-and-forget). */\n message<T = void>(name: string, opts?: {\n unreliable?: boolean;\n }): NetMessage<T>;\n /** Client → server (offline / host: delivered in-process, `from` = our own player). */\n send<T>(msg: NetMessage<T>, data: T): void;\n /** Server → every player (incl. the host's own), minus `except`. */\n broadcast<T>(msg: NetMessage<T>, data: T, opts?: {\n except?: NetPlayer | null;\n }): void;\n /** Subscribe to a built-in event or to a message (`from` = the sending player on the server,\n * null on a client — the server sent it). Returns `Net` for chaining. */\n on<K extends keyof NetEvents>(event: K, cb: NetEvents[K]): this;\n on<T>(msg: NetMessage<T>, cb: (data: T, from: NetPlayer | null) => void): this;\n off<K extends keyof NetEvents>(event: K, cb: NetEvents[K]): this;\n off<T>(msg: NetMessage<T>, cb: (data: T, from: NetPlayer | null) => void): this;\n /** The per-tick input layout (one per game): `const PlayerInput = Net.input({ moveX: 0, moveY: 0, jump: false })`.\n * Fields: number → f32, boolean → 1 bit, number[] → f32 × length. */\n input<T extends object>(defaults: T): NetInput<T>;\n /** Set this tick's input — from `updateFixed`, once per tick, on the machine that owns the player\n * (client / host / offline). The owner's sim reads it back through `rep.input(PlayerInput)`; a\n * client also ships it to the server for the same tick. */\n setInput<T extends object>(inp: NetInput<T>, values: Partial<T>): void;\n /** A replicated entity type: the defaults are the snapshot layout (same field rules as `input`),\n * `transform` tells the SDK which fields mirror the node's pose, `client` births the proxy on a\n * client when the server spawns one (`new Node().aspect(Replicated, { kind, owner })`) — it may\n * be set later, `Kind.client = …`, where the client's code lives. `discrete` names the numeric\n * fields that are never interpolated (an index, a count); `correction` tunes how the owner's\n * prediction is brought back to the server's state (all in the game's own units). */\n kind<S extends object>(name: string, defaults: S, opts?: {\n transform?: NetTransform;\n client?: (rep: NetEntity<S>, scene: any) => any;\n discrete?: readonly (keyof S & string)[];\n correction?: Partial<NetCorrection>;\n }): NetKind<S>;\n /** Every replicated entity this machine knows. */\n get entities(): readonly NetEntity[];\n entity(netId: number): NetEntity | undefined;\n /** Dev only: yojimbo's network simulator on our side of the wire (latency/jitter in ms, loss in %). */\n simulate(opts: {\n latency?: number;\n jitter?: number;\n loss?: number;\n }): void;\n}\nexport declare const Net: NetImpl;\n","types/net/replication.d.ts":"import { Aspect } from \"../core/Aspect\";\nimport { Vec3 } from \"../math/vec\";\nimport type { Node } from \"../gl/Node\";\nimport { Scene } from \"../gl/Scene\";\nimport { type Layout } from \"./codec\";\nimport { NetPlayer } from \"./core\";\nexport type NetTransform = \"pos\" | \"pos+rot\" | \"none\";\n/** How an owner's prediction is brought back to the server's state. The SDK knows nothing of what\n * the entity is, so the defaults are neutral: every disagreement counts, none is a teleport. */\nexport type NetCorrection = {\n /** A vertical disagreement below this is ignored (world units). 0 = none ignored. A body that\n * snaps to a floor differs by a little between two machines, and lifting it by that feeds itself. */\n deadbandY: number;\n /** A disagreement of this much or more is a teleport: the body jumps and `correction` stays zero\n * (world units). Infinity = always smoothed. */\n snap: number;\n /** The decay time constant of the visual offset `correction` (seconds). 0 = no smoothing. */\n tau: number;\n};\n/** The per-tick input layout: `const PlayerInput = Net.input({ moveX: 0, moveY: 0, jump: false })`. */\nexport type NetInput<T extends object = any> = {\n readonly layout: Layout;\n readonly defaults: T;\n readonly __t?: T;\n};\n/** A replicated entity type: `const PlayerKind = Net.kind('player', { pos: [0,0,0], hp: 100 }, { transform: 'pos', client })`. */\nexport type NetKind<S extends object = any> = {\n readonly name: string;\n readonly layout: Layout;\n readonly defaults: S;\n /** Which state fields the SDK samples on the server and applies to a client proxy: `pos` (a\n * `pos: [x,y,z]` field), `pos+rot` (+ a `rot: [x,y,z,w]` quaternion field), or `none`. */\n readonly transform: NetTransform;\n readonly correction: NetCorrection;\n /** Births the client-side proxy on spawn; the SDK attaches `Replicated` to what it returns.\n * Assignable: a declaration both ends share may leave it to the client's own module. */\n client?: (rep: NetEntity<S>, scene: Scene | null) => Node | void;\n readonly __t?: S;\n};\n/** Live counters (`Net.stats`): how the clocks and the prediction are doing. */\nexport declare const stats: {\n /** client: snapshots received */ snapshots: number;\n /** client: how far ahead of the server's simulation our newest input was at the last snapshot */ ahead: number;\n /** client: our tick minus the estimated server tick */ lead: number;\n /** client: tick nudges (+1 / −1) by the lead control */ nudges: number;\n /** owner: corrections applied, the largest one and their sum (metres) — `sum / corrections` = the typical one */ corrections: number;\n maxCorrection: number;\n sumCorrection: number;\n /** server: inputs that arrived late (the last one was repeated), all clients */ missed: number;\n /** bytes sent on the unreliable channel (snapshots / inputs) */ bytesOut: number;\n};\nexport declare class NetEntity<S extends object = any> {\n /** Session-unique id, assigned by the server. */\n readonly netId: number;\n readonly kind: NetKind<S>;\n /** The owning player's id; 0 = the server's own (props, the game state). */\n readonly ownerId: number;\n /** Server: the authoritative state you write (`pos` is sampled from the node). Client remote:\n * interpolated. Client owner: the newest authoritative state. */\n readonly state: S;\n /** The node carrying this entity (server: yours; client: what the kind's factory returned). */\n node: Node | null;\n /** Owner on a client: the visual offset left by the last correction, decaying to zero — add it to\n * what you DRAW (a child mesh, the camera), never to physics. */\n readonly correction: Vec3;\n constructor(netId: number, kind: NetKind<S>, ownerId: number, s: S);\n get owner(): NetPlayer | null;\n /** Our own player owns it (offline: everything owned by `Net.me`). */\n get isMine(): boolean;\n /** This machine runs the simulation for it: the server always, a client for what it owns\n * (prediction). A remote proxy on a client is interpolation only. */\n get simulated(): boolean;\n /** The owner's input for the tick being simulated — the ring entry on the server (the last one\n * repeated when it is late), the local input on the owner / host / offline. */\n input<T extends object>(inp: NetInput<T>): T;\n /** `input()` is an input the owner gave — false until the first one exists (the server before\n * the owner's first packet, the owner before its first `Net.setInput`), when it is the defaults. */\n get hasInput(): boolean;\n /** Client: `state` was refreshed (a snapshot landed / the interpolation moved). */\n on(event: \"state\", cb: (s: S) => void): this;\n off(event: \"state\", cb: (s: S) => void): this;\n}\nexport declare const declareKind: <S extends object>(name: string, defaults: S, opts?: {\n transform?: NetTransform;\n client?: NetKind<S>[\"client\"];\n discrete?: readonly string[];\n correction?: Partial<NetCorrection>;\n}) => NetKind<S>;\nexport declare const declareInput: <T extends object>(defaults: T) => NetInput<T>;\nexport declare const setInput: <T extends object>(inp: NetInput<T>, values: Partial<T>) => void;\nexport declare const currentTick: () => number;\nexport declare const viewTick: () => number;\nexport declare const allEntities: () => NetEntity[];\nexport declare const entityById: (netId: number) => NetEntity | undefined;\n/**\n * The server's handle on a replicated entity — attach it to the node that IS the entity:\n * `new Node().aspect(Replicated, { kind: PlayerKind, owner: player })`. From then on the entity exists\n * on every client (the kind's `client` factory births the proxy there, and the SDK attaches this same\n * aspect to it), its state is packed into every snapshot, and `node.destroy()` despawns it everywhere.\n * `node.replicated.state` / `.isMine` / `.simulated` / `.input()` are the same on both sides.\n */\nexport declare class Replicated extends Aspect<\"replicated\", Node> {\n static readonly aspect = \"replicated\";\n /** Server: the entity type (required). */\n kind: NetKind<any>;\n /** Server: the owning player, or null for the server's own. */\n owner: NetPlayer | null;\n protected onAttach(): void;\n protected onDetach(): void;\n /** The entity itself (what the client factory received). */\n get entity(): NetEntity;\n get netId(): number;\n get state(): any;\n get isMine(): boolean;\n get simulated(): boolean;\n get ownerPlayer(): NetPlayer | null;\n get correction(): Vec3;\n /** The owner's input for the tick being simulated (see `NetEntity.input`). */\n input<T extends object>(inp: NetInput<T>): T;\n get hasInput(): boolean;\n}\nexport declare const installReplication: () => void;\n","types/plugin.d.ts":"import { File as HostFile } from \"./runtime/fetch\";\nimport { ServiceClient } from \"./runtime/service\";\nimport { NativeViewElement } from \"./ui/NativeView\";\nexport type { PresentOptions } from \"./ui/presentable\";\nexport type { NativeView } from \"./ui/NativeView\";\nexport type { FetchResponse } from \"./runtime/fetch\";\n/** Signed 32-bit integer on the wire. */\nexport type i32 = number;\n/** Double on the wire — also every integer that can leave 32 bits (a millisecond time stamp). */\nexport type f64 = number;\n/** Bytes that STAY in the host's buffer table: the native half hands over its bytes + a name, the\n * app gets the SDK's `File` handle (a texture source, a `FormData` value, a share) and the bytes\n * never enter the JS heap. For bytes the app must read itself, a contract says `Uint8Array`. */\nexport type File = HostFile;\n/** Any JSON value, opaque to the generator (GeoJSON, a developer's own payload): it crosses as is\n * and the native half receives the platform's untyped value. */\nexport type Json = null | boolean | number | string | Json[] | {\n [key: string]: Json;\n};\ndeclare const channel: unique symbol;\n/** Marks a contract interface as a NativeView channel. `Name` is what the halves register under\n * (`registerView(name)`); `Params` is what a factory receives; `Events` maps an event's name to\n * its payload (`void` = no payload). */\nexport interface View<Name extends string, Params extends object = {}, Events extends object = {}> {\n readonly [channel]?: {\n kind: \"view\";\n name: Name;\n params: Params;\n events: Events;\n };\n}\n/** Marks a contract interface as a headless Service channel — see {@link View}. */\nexport interface Service<Name extends string, Params extends object = {}, Events extends object = {}> {\n readonly [channel]?: {\n kind: \"service\";\n name: Name;\n params: Params;\n events: Events;\n };\n}\n/** A listener of the event `K`: no argument for a `void` payload. */\nexport type Listener<Events, K extends keyof Events> = Events[K] extends void ? () => void : (payload: Events[K]) => void;\n/** What an event's payload is read with when it is not on the wire what it is for the app (it\n * holds a File): by the event's name. */\nexport type EventReaders = {\n [event: string]: (wire: any) => any;\n};\n/** The element of a view plugin: a `NativeView` whose events are the contract's. Generated wrappers\n * extend it (`<Name>Base`); a hand-written one extends that, or this when its API is not the wire's. */\nexport declare class ViewChannel<Events extends object = {}> extends NativeViewElement {\n private readonly _readers;\n constructor(iface: string, name: string, params: object, readers?: EventReaders);\n /** Whether this host registered a view under `name` — at contract version `since` or later, when\n * one is given (a method's `@since`). */\n static supports(name: string, since?: number): boolean;\n on<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n off<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n}\n/** The client of a service plugin: a session that opens on the first call, with the contract's\n * events. The service twin of {@link ViewChannel}. */\nexport declare class ServiceChannel<Events extends object = {}> extends ServiceClient {\n private readonly _readers;\n constructor(iface: string, name: string, params?: object, readers?: EventReaders);\n /** Whether this host registered a service under `name` — at contract version `since` or later,\n * when one is given (a method's `@since`). */\n static supports(name: string, since?: number): boolean;\n on<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n off<K extends keyof Events & string>(event: K, callback: Listener<Events, K>): this;\n}\n/** The text of a host buffer — what a bundled `asset()` is in a shell compile (`\"id:N\"`): the host\n * already holds the bytes. Empty when there is no such buffer. */\nexport declare const bufferText: (systemId: number) => string;\n/** Prepare-then-present for a view that needs the camera: fail before any prompt on a host without\n * the view, ask for the permission while the current destination stays visible, give up when\n * another navigation superseded this one. Resolves when the view may open. */\nexport declare const prepareCamera: (view: ViewChannel<any>) => Promise<void>;\n","types/plugins/gen/camera/sdk/camera.d.ts":"import { type File, type NativeView, type PresentOptions } from \"../../../../plugin\";\nimport type { Facing } from \"../contract\";\nexport type CameraFacing = Facing;\nexport interface CameraView extends NativeView {\n /** Request the camera permission, then present the preview. The current destination stays\n * visible until the camera is ready; rejects if the permission is denied, the host has no\n * camera, or another navigation superseded this one. */\n open(options?: PresentOptions): Promise<void>;\n /** Capture a still frame as an image `File` (host-encoded). */\n takePhoto(): Promise<File>;\n /** Switch between the front and the back camera while the preview is live. */\n setFacingMode(facingMode: CameraFacing): Promise<void>;\n}\n/**\n * Create a camera view (default: the back camera). `CameraView.isSupported` reports whether this\n * host has the capability — check it before offering the feature.\n */\nexport declare const CameraView: {\n (options?: {\n facingMode?: CameraFacing;\n }): CameraView;\n /** Whether this host registered a \"camera\" view. */\n readonly isSupported: boolean;\n};\n","types/plugins/gen/camera/sdk/camera.gen.d.ts":"import { ViewChannel, type File } from \"../../../../plugin\";\nimport type { CameraEvents, CameraParams, Facing } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"camera\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** Capture a still frame as a JPEG.\n * Rejects with \"failed\". */\nexport declare const takePhoto: (view: ViewChannel<CameraEvents>) => Promise<File>;\n/** Switch the camera while the preview is live. */\nexport declare const setFacingMode: (view: ViewChannel<CameraEvents>, mode: Facing) => Promise<void>;\n/** A method of the contract. */\nexport type Method = \"takePhoto\" | \"setFacingMode\";\n/** Whether this host has the view \"camera\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The view \"camera\" with the wire's methods as its own. */\nexport declare class CameraViewBase extends ViewChannel<CameraEvents> {\n constructor(params?: CameraParams);\n /** Capture a still frame as a JPEG.\n * Rejects with \"failed\". */\n takePhoto(): Promise<File>;\n /** Switch the camera while the preview is live. */\n setFacingMode(mode: Facing): Promise<void>;\n}\n","types/plugins/gen/geolocation/sdk/geolocation.d.ts":"import type { GeoOptions, GeoPosition } from \"../contract\";\nexport type { GeoOptions, GeoPosition };\n/** A live `Geolocation.watch()` subscription — `stop()` it when the screen goes away. */\nexport interface GeoWatch {\n stop(): void;\n}\n/**\n * The device position. `Geolocation.isSupported` reports whether this host registered the\n * service — check it before offering location features.\n */\nexport declare const Geolocation: {\n /** Whether this host registered a \"geolocation\" service. */\n readonly isSupported: boolean;\n /** One position fix. Prompts for permission on first use; rejects on denial (\"denied\"), no\n * provider (\"unavailable\"), or `options.timeout` elapsing (\"timeout\"). */\n getCurrent(options?: GeoOptions): Promise<GeoPosition>;\n /** Continuous updates. Resolves once watching (permission granted + provider started) — so a\n * denial is a rejection, never a silently dead callback. One host watch serves every\n * subscriber; the options of the watch that starts it win. Always `stop()` when done. */\n watch(callback: (position: GeoPosition) => void, options?: GeoOptions): Promise<GeoWatch>;\n};\n","types/plugins/gen/geolocation/sdk/geolocation.gen.d.ts":"import { ServiceChannel } from \"../../../../plugin\";\nimport type { GeoOptions, GeoPosition, GeolocationEvents, GeolocationParams } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"geolocation\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** One fix.\n * Rejects with \"denied\" / \"unavailable\" / \"timeout\". */\nexport declare const getCurrent: (service: ServiceChannel<GeolocationEvents>, options?: GeoOptions) => Promise<GeoPosition>;\n/** Start the session's watch; resolves once it is live (permission granted, provider started).\n * A second call while watching resolves at once and keeps the first call's options.\n * Rejects with \"denied\" / \"unavailable\". */\nexport declare const startWatch: (service: ServiceChannel<GeolocationEvents>, options?: GeoOptions) => Promise<void>;\nexport declare const stopWatch: (service: ServiceChannel<GeolocationEvents>) => Promise<void>;\n/** A method of the contract. */\nexport type Method = \"getCurrent\" | \"startWatch\" | \"stopWatch\";\n/** Whether this host has the service \"geolocation\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The service \"geolocation\" with the wire's methods as its own. */\nexport declare class GeolocationBase extends ServiceChannel<GeolocationEvents> {\n constructor(params?: GeolocationParams);\n /** One fix.\n * Rejects with \"denied\" / \"unavailable\" / \"timeout\". */\n getCurrent(options?: GeoOptions): Promise<GeoPosition>;\n /** Start the session's watch; resolves once it is live (permission granted, provider started).\n * A second call while watching resolves at once and keeps the first call's options.\n * Rejects with \"denied\" / \"unavailable\". */\n startWatch(options?: GeoOptions): Promise<void>;\n stopWatch(): Promise<void>;\n}\n","types/plugins/gen/map/sdk/map.d.ts":"import { type FetchResponse, type NativeView } from \"../../../../plugin\";\nimport type { LngLat, MapCamera, MapCameraMove, MapFitOptions, MapPadding, MapParams, MapUserLocationOptions } from \"../contract\";\nexport type { LngLat, MapCamera };\nexport type CameraMove = MapCameraMove;\nexport type FitOptions = MapFitOptions;\nexport type MapPaddingValues = MapPadding;\nexport type UserLocationOptions = MapUserLocationOptions;\n/** The ready-made styles a map falls back on — [OpenFreeMap](https://openfreemap.org): OSM data,\n * no key, no registration, no request limits, commercial use allowed, and the whole stack is\n * open-source if you'd rather self-host. `liberty` is the default. Credit them (and OSM) in your\n * app: \"© OpenFreeMap © OpenMapTiles, data from OpenStreetMap\". A public free instance is a\n * donation-funded service with no SLA — for a product with real traffic, run your own tiles and\n * pass that style's URL instead. */\nexport type MapStyleName = \"liberty\" | \"bright\" | \"positron\" | \"dark\" | \"fiord\";\n/**\n * Where the map's style comes from:\n *\n * - a **name** — `\"liberty\"` (the default), `\"positron\"`, … see {@link MapStyleName}: a ready-made\n * style on a free public tile server, so `MapView()` alone already draws a world map;\n * - a **URL** — `\"https://tiles.example.com/styles/city/style.json\"`, the map fetches it;\n * - a **bundled style** — `asset(\"./map/style.json\")`: the file ships inside the app and the\n * wrapper hands its text to the map, so the style itself needs no server (tiles, sprites and\n * glyphs are still fetched from whatever urls it names);\n * - an **already-read file** — a `FetchResponse` from `fetchLocal(\"style.json\")` or\n * `await fetch(url)` (a style downloaded once and cached in `files`);\n * - the **style object** itself — the natural way to substitute a tile-server address at runtime:\n * `{ ...style, sources: { openmaptiles: { type: \"vector\", url: `${server}/data/v3.json` } } }`.\n *\n * Whichever form: **every url INSIDE the style (`sources[].url`, `sprite`, `glyphs`) must be\n * absolute.** maplibre-native, unlike maplibre-gl-js, resolves no relative ones — a style with\n * them loads to an empty basemap (your layers still draw). A tileserver-gl instance emits\n * relative urls until its `publicUrl` is configured.\n */\nexport type MapStyle = MapStyleName | (string & {}) | FetchResponse | object;\nexport interface MapOptions extends Omit<MapParams, \"style\" | \"styleJson\"> {\n /** The MapLibre style: a ready-made name (`\"liberty\"` — the default, `\"positron\"`, …), a URL,\n * a style bundled with the app (`asset(\"./style.json\")`), an already-read file\n * (`fetchLocal(\"style.json\")`, `await fetch(url)`) or the style object itself — see\n * {@link MapStyle}. */\n style?: MapStyle;\n}\n/** A tap on the map itself — not on a feature of a managed layer. */\nexport interface MapTap {\n lngLat: LngLat;\n /** View-space point, px. */\n point: [number, number];\n}\n/** One marker. `id` comes back in `onTap`; `icon` names an image of the style's sprite; `color` /\n * `title` feed the default layers; extra keys become feature properties. */\nexport interface MarkerItem {\n id: string | number;\n lngLat: LngLat;\n icon?: string;\n color?: string;\n title?: string;\n [property: string]: any;\n}\nexport interface MarkerTap {\n id: string | number;\n lngLat: LngLat;\n /** Every property of the tapped feature (the item's keys, `id` and `lngLat` excluded). */\n properties: Record<string, any>;\n}\nexport interface MarkerLayerOptions {\n /** Group nearby markers into clusters (a cluster tap zooms in). Default false. */\n cluster?: boolean;\n /** Cluster radius, px (default 50). */\n clusterRadius?: number;\n /** Zoom at which clusters stop forming (default: maxZoom − 1). */\n clusterMaxZoom?: number;\n}\nexport interface LineLayerOptions {\n color?: string;\n /** Px (default 4). */\n width?: number;\n /** 0–1 (default 1). */\n opacity?: number;\n}\nexport interface MarkerLayer {\n readonly name: string;\n /** Replace the layer's markers. */\n set(items: MarkerItem[]): this;\n clear(): this;\n /** A marker (or any feature of this layer's source) was tapped. */\n onTap(callback: (marker: MarkerTap) => void): this;\n}\nexport interface LineLayer {\n readonly name: string;\n /** Replace the line with these vertices. */\n set(coordinates: LngLat[]): this;\n clear(): this;\n}\nexport interface MapView extends NativeView {\n /** The style loaded and the map is interactive (queued calls have been replayed). */\n onReady(callback: () => void): this;\n /** A tap that hit no feature of a managed layer. */\n onTap(callback: (tap: MapTap) => void): this;\n /** The camera settled after a gesture or an animation. */\n onMove(callback: (camera: MapCamera) => void): this;\n /** The map reported a problem — a style that wouldn't load, a source it couldn't reach. Never\n * fatal; with no handler the message goes to `console.error`, so it is never silent. */\n onError(callback: (error: {\n message: string;\n }) => void): this;\n /** A named marker layer (one GeoJSON source). If the style already declares a source with this\n * name, its layers are used as-is and only the data is pushed; otherwise the plugin creates the\n * source and default marker layers (colored dot, `icon`, `title` label; clusters on request). */\n markers(name: string, options?: MarkerLayerOptions): MarkerLayer;\n /** A named line layer (one GeoJSON source) — same style-first rule as `markers`. */\n line(name: string, options?: LineLayerOptions): LineLayer;\n /** Raw escape hatch: replace the data of any GeoJSON source in the style. */\n setData(source: string, geojson: object): this;\n flyTo(center: LngLat, options?: CameraMove): this;\n jumpTo(center: LngLat, options?: CameraMove): this;\n /** Fit the camera to these points (padding + the view padding respected). */\n fitPoints(points: LngLat[], options?: FitOptions): this;\n /** Content inset: the part of the view covered by your UI (`\"40%\"` = of the view's size).\n * Camera operations center inside the remaining area. */\n setPadding(padding: MapPaddingValues): this;\n getCamera(): Promise<MapCamera>;\n /** Move the user puck (the map draws it; the position comes from you — `Geolocation.watch`).\n * `null` hides it. */\n setUserLocation(lngLat: LngLat | null, options?: UserLocationOptions): this;\n}\n/**\n * Create a map view. `MapView.isSupported` reports whether this host registered a \"map\" view —\n * check it before offering the feature.\n */\nexport declare const MapView: {\n (options?: MapOptions): MapView;\n /** Whether this host registered a \"map\" view. */\n readonly isSupported: boolean;\n};\n","types/plugins/gen/map/sdk/map.gen.d.ts":"import { ViewChannel, type Json } from \"../../../../plugin\";\nimport type { LngLat, MapCamera, MapCameraMove, MapEvents, MapFitOptions, MapLayerKind, MapLayerOptions, MapPadding, MapParams, MapUserLocationOptions } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"map\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** Make sure the GeoJSON source `source` exists. A source the style declares is used as is (its\n * layers draw, only data flows); otherwise the half creates it with the default layers of `kind`.\n * Rejects with \"notReady\". */\nexport declare const ensureLayer: (view: ViewChannel<MapEvents>, source: string, kind: MapLayerKind, options?: MapLayerOptions) => Promise<void>;\nexport declare const removeLayer: (view: ViewChannel<MapEvents>, source: string) => Promise<void>;\n/** Replace the data of a GeoJSON source: a Feature or a FeatureCollection.\n * Rejects with \"notReady\". */\nexport declare const setData: (view: ViewChannel<MapEvents>, source: string, geojson: Json) => Promise<void>;\nexport declare const flyTo: (view: ViewChannel<MapEvents>, center: LngLat, options?: MapCameraMove) => Promise<void>;\nexport declare const jumpTo: (view: ViewChannel<MapEvents>, center: LngLat, options?: MapCameraMove) => Promise<void>;\n/** Fit the camera to the points.\n * Rejects with \"noPoints\". */\nexport declare const fitPoints: (view: ViewChannel<MapEvents>, points: LngLat[], options?: MapFitOptions) => Promise<void>;\n/** The part of the view covered by the app's UI; camera moves center inside the rest. */\nexport declare const setPadding: (view: ViewChannel<MapEvents>, padding: MapPadding) => Promise<void>;\n/** Rejects with \"notReady\". */\nexport declare const getCamera: (view: ViewChannel<MapEvents>) => Promise<MapCamera>;\n/** Move the user puck; null hides it. */\nexport declare const setUserLocation: (view: ViewChannel<MapEvents>, lngLat: LngLat | null, options?: MapUserLocationOptions) => Promise<void>;\n/** A method of the contract. */\nexport type Method = \"ensureLayer\" | \"removeLayer\" | \"setData\" | \"flyTo\" | \"jumpTo\" | \"fitPoints\" | \"setPadding\" | \"getCamera\" | \"setUserLocation\";\n/** Whether this host has the view \"map\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The view \"map\" with the wire's methods as its own. */\nexport declare class MapViewBase extends ViewChannel<MapEvents> {\n constructor(params?: MapParams);\n /** Make sure the GeoJSON source `source` exists. A source the style declares is used as is (its\n * layers draw, only data flows); otherwise the half creates it with the default layers of `kind`.\n * Rejects with \"notReady\". */\n ensureLayer(source: string, kind: MapLayerKind, options?: MapLayerOptions): Promise<void>;\n removeLayer(source: string): Promise<void>;\n /** Replace the data of a GeoJSON source: a Feature or a FeatureCollection.\n * Rejects with \"notReady\". */\n setData(source: string, geojson: Json): Promise<void>;\n flyTo(center: LngLat, options?: MapCameraMove): Promise<void>;\n jumpTo(center: LngLat, options?: MapCameraMove): Promise<void>;\n /** Fit the camera to the points.\n * Rejects with \"noPoints\". */\n fitPoints(points: LngLat[], options?: MapFitOptions): Promise<void>;\n /** The part of the view covered by the app's UI; camera moves center inside the rest. */\n setPadding(padding: MapPadding): Promise<void>;\n /** Rejects with \"notReady\". */\n getCamera(): Promise<MapCamera>;\n /** Move the user puck; null hides it. */\n setUserLocation(lngLat: LngLat | null, options?: MapUserLocationOptions): Promise<void>;\n}\n","types/plugins/gen/push/sdk/push.d.ts":"import type { PushEvents, PushPayload, PushRegisterOptions, PushRegistration, PushStatus } from \"../contract\";\nexport type { PushPayload, PushRegisterOptions, PushStatus };\nexport type PushEvent = keyof PushEvents;\n/**\n * Remote push notifications. `Push.isSupported` reports whether this host registered the\n * service — check it before offering notification features.\n */\nexport declare const Push: {\n /** Whether this host registered a \"push\" service. */\n readonly isSupported: boolean;\n /** Permission + registration state. Never prompts. */\n getStatus(): Promise<PushStatus>;\n /** Ask for permission (first time) and register this device → the opaque address your server\n * targets. Idempotent — safe to call every launch; rejects \"denied\" / \"unavailable\". */\n register(options?: PushRegisterOptions): Promise<PushRegistration>;\n /** Remove this device's registration (the address stops receiving). */\n unregister(): Promise<void>;\n /** The notification that cold-started this app run, or null. Stable across calls. */\n getLaunch(): Promise<PushPayload | null>;\n /** \"message\" = received while the app is open; \"tap\" = the user tapped one while it ran. */\n addEventListener(event: PushEvent, callback: (payload: PushPayload) => void): void;\n removeEventListener(event: PushEvent, callback: (payload: PushPayload) => void): void;\n};\n","types/plugins/gen/push/sdk/push.gen.d.ts":"import { ServiceChannel } from \"../../../../plugin\";\nimport type { PushEvents, PushParams, PushPayload, PushRegisterOptions, PushRegistration, PushStatus } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"push\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** Permission + registration state. Never prompts. */\nexport declare const getStatus: (service: ServiceChannel<PushEvents>) => Promise<PushStatus>;\n/** Ask for the permission (the first time) and register this device. Idempotent.\n * Rejects with \"denied\" / \"unavailable\". */\nexport declare const register: (service: ServiceChannel<PushEvents>, options?: PushRegisterOptions) => Promise<PushRegistration>;\n/** Remove this device's registration.\n * Rejects with \"unavailable\". */\nexport declare const unregister: (service: ServiceChannel<PushEvents>) => Promise<void>;\n/** The notification that cold-started this world, or null. Stable across calls. */\nexport declare const getLaunch: (service: ServiceChannel<PushEvents>) => Promise<PushPayload | null>;\n/** A method of the contract. */\nexport type Method = \"getStatus\" | \"register\" | \"unregister\" | \"getLaunch\";\n/** Whether this host has the service \"push\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The service \"push\" with the wire's methods as its own. */\nexport declare class PushBase extends ServiceChannel<PushEvents> {\n constructor(params?: PushParams);\n /** Permission + registration state. Never prompts. */\n getStatus(): Promise<PushStatus>;\n /** Ask for the permission (the first time) and register this device. Idempotent.\n * Rejects with \"denied\" / \"unavailable\". */\n register(options?: PushRegisterOptions): Promise<PushRegistration>;\n /** Remove this device's registration.\n * Rejects with \"unavailable\". */\n unregister(): Promise<void>;\n /** The notification that cold-started this world, or null. Stable across calls. */\n getLaunch(): Promise<PushPayload | null>;\n}\n","types/plugins/gen/qr-scanner/sdk/qr-scanner.d.ts":"import { type NativeView, type PresentOptions } from \"../../../../plugin\";\nexport interface QRScanner extends NativeView {\n /** Fires per decoded camera frame: the decoded string, or `null` for a frame with no readable\n * code (expect those repeatedly while the user aims). The same code can be reported more than\n * once — `close()` or debounce once you have what you need. */\n onScan(callback: (data: string | null) => void): this;\n /** Request the camera permission, then present the scanner. The current destination (and its\n * loading state) stays visible until the scanner is ready; rejects if the camera is denied,\n * the host can't scan, or another navigation superseded this one. */\n open(options?: PresentOptions): Promise<void>;\n}\n/**\n * Create a QR scanner view. `QRScanner.isSupported` reports whether this host can scan at all —\n * check it before offering the feature.\n */\nexport declare const QRScanner: {\n (): QRScanner;\n /** Whether this host registered a \"qrScanner\" view. */\n readonly isSupported: boolean;\n};\n","types/plugins/gen/qr-scanner/sdk/qr-scanner.gen.d.ts":"import { ViewChannel } from \"../../../../plugin\";\nimport type { QRScannerEvents, QRScannerParams } from \"../contract\";\n/** What the halves register under. */\nexport declare const NAME = \"qrScanner\";\n/** The contract's version: the highest `@since` of its members. */\nexport declare const VERSION = 1;\n/** A method of the contract. */\nexport type Method = never;\n/** Whether this host has the view \"qrScanner\" — and, given a method, a half new enough for it\n * (a method added after the first version of the contract is tagged `@since`). */\nexport declare const supports: (method?: Method) => boolean;\n/** The view \"qrScanner\" with the wire's methods as its own. */\nexport declare class QRScannerBase extends ViewChannel<QRScannerEvents> {\n constructor(params?: QRScannerParams);\n}\n","types/plugins/permission.d.ts":"export declare const _requestCameraPermission: () => Promise<void>;\n","types/plugins/service.d.ts":"export interface Service {\n /** Invoke a method on the service (`battery.call(\"level\")`). Arguments and the result are\n * JSON-serialized; rejects when the host has no such service or the method reports an\n * error. The host session opens lazily on the first call. */\n call(method: string, ...args: any[]): Promise<any>;\n /** Subscribe to an event the service emits while a session is open\n * (`battery.on(\"change\", data => …)`). Payloads are JSON-decoded. */\n on(event: string, callback: (data?: any) => void): this;\n /** Remove a previously added listener. */\n off(event: string, callback: (data?: any) => void): this;\n /** Close the host session (stops whatever the service was doing). Listeners stay\n * registered — a later `call()` opens a fresh session that delivers to them again. */\n close(): void;\n}\n/**\n * A host-registered headless service — the UI-less sibling of `NativeView`. Use it for\n * services without a typed wrapper: native code registered in your app shell\n * (`engine.registerService(\"app.battery\") { … }`) or a third-party plugin's channel.\n * **Host-optional** — gate on `Service.isSupported` (the web editor registers none of them).\n *\n * ```ts\n * if (Service.isSupported(\"app.battery\")) {\n * const battery = Service(\"app.battery\")\n * battery.on(\"change\", data => { level.text = data.level + \"%\" })\n * const { level } = await battery.call(\"level\")\n * }\n * ```\n */\nexport declare const Service: {\n (name: string, params?: any): Service;\n /** Whether this host registered a service under `name`. */\n isSupported(name: string): boolean;\n};\n","types/runtime/app.d.ts":"export type AppState = \"active\" | \"background\";\n/** `\"landscape\"` — either landscape direction (sensor landscape), `\"portrait\"` — upright only,\n * `\"auto\"` — released: the device's own rotation rules apply. */\nexport type OrientationLock = \"auto\" | \"portrait\" | \"landscape\";\ntype AppEventMap = {\n /** The app left the foreground (home button, tab hidden, another app on top). Delivered before\n * the host halts the frame loop — the last chance to persist state / pause work. */\n pause: () => void;\n /** The app returned to the foreground; frames are running again. */\n resume: () => void;\n /** A link arrived while the app was running (warm deep link). `app.launchUrl` is already\n * updated to the same value when this fires. */\n url: (url: string) => void;\n /** The on-screen keyboard changed. `height` mirrors `app.keyboardHeight` (the raw overlap, see\n * there); `duration` is the platform's keyboard animation duration in ms (0 where none) — pass\n * it to `animateTo` to move a composer in sync with the keyboard. */\n keyboard: (height: number, duration: number) => void;\n};\nexport declare const app: {\n /** The SDK this app was compiled with (semver, e.g. `\"2.0.0\"`). Its major is the bundle ↔ runtime\n * contract: a host runs only bundles of its own major, and the launchers send it as `?sdk=` when\n * they fetch a published bundle — the platform keeps one bundle per major. */\n sdkVersion: string;\n /** Current lifecycle state. `\"background\"` while the app is not the foreground app / the tab is\n * hidden. `\"active\"` on hosts that don't track it. */\n readonly state: AppState;\n /** The URL the app was (most recently) opened with — the deep link — or `null` for a plain\n * launch. Warm links update it and fire the `\"url\"` event. */\n readonly launchUrl: string | null;\n /** On-screen keyboard height in logical px currently overlapping the app viewport, `0` when\n * hidden. This is the RAW overlap, independent of the focused input's `keyboardShrink` policy —\n * with the default shrink the layout already avoids the keyboard; the main consumer is overlay\n * mode (`keyboardShrink: false`), e.g. a chat composer's `pb`. `0` on hosts without an\n * on-screen keyboard. */\n readonly keyboardHeight: number;\n /** Lock the screen orientation — `\"landscape\"` for a horizontal game (the device rotates to\n * landscape right away and stays there whichever way it is held), `\"portrait\"` for upright\n * only, `\"auto\"` to release. Call it once at startup; the lock is per app run (it resets\n * when the app quits or restarts), so there is nothing to undo. The rotation arrives as an\n * ordinary resize — layouts reflow, a scene's viewport follows. Silent no-op on hosts\n * without a rotatable screen (desktop, headless, web). */\n setOrientation(mode: OrientationLock): void;\n /** Re-run this app's bundle in a fresh world — the platform's `location.reload()`. Pass `url`\n * to reboot with different launch arguments (the new run reads them via `app.launchUrl`),\n * `null` to reboot with a cleared one, or omit it to replay the current one. No-op on hosts\n * without world control (headless). */\n restart(url?: string | null): void;\n /** Leave this app. Inside the LeCodes viewer that returns to the launcher (the LeCodes home\n * screen); a standalone-built app leaves to the platform instead — Android backgrounds it,\n * iOS ignores the call (the platform forbids programmatic exit). */\n quit(): void;\n /** Global back-press fallback (Android back button/gesture — iOS has no system back). Fires\n * only when nothing else consumed the press: no open widget/modal claimed it, the current\n * screen has no `onBack`, every pager is at its tab root and the router is at its\n * stack root. The place for app-wide policy — e.g. double-press-to-quit:\n *\n * ```ts\n * let armedAt = 0\n * app.onBack(() => {\n * if (Date.now() - armedAt < 2000) { app.quit(); return }\n * armedAt = Date.now()\n * toast(\"Press back again to exit\")\n * })\n * ```\n *\n * Replaces the previous handler; pass `null` to remove. */\n onBack(callback: (() => void) | null): void;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: (() => void) | null): void;\n addEventListener<E extends keyof AppEventMap>(event: E, callback: AppEventMap[E]): void;\n removeEventListener<E extends keyof AppEventMap>(event: E, callback: AppEventMap[E]): void;\n};\nexport {};\n","types/runtime/appEvents.d.ts":"type AppEventCallback = (data?: string) => void;\nexport declare const appEventsOn: (event: string, cb: AppEventCallback) => void;\nexport declare const appEventsOff: (event: string, cb: AppEventCallback) => void;\ntype KeyboardCallback = (height: number, duration: number) => void;\nexport declare const keyboardEventsOn: (cb: KeyboardCallback) => void;\nexport declare const keyboardEventsOff: (cb: KeyboardCallback) => void;\nexport {};\n","types/runtime/channel.d.ts":"export {};\n","types/runtime/clipboard.d.ts":"export declare const clipboard: {\n /** Put `text` on the system clipboard. Silent no-op on hosts without clipboard access. */\n write(text: string): void;\n /** Read text from the system clipboard. Rejects when the platform has no clipboard access, the\n * user denied it, or there is nothing readable. */\n read(): Promise<string>;\n};\n","types/runtime/datetime.d.ts":"export type Locale = \"en\" | \"ru\";\nexport type DateInput = Date | number | string | DateValue;\nexport type Unit = \"ms\" | \"second\" | \"minute\" | \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\n/**\n * An immutable moment in time — the value returned by [`date()`]. Wraps a single epoch-millisecond\n * scalar (`t`); every method returns a new `DateValue` or a plain scalar, never mutating. Construct\n * it with `date(...)`, not `new`.\n */\nexport declare class DateValue {\n /** Epoch milliseconds — the one canonical scalar. Prefer `valueOf()`; this is public so `date(a)`\n * can read it back cheaply and so tooling can treat it as the value's single component. */\n readonly t: number;\n constructor(ms: number);\n /**\n * Format against a `day.js`-style token pattern (default `\"D MMMM YYYY\"`). Locale defaults to the\n * current device language.\n *\n * Tokens: `YYYY`/`YY` year · `MMMM`/`MMM`/`MM`/`M` month · `DD`/`D` day · `dddd`/`ddd` weekday ·\n * `HH`/`H` 24-hour · `hh`/`h` 12-hour · `mm`/`m` minute · `ss`/`s` second · `A`/`a` AM/PM.\n *\n * ```ts\n * date().format() // \"10 July 2026\" / \"10 июля 2026\"\n * date(ts).format(\"DD.MM.YYYY HH:mm\") // \"10.07.2026 14:05\"\n * date(ts).format(\"MMMM YYYY\", \"ru\") // \"Июль 2026\" (nominative — no day token)\n * ```\n */\n format(pattern?: string, locale?: Locale): string;\n /**\n * Human relative time vs `now` (default: the current time) — \"5 minutes ago\", \"in 2 days\",\n * \"5 минут назад\", \"через 2 дня\". Reads as \"just now\" under ~45 seconds; handles Russian number\n * agreement (`1 минуту` / `2 минуты` / `5 минут`). Locale defaults to the device language.\n */\n timeAgo(locale?: Locale, now?: DateInput): string;\n /** Add `n` of a unit, returning a new value. Linear units (`ms`…`week`) are scalar ms math;\n * `month`/`year` are calendar-aware (clamp on short months, like day.js). */\n add(n: number, unit: Unit): DateValue;\n /** Subtract `n` of a unit. Equivalent to `add(-n, unit)`. */\n subtract(n: number, unit: Unit): DateValue;\n /** Snap down to the start of a unit (local time): start of day/hour/month/year, etc. */\n startOf(unit: Unit): DateValue;\n /** Snap up to the end of a unit (local time): the last millisecond of the day/hour/month/… */\n endOf(unit: Unit): DateValue;\n /** Epoch milliseconds. Enables `+date(x)`, `date(a) < date(b)`, `date(a) - date(b)` via coercion. */\n valueOf(): number;\n /** Whole seconds since the epoch (Unix time). */\n unix(): number;\n /** Signed difference to `other`, in whole `unit`s (default `ms`), truncated toward zero. */\n diff(other: DateInput, unit?: Unit): number;\n isBefore(other: DateInput): boolean;\n isAfter(other: DateInput): boolean;\n isSame(other: DateInput): boolean;\n year(): number;\n /** 0-based month (0 = January), matching `Date.getMonth`. */\n month(): number;\n /** Day of the month, 1–31. */\n day(): number;\n /** Day of the week, 0 (Sunday)–6 (Saturday), matching `Date.getDay`. */\n weekday(): number;\n hour(): number;\n minute(): number;\n second(): number;\n /** A native `Date` snapshot of this value. */\n toDate(): Date;\n}\n/**\n * Create a `DateValue` — a locale-aware, immutable moment, dayjs-style. Accepts a `Date`, a\n * millisecond timestamp (`Date.now()`), a parseable string, or another `DateValue`; with no argument\n * it's the current time. Chain arithmetic and finish with `format` / `timeAgo`, both of which\n * understand **English** and **Russian** and default to the current device language\n * ([`device.language`](../runtime/device.ts)).\n *\n * ```ts\n * date().format(\"dddd, D MMMM\") // \"Friday, 10 July\" / \"пятница, 10 июля\"\n * date(ts).timeAgo() // \"5 minutes ago\" / \"5 минут назад\"\n * date().add(3, \"day\").startOf(\"day\").format(\"D MMMM\")\n * date(a).diff(b, \"hour\") // signed whole hours\n * date(a).isBefore(b) // boolean\n * ```\n */\nexport declare const date: (value?: DateInput) => DateValue;\n","types/runtime/device.d.ts":"import { Quat } from \"../math/quat\";\nimport { Vec3 } from \"../math/vec\";\ntype ResizeCallback = (width: number, height: number) => void;\ntype HdrChangeCallback = (headroom: number) => void;\ntype DeviceEventMap = {\n resize: ResizeCallback;\n /** Connectivity came back (best-effort, navigator.onLine semantics). */\n online: () => void;\n /** Connectivity was lost. */\n offline: () => void;\n /** The headroom the 3D engine renders to moved (`device.hdr.headroom`): the display ramped up to\n * its peak after launch, brightness changed, the window went to another screen. */\n hdrchange: HdrChangeCallback;\n};\n/** Semantic haptic styles for `device.vibrate`. Impact styles (`light`/`medium`/`heavy`/`soft`/\n * `rigid`) are a physical \"tap\" of varying weight; notification styles (`success`/`warning`/`error`)\n * cue an outcome; `selection` is a light tick for a value change. Chosen to map 1:1 onto iOS\n * `UIFeedbackGenerator` and, on Android, `HapticFeedbackConstants` / `VibrationEffect` — so the same\n * call feels native everywhere, rather than a duration that only web/Android can honor. */\nexport type HapticStyle = \"light\" | \"medium\" | \"heavy\" | \"soft\" | \"rigid\" | \"success\" | \"warning\" | \"error\" | \"selection\";\n/** Options for `device.motion.start`. */\nexport interface MotionOptions {\n /** Sensor update interval in seconds (default 1/60). The sensor fuses at ≥ this rate in the\n * background; you poll the freshest sample each frame, so this is a floor, not a sync. */\n interval?: number;\n /** Frame the readables are delivered in. \"world\" (default): engine Y-up, screen-oriented — drops\n * straight into `camera.quaternion` / any node. \"device\": the raw sensor frame, no conversion. */\n frame?: \"world\" | \"device\";\n}\nexport declare const device: {\n /** Which INPUT MODEL the app is running under — the thing to branch on when a build needs\n * mouse-look instead of on-screen sticks. It is not the OS name: a Mac reports `\"desktop\"`,\n * like Windows and Linux do (the OS/version detail is host-side, not here). */\n readonly platform: \"web\" | \"android\" | \"ios\" | \"desktop\" | string;\n readonly language: string;\n /** Display device-pixel ratio (physical px per logical/CSS px): 1 on standard displays, 2–3 on\n * retina / iOS. Bake a Canvas at this ratio for crisp output without hardcoding, e.g.\n * `new Canvas(w, h, { pixelRatio: device.pixelRatio })`. NOTE: the web 2D/GL surface currently\n * renders at logical resolution, so on web this only helps UI canvases / is forward-looking for\n * 2D; on iOS (physical surface) it makes 2D canvases crisp. Falls back to 1 if the host omits it. */\n readonly pixelRatio: number;\n /** Current display width in logical px — the same value the \"resize\" event delivers, but readable at\n * any time (not only inside the listener). 0 until the host has reported a size. */\n readonly width: number;\n /** Current display height in logical px — the same value the \"resize\" event delivers, readable at any\n * time. 0 until the host has reported a size. */\n readonly height: number;\n /** Opt into the precise-touch system where the platform supports it. OFF by default. When on, fast\n * strokes are sampled at the touch digitizer's full rate (iOS coalesced touches, ≈120–240 Hz) instead\n * of once per display frame (~60 Hz), so a pointer-heavy app (drawing, handwriting, dragging) gets more\n * points and smoother lines. Leave it off for tap/button UIs. No-op on hosts without a coalesced-input\n * concept (web already coalesces pointermove; headless). */\n setPreciseTouch(enabled: boolean): void;\n /** Fire a one-shot haptic of the given semantic `style` (default `\"medium\"`) — a physical tap on\n * supported hardware (iOS Taptic Engine, Android vibrator). Chosen by meaning, not duration, so it\n * feels native on each platform; see {@link HapticStyle}. Host-gated: a silent no-op where there's\n * no haptic hardware (iPad, older iPhones, web, headless). */\n vibrate(style?: HapticStyle): void;\n /** The host's performance overlay: one line over everything with the frames per second the\n * display actually got, how evenly they came (`66 fps · 73% even` is judder, `60 fps · 100% even`\n * is smooth), and the GPU's and the main thread's milliseconds per frame. The host measures and\n * draws it itself about once a second — nothing of it runs in the app's JS, so it does not change\n * what it measures. It belongs to the host, not to the project: it stays on when another project\n * is opened. Reads `false`, and writing does nothing, on hosts without one (web, headless). */\n statsOverlay: boolean;\n /** Device-orientation sensor (gyro + accelerometer, fused) for tilt/steering and magic-window /\n * 360° panoramas. Poll `attitude` / `gravity` inside setLoop; they return the freshest fused\n * sample, so the sensor rate need not match your frame rate. Host-gated: a no-op with no sensor. */\n motion: {\n /** Whether this device has the motion sensors at all (no gyro → false; iPad/older, web, headless). */\n readonly available: boolean;\n /** Whether updates are currently running (start succeeded and stop hasn't been called). */\n readonly enabled: boolean;\n /** Begin sensor updates. Resolves to whether it actually started (false = no sensor / denied).\n * Async so a web host can await its permission prompt; native resolves immediately. */\n start(options?: MotionOptions): Promise<boolean>;\n /** Stop sensor updates and release the sensor (battery). */\n stop(): void;\n /** Capture the current heading as \"forward\" — a yaw-only recenter (pitch/roll stay gravity-\n * referenced, so the horizon stays level). No-op in the \"device\" frame. */\n recenter(): void;\n /** The device's current orientation as a `Quat`. In the \"world\" frame (default) it's engine Y-up\n * and screen-oriented, so `camera.quaternion = device.motion.attitude` is a complete magic-window\n * / panorama camera. `Quat.identity` until the first sample arrives / when not running. */\n readonly attitude: Quat;\n /** Gravity direction for tilt controls. In the \"world\" frame it's SCREEN space (x → right, y →\n * down, matching clientX/clientY), orientation-aware — a 2D game reads `gravity.x / gravity.y`.\n * `(0,0,0)` when not running. */\n readonly gravity: Vec3;\n };\n /** The display's extended dynamic range — HDR. On a screen with headroom above SDR white (Apple's\n * XDR panels; the macOS host today) the 3D surface is float and the engine renders past 1.0:\n * 1.0 is the white of the UI and of a diffuse white surface, and the sun, emissives and speculars\n * climb up to `headroom` times that. Everywhere else it is SDR: `available` false, `headroom` 1,\n * the look setters remembered but invisible.\n *\n * Branch content on `available`, not on `headroom` — the live value ramps up from 1 over the\n * first seconds after launch and follows the brightness keys. Particle `emissive` is the thing\n * to raise: it is in post-exposure units (1 = white on screen) and everything above that clips on\n * SDR, so an HDR display is the only place a fireball peaking at 8 reads as one. */\n hdr: {\n /** Whether the surface can show anything above SDR white at all (`maxHeadroom > 1`). */\n readonly available: boolean;\n /** The peak the display can reach, as a multiple of SDR white (a 1600-nit XDR panel reports up\n * to 16). Constant for the surface; 1 on SDR. */\n readonly maxHeadroom: number;\n /** The headroom the engine renders to right now — the screen's current peak as a multiple of SDR\n * white, quantised to half-stops. Moves with brightness and the screen under the window\n * (`hdrchange` event); never below 1. */\n readonly headroom: number;\n /** How much of the picture reaches for the headroom, 0..1 (default 0.35). 0 touches only what\n * SDR clipped — faithful to the SDR grade, but a mostly-mid-tone frame then looks flat next to\n * the one bright spot; 1 lifts nearly everything above black toward the peak. A sunlit exterior\n * takes 1, a dim interior wants less. A host may pin it (`LECODES_HDR_STRENGTH`). */\n strength: number;\n /** Where white lands, as a multiple of SDR white, 1..8 (default 1) — the \"HDR brightness\" of a\n * console game's calibration screen, where paper white sits at ~200 nits against SDR's ~100.\n * It scales the WHOLE picture: at 1 a white wall is as bright as the UI's white, at 2 it is\n * twice that, and highlights still climb above it (the engine keeps `headroom / paperWhite` for\n * them, clamped at the peak). `strength` decides how much of the picture reaches for the\n * peak; this decides where the picture starts. 1.5–2 is the console norm; a game that wants to\n * read as \"HDR on\" rather than \"SDR with a brighter sun\" wants this over `strength`. A host may\n * pin it (`LECODES_HDR_PAPER_WHITE`). */\n paperWhite: number;\n };\n /** Current connectivity — best-effort navigator.onLine semantics: `false` only when the platform\n * is sure there's no network. `true` on hosts that don't track it. Change events: `\"online\"` /\n * `\"offline\"`. */\n readonly online: boolean;\n addEventListener<E extends keyof DeviceEventMap>(channel: E, callback: DeviceEventMap[E]): void;\n removeEventListener<E extends keyof DeviceEventMap>(channel: E, callback: DeviceEventMap[E]): void;\n};\nexport {};\n","types/runtime/fetch.d.ts":"export type FetchOptions = {\n body?: any;\n method?: string;\n headers?: Record<string, string>;\n useOnce?: boolean;\n onProgress?: (progress: {\n loaded: number;\n total?: number;\n }) => void;\n};\nexport interface FetchResponse {\n readonly status: number;\n json<T = any>(): T;\n text(): string;\n /** @deprecated A no-op: the body is freed with the response's handle (owned handles). Apps written\n * against the pre-owned SDK still call it after `text()` / `json()`; remove the call. */\n dispose(): void;\n}\nexport declare const fetch: (url: string, options?: FetchOptions) => Promise<FetchResponse>;\nexport declare const fetchLocal: (path: string) => FetchResponse;\n/** A handle to a picked / fetched file (see openFilePicker). */\nexport declare class File {\n readonly name: string;\n readonly size: number;\n constructor(systemId: number, name: string, size: number);\n}\ntype FormDataValue = string | number | boolean | File | FetchResponse;\nexport declare class FormData {\n private _entries;\n append(name: string, value: FormDataValue, filename?: string): void;\n delete(name: string): void;\n}\nexport {};\n","types/runtime/files.d.ts":"import { File, type FetchResponse } from \"./fetch\";\ntype OpenFilePickerOptions = {\n accept?: string;\n};\nexport declare function openFilePicker(options?: OpenFilePickerOptions & {\n multiple?: false;\n}): Promise<File | null>;\nexport declare function openFilePicker(options: OpenFilePickerOptions & {\n multiple: true;\n}): Promise<File[]>;\n/** Anything writable as-is: text, raw bytes, or a buffer the host already holds\n * (a picked `File`, a `FetchResponse`, a `Canvas.toFile()` snapshot). */\nexport type FileData = string | Uint8Array | ArrayBuffer | File | FetchResponse;\n/** One directory entry, as `files.ls` / `files.stat` report it. */\nexport type FileEntry = {\n /** The last path segment. */\n name: string;\n /** Relative to the listed directory, `/`-separated — equal to `name` unless the listing was\n * recursive. Join it onto the directory you listed to read the file. */\n path: string;\n kind: \"file\" | \"dir\";\n /** Bytes; 0 for a directory. */\n size: number;\n /** Last modification, ms since the epoch (a `Date` value). */\n modified: number;\n};\nexport declare const files: {\n /** Is there a filesystem here (desktop)? False on web/mobile, where every other call rejects. */\n readonly supported: boolean;\n /** Replace the file's contents, creating the parent folders on the way. */\n write(path: string, data: FileData): Promise<void>;\n /** Add to the end of the file, creating it (and the parent folders) when it isn't there yet. */\n append(path: string, data: FileData): Promise<void>;\n /** The whole file as UTF-8 text — null when there is no such file. */\n readText(path: string): Promise<string | null>;\n /** The whole file as bytes — null when there is no such file. */\n readBytes(path: string): Promise<Uint8Array | null>;\n /** Delete a file, or a directory (empty, or any directory with `{ recursive: true }`). Deleting\n * something already gone is success — what's promised is that the path is free afterwards. */\n rm(path: string, options?: {\n recursive?: boolean;\n }): Promise<void>;\n /** Create a directory and any missing parents. An existing directory is fine. */\n mkdir(path: string): Promise<void>;\n /** The entries of a directory, sorted by path — null when there is no such directory (an empty\n * one is `[]`, so `(await files.ls(\"saves\")) ?? []` covers both). `{ recursive: true }` walks\n * the subfolders too; each entry's `path` is then relative to the directory listed. A path that\n * is a file, not a directory, rejects. Filter in JS — `entries.filter(e => e.name.endsWith(\".json\"))`. */\n ls(path: string, options?: {\n recursive?: boolean;\n }): Promise<FileEntry[] | null>;\n /** What is at `path`: a file or a directory entry (`path` equal to `name`), or null when nothing\n * is there — `(await files.stat(p)) !== null` is the exists check. */\n stat(path: string): Promise<FileEntry | null>;\n};\nexport {};\n","types/runtime/input.d.ts":"/** Continuous channel ids — the `_creatorInput.read` contract (sdk/src/bridges/input.d.ts). */\nexport declare const InputChannel: {\n readonly MouseX: 0;\n readonly MouseY: 1;\n readonly MouseDX: 2;\n readonly MouseDY: 3;\n readonly WheelX: 4;\n readonly WheelY: 5;\n readonly PointerLocked: 6;\n readonly GamepadCount: 7;\n readonly PointerOnUI: 8;\n readonly GamepadBase: 16;\n readonly GamepadStride: 16;\n readonly PadConnected: 0;\n readonly PadLeftX: 1;\n readonly PadLeftY: 2;\n readonly PadRightX: 3;\n readonly PadRightY: 4;\n readonly PadLeftTrigger: 5;\n readonly PadRightTrigger: 6;\n};\nexport type InputEventName = \"keydown\" | \"keyup\" | \"gamepadconnected\" | \"gamepaddisconnected\";\n/** `keydown` / `keyup` payload. `code` is the same string `Input.key()` takes. */\nexport interface InputKeyEvent {\n readonly type: \"keydown\" | \"keyup\";\n /** Button code: KeyboardEvent.code ('KeyW', 'Space'), 'MouseLeft|Right|Middle|Back|Forward', or\n * 'GamepadSouth|East|West|North|L1|R1|L2|R2|Select|Start|L3|R3|Up|Down|Left|Right'. */\n readonly code: string;\n /** Which device: 'keyboard' | 'mouse' | 'gamepad'. */\n readonly source: \"keyboard\" | \"mouse\" | \"gamepad\";\n /** Pad index (0..3) for gamepad buttons, undefined otherwise. */\n readonly gamepad?: number;\n /** OS auto-repeat keydown (key still held) — ignore for one-shot actions. */\n readonly repeat: boolean;\n}\nexport interface InputGamepadEvent {\n readonly type: \"gamepadconnected\" | \"gamepaddisconnected\";\n readonly gamepad: number;\n}\ntype Listener<E> = (e: E) => void;\ntype InputEventMap = {\n keydown: InputKeyEvent;\n keyup: InputKeyEvent;\n gamepadconnected: InputGamepadEvent;\n gamepaddisconnected: InputGamepadEvent;\n};\n/** Mouse state — polled. Position is the cursor inside the viewport in logical px; `delta` is the\n * motion during the previous frame (raw where the OS offers it) and keeps counting while locked —\n * that's FPS look. Hosts without a mouse report zeros. */\nexport declare const mouse: {\n readonly position: {\n x: number;\n y: number;\n };\n readonly delta: {\n x: number;\n y: number;\n };\n /** Wheel notches during the previous frame (+y = wheel toward you / scroll down). */\n readonly wheel: {\n x: number;\n y: number;\n };\n /** Pointer lock: cursor hidden + confined, `delta` keeps flowing. Web grants it only from a user\n * gesture (call it in a 'keydown' handler for MouseLeft); hosts drop it on focus loss and\n * re-acquire on focus. Escape does NOT unlock by itself on native hosts — call `unlock()`. */\n readonly locked: boolean;\n /** The primary button went down on a UI element (a button, a scrollable, an input, a modal\n * backdrop) and is still held. Stays true wherever the cursor drifts until the release, so\n * `if (!Input.mouse.onUI) look(Input.mouse.delta)` never turns a HUD drag into camera look.\n * Always false while `locked`. A press that fell through to the scene reads false. */\n readonly onUI: boolean;\n lock(): boolean;\n unlock(): void;\n};\nexport type GamepadAxisName = \"leftX\" | \"leftY\" | \"rightX\" | \"rightY\" | \"leftTrigger\" | \"rightTrigger\";\nexport interface GamepadState {\n readonly index: number;\n readonly connected: boolean;\n /** Stick axes −1..1 (+Y = down, like the web Gamepad API), triggers 0..1. `deadzone` (default\n * 0.15) zeroes small stick drift — pass 0 for the raw value. */\n axis(name: GamepadAxisName, deadzone?: number): number;\n /** Held? Same as `Input.key(code, index)`. */\n button(code: string): boolean;\n /** Rumble: `strong` = the heavy low-frequency motor, `weak` = the light high-frequency one, both\n * 0..1, for `durationMs` (default 200, hosts cap at 5000). A new call replaces the running\n * effect. The host stops the motors by itself — after the duration, on focus loss and when the\n * project is swapped — so there is nothing to clean up. False when the pad or host has no motors. */\n rumble(strong: number, weak?: number, durationMs?: number): boolean;\n /** Stop the running rumble now. */\n stopRumble(): void;\n}\nexport declare const Input: {\n /**\n * Is a button held? `code` is the physical key (`KeyboardEvent.code`: 'ArrowRight', 'KeyW',\n * 'Space'), a mouse button ('MouseLeft', 'MouseRight', 'MouseMiddle') or a gamepad button\n * ('GamepadSouth' = A/Cross, 'GamepadR2' = right trigger as a button …). Poll inside setLoop for\n * frame-independent movement. `gamepad` scopes a Gamepad* code to one pad; omitted = any pad.\n */\n key(code: string, gamepad?: number): boolean;\n /** Listen for a discrete input moment. `keydown`/`keyup` cover EVERY button — keyboard, mouse,\n * gamepad — filter on `e.code`. Use these for one-shot actions (jump, shoot, charge-release);\n * `Input.key` for continuous ones (walk). */\n on<K extends InputEventName>(name: K, listener: Listener<InputEventMap[K]>): void;\n off<K extends InputEventName>(name: K, listener: Listener<InputEventMap[K]>): void;\n mouse: {\n readonly position: {\n x: number;\n y: number;\n };\n readonly delta: {\n x: number;\n y: number;\n };\n /** Wheel notches during the previous frame (+y = wheel toward you / scroll down). */\n readonly wheel: {\n x: number;\n y: number;\n };\n /** Pointer lock: cursor hidden + confined, `delta` keeps flowing. Web grants it only from a user\n * gesture (call it in a 'keydown' handler for MouseLeft); hosts drop it on focus loss and\n * re-acquire on focus. Escape does NOT unlock by itself on native hosts — call `unlock()`. */\n readonly locked: boolean;\n /** The primary button went down on a UI element (a button, a scrollable, an input, a modal\n * backdrop) and is still held. Stays true wherever the cursor drifts until the release, so\n * `if (!Input.mouse.onUI) look(Input.mouse.delta)` never turns a HUD drag into camera look.\n * Always false while `locked`. A press that fell through to the scene reads false. */\n readonly onUI: boolean;\n lock(): boolean;\n unlock(): void;\n };\n /** Gamepad `index` (0..3). Always returns an object — check `.connected`. */\n gamepad(index?: number): GamepadState;\n /** Indices of the currently connected gamepads. */\n gamepads(): number[];\n /** @internal — hosts/tests: deliver an event exactly as the host listener would. */\n _emit(kind: number, code: string, gamepad: number, repeat: number): void;\n};\nexport {};\n","types/runtime/media.d.ts":"import { Emitter } from \"../core/events\";\nimport { Texture } from \"../gl/Texture\";\ntype MediaEvents = {\n /** Fired at each loop boundary while `loop` is true. */\n loopReached: () => void;\n /** Fired once when playback reaches the end while `loop` is false. */\n completed: () => void;\n};\ndeclare abstract class MediaPlayer extends Emitter<MediaEvents> {\n protected _src: string;\n private _playing;\n private _loop;\n private _volume;\n play(): void;\n pause(): void;\n /** Pause and rewind to the start. */\n stop(): void;\n get playing(): boolean;\n set playing(value: boolean);\n get volume(): number;\n set volume(value: number);\n get loop(): boolean;\n set loop(value: boolean);\n /** Current playback position, in seconds. Settable to seek. */\n get time(): number;\n set time(value: number);\n /** Total media length in seconds (0 until metadata has loaded). */\n get duration(): number;\n /** @deprecated There is nothing to dispose — a player the app stops referencing is released by\n * the runtime (a playing one at its end). Kept as `stop()` so old code still silences the player;\n * call `stop()` / `pause()` instead. */\n dispose(): void;\n}\nexport declare class AudioPlayer extends MediaPlayer {\n constructor(src?: string);\n}\nexport declare class VideoPlayer extends MediaPlayer {\n constructor(src?: string);\n /** A 3D Texture that samples this video (e.g. for a Material.video()). Owned by the player. */\n get texture(): Texture;\n}\nexport {};\n","types/runtime/misc.d.ts":"import type { ColorInput } from \"../core/color\";\n/** Show a transient toast notification. */\nexport declare const toast: (msg: string) => void;\n/** Open `url` in the system browser / external handler (fire-and-forget, like `share`). Silent\n * no-op on hosts without one (headless). */\nexport declare const openURL: (url: string) => void;\nexport type SvgSourceValue = {\n readonly svg: string;\n /** The source-level tint (a mask recolor under the `tintColor` style, which wins): any color, or\n * a theme `var(--…)`. */\n tintColor: ColorInput | null;\n};\n/** Wrap raw SVG XML so it can be used as an image source. */\nexport declare const SvgSource: (svg: string) => SvgSourceValue;\n/** The type of the value: what `SvgSource(xml)`, `assetIcon(\"lucide:bell\")` and `asset(\"./logo.svg\")`\n * all return, and what `UIImage` / `bgImage` take — ONE name for an SVG image source, global to a\n * project like the function (host.d.ts names it for the macros). */\nexport type SvgSource = SvgSourceValue;\n","types/runtime/net.d.ts":"import { Emitter } from \"../core/events\";\ntype SocketEvents = {\n open: () => void;\n message: (data: any) => void;\n close: (code?: number) => void;\n error: () => void;\n};\nexport declare class WebSocket extends Emitter<SocketEvents> {\n private _id;\n constructor(url: string);\n /** Send a text frame. */\n send(message: string): void;\n close(): void;\n private _onMessage;\n}\nexport {};\n","types/runtime/rpc.d.ts":"/**\n * Client transport for the app backend (docs/backend-plan.md §3.2 / §3.3). The compiler replaces\n * every `*.server.ts` module in the client bundle with a stub whose exports are built by the three\n * globals below — user code never calls them; it imports the server function and calls it.\n *\n * export const listNotes = __rpc(\"<serverUrl>\", \"notes.server.ts#listNotes\")\n * export const chat = __channel(\"<serverUrl>\", \"chat.server.ts#chat\")\n * export const db = __serverOnly(\"schema.server.ts#db\")\n *\n * Wire (implemented by the runner):\n * POST <serverUrl>/api/<id> body {\"args\":[…]}, `authorization: Bearer <session>` when known\n * — with a `File` among the arguments: multipart, the field `args` is\n * that JSON with `{\"$file\": <i>}` where the file stood, `file<i>` the files\n * → 200 {\"ok\":true,\"result\":…,\"session\"?:\"…\"} | {\"ok\":false,\"status\":n,\"message\":\"…\",\"session\"?:\"…\"}\n * WS <serverUrl>/ws the channel socket — its frames are ./wire.ts\n *\n * The session token is transport-owned (cookie-like): stored under `lecodes.session:<serverUrl>` in\n * localStorage, sent on every call and on the socket, replaced whenever a response carries `session`.\n * User code never sees it — \"am I logged in\" is an endpoint (`me()`), see the plan.\n */\nimport type { ChannelSubscription } from \"../server/channel\";\n/** Rejection value of a failed endpoint call: `status` mirrors the server's `ApiError`\n * (0 = the request itself failed: no network / no server). */\nexport declare class RpcError extends Error {\n readonly status: number;\n constructor(status: number, message: string);\n}\n/** Build the client proxy of endpoint `id`. Positional args travel as a JSON array. */\nexport declare const __rpc: (serverUrl: string, id: string) => (...args: unknown[]) => Promise<any>;\n/** A server-only export (db, models, helpers) referenced from client code: any use throws. */\nexport declare const __serverOnly: (id: string) => any;\n/**\n * Build the client proxy of channel `id` — what a `channel()` export of a `*.server.ts` file is in\n * the app (its type is the server's: src/server/channel.ts). `subscribe([...args,] handler, options?)`:\n * what stands before the handler travels to the channel's `groupBy`.\n */\nexport declare const __channel: (serverUrl: string, id: string) => {\n subscribe(...all: unknown[]): ChannelSubscription;\n publish(): never;\n};\n","types/runtime/service.d.ts":"export {};\n","types/runtime/share.d.ts":"import type { File, FetchResponse } from \"./fetch\";\nexport declare function share(media: File | FetchResponse, text?: string): void;\n","types/runtime/storage.d.ts":"export declare const localStorage: {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n};\n","types/runtime/touch.d.ts":"export declare class ClickEvent<T = any> {\n readonly type = \"click\";\n readonly pointerId: number;\n readonly clientX: number;\n readonly clientY: number;\n /** World-space hit position (2D scenes only; undefined in 3D). */\n worldX?: number;\n worldY?: number;\n target: T;\n constructor(clientX: number, clientY: number, pointerId: number);\n}\nexport interface TrackHandler {\n onMove?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onEnd?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onCancel?(): void;\n claim?: boolean | \"pan-x\" | \"pan-y\" | \"pan-down\" | \"pan-up\" | \"pan-left\" | \"pan-right\";\n}\nexport declare class TouchStartEvent<T = any> {\n readonly type = \"touchstart\";\n readonly pointerId: number;\n readonly clientX: number;\n readonly clientY: number;\n /** World-space hit position (2D scenes only; undefined in 3D). */\n worldX?: number;\n worldY?: number;\n target: T;\n constructor(clientX: number, clientY: number, pointerId: number);\n /** Capture subsequent moves/end for this pointer (drag/pan gestures). */\n track(handler: TrackHandler): void;\n}\n/** Delivered to a `UIButton` `onLongPress` handler when a finger is held on the button past the\n * host's long-press threshold. Like `TouchStartEvent` it can `track(...)` the rest of the gesture —\n * so the common \"press-and-hold, then drag to move\" flow is one handler: start the drag from here. */\nexport declare class LongPressEvent<T = any> {\n readonly type = \"longpress\";\n readonly pointerId: number;\n readonly clientX: number;\n readonly clientY: number;\n /** World-space hit position (2D scenes only; undefined in 3D). */\n worldX?: number;\n worldY?: number;\n target: T;\n constructor(clientX: number, clientY: number, pointerId: number);\n /** Capture subsequent moves/end for this pointer — drag the element after the hold. */\n track(handler: TrackHandler): void;\n}\n/** What a hover `track()` takes: the cursor's moves inside the element (only delivered when\n * `onMove` is present — otherwise the host never crosses into JS for them), `onEnd` when it\n * leaves (with the last position), `onCancel` when the element went away underneath it. No\n * `claim`: a hover competes with nothing. */\nexport interface HoverTrackHandler {\n onMove?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onEnd?(pos: {\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n }): void;\n onCancel?(): void;\n}\n/** Delivered to a `UIButton` `onMouseEnter` handler when a mouse cursor (no button) enters the\n * button. There is no separate leave event: `ev.track({ onEnd })` follows this hover to its end,\n * `onMove` follows the cursor inside — the visual state itself is the reserved `$hovered` class.\n * Touch never produces one. */\nexport declare class MouseEnterEvent<T = any> {\n readonly type = \"mouseenter\";\n readonly clientX: number;\n readonly clientY: number;\n target: T;\n constructor(clientX: number, clientY: number);\n /** Follow this hover: moves inside the element, its end (the cursor left), its cancel. */\n track(handler: HoverTrackHandler): void;\n}\n","types/runtime/wire.d.ts":"/**\n * The frames of the channel socket (`<serverUrl>/ws`) — the ONE description both ends are written\n * against: the client transport (./rpc.ts) and the server's hub (../server/channelHub.ts, which the\n * runner and the local backend of `lecodes dev` both run). JSON text frames, one per message.\n *\n * → hello who is on this socket. Sent first, and again whenever the session changes: the server\n * then DROPS the socket's subscriptions (they were granted to someone else) and the\n * client sends them again, under new ids.\n * → sub subscribe to channel `ch`; `args` are what the app passed to `subscribe` before the\n * handler — the channel's `groupBy` reads them.\n * → unsub\n * ← session a token minted while the socket was served (the first contact of a guest): the client\n * stores it; nothing is dropped, the server already has it.\n * ← ok the subscription stands; `group` is where the server put it (null = a channel without\n * groups). The client learns its group only here — it never names one.\n * ← err refused (a hook threw) — the subscription is gone.\n * ← ev one published message, addressed by channel + group so the server sends one frame to\n * every socket of a group; the client hands it to each of its subscriptions there.\n *\n * A group's value is not a secret: its subscriber is told it.\n */\n/** What `groupBy` may answer. `42` and `\"42\"` are two groups. */\nexport type ChannelGroup = string | number;\nexport type ClientFrame = {\n t: \"hello\";\n session: string | null;\n} | {\n t: \"sub\";\n id: number;\n ch: string;\n args: unknown[];\n} | {\n t: \"unsub\";\n id: number;\n};\nexport type ServerFrame = {\n t: \"session\";\n session: string;\n} | {\n t: \"ok\";\n id: number;\n group: ChannelGroup | null;\n} | {\n t: \"err\";\n id: number;\n status: number;\n message: string;\n} | {\n t: \"ev\";\n ch: string;\n group: ChannelGroup | null;\n data: unknown;\n};\n","types/scene/defineScene.d.ts":"import { use, ref, make, type AspectEntry, type MakeEntry as SharedMakeEntry } from \"./grammar\";\nimport type { Vec3Like } from \"../math/vec\";\nimport { Scene, type SceneOptions } from \"../gl/Scene\";\nimport { Node } from \"../gl/Node\";\nimport { Mesh } from \"../gl/Mesh\";\nimport { Model } from \"../gl/Model\";\nimport { type LightmapTransmit } from \"../gl/Lightmap\";\nimport { type FoliageOptions } from \"../gl/Foliage\";\nimport { type TerrainLayer, type TerrainRegion, type TerrainOptions } from \"../gl/terrain/Terrain\";\nimport { Light, type SunOptions } from \"../gl/Light\";\nimport { type MaterialDef } from \"./material\";\nimport type { CapsuleOptions, CylinderOptions, PlaneOptions, SphereOptions } from \"../gl/Geometry\";\nimport { GizmoBuffer } from \"./gizmos\";\nexport type MeshDef = {\n kind: \"box\";\n size?: Vec3Like | number;\n} | ({\n kind: \"sphere\";\n} & SphereOptions) | ({\n kind: \"cylinder\";\n} & CylinderOptions) | ({\n kind: \"capsule\";\n} & CapsuleOptions) | ({\n kind: \"plane\";\n} & PlaneOptions);\nexport type LightDef = {\n kind: \"sun\";\n} & SunOptions;\n/** A stamp: the terrain conforms to another node of this file (a road) at load — see Terrain.conform. */\nexport type TerrainStampDef = {\n /** Path of the node (a Mesh, a Model, or a node holding them) the ground hugs. */\n node: string;\n offset?: number;\n falloff?: number;\n mode?: \"both\" | \"lower\" | \"raise\";\n};\n/** The `terrain: {}` source block (docs/terrain-plan.md §3.3): a `.terrain` file OR a flat grid to\n * generate from, its layers, and the stamps / holes applied at load (in order, after every node of the\n * file exists — a road built by `make()` is a valid target). Add `Shape { heightfield: true }` +\n * `Physics { motion: 'static' }` in `aspects` for collision. */\nexport type TerrainNodeDef = {\n /** `asset('./assets/terrain/valley.terrain')` — heights / holes / control from a file. */\n data?: string;\n size?: number;\n sizeX?: number;\n sizeZ?: number;\n cellSize?: number;\n chunk?: number;\n layers?: TerrainLayer[];\n normals?: TerrainOptions[\"normals\"];\n tint?: TerrainOptions[\"tint\"];\n stamps?: TerrainStampDef[];\n holes?: TerrainRegion[];\n};\nexport type { MaterialDef };\nexport { use, ref, make };\nexport type { AspectEntry };\n/** A `make(fn, args)` source entry whose factory returns a 3D {@link Node}. */\nexport type MakeEntry<A extends Record<string, unknown> = Record<string, unknown>> = SharedMakeEntry<A, Node>;\n/** Transform overrides for one INTERNAL node of a GLB model or a prefab instance\n * (`overrides` on a model/prefab node, keyed by part path). */\nexport type ModelOverrideDef = {\n position?: Vec3Like;\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n visible?: boolean;\n /** Materials by primitive SLOT of this part (`0` for a single-material mesh; the editor lists\n * the slots with their glTF material names): a material asset, an inline def, or a custom\n * shader. Slots left out keep the glTF material. */\n materials?: Record<number | string, MaterialDef>;\n};\n/** Camera projection settings, shared by the `camera:` source block and the top-level `camera:`\n * block. All optional — an omitted key keeps the host default (60° / 0.01 / 1000). */\nexport type CameraProjectionDef = {\n /** Vertical field of view in degrees (default 60) — smaller is a longer lens. */\n fov?: number;\n /** Near clip distance (default 0.01). */\n near?: number;\n /** Far clip distance = view range (default 1000); geometry past it is culled. */\n far?: number;\n};\n/** The `camera: {}` source block — projection settings for the node that drives the view. */\nexport type CameraNodeDef = CameraProjectionDef;\nexport type SceneNodeDef = {\n mesh?: MeshDef;\n /** GLB url — `asset('./hero.glb')`. */\n model?: string;\n light?: LightDef;\n /** A heightmap ground — see {@link TerrainNodeDef}. */\n terrain?: TerrainNodeDef;\n /** The scene camera as a NODE: in play mode `scene.camera` follows this node's world transform\n * every frame (so movement aspects on it are camera flythroughs); the editor shows a frustum\n * marker and refuses to delete the last camera node. The first camera node in file order wins;\n * cameras inside prefabs are ignored (like a prefab's `camera:` block). */\n camera?: CameraNodeDef;\n /** A code-built subtree — `make(factoryFn, { ...literal args })`. */\n make?: MakeEntry<any>;\n /** Another scene file used as a reusable composition — the imported handle:\n * `import streetlamp from './streetlamp.scene'` … `lamp: { prefab: streetlamp }`. Its nodes\n * instantiate under this node per instance (env/camera are the instancing file's business and\n * are ignored); `ref()`s inside the prefab resolve file-locally, per instance. */\n prefab?: SceneHandle<any>;\n /** Material for a `mesh` source. */\n material?: MaterialDef;\n /** Model/prefab sources: transform overrides for the INTERNAL nodes, keyed by part path\n * (see the part-path grammar above `modelPartRows`). Unresolved paths are ignored. */\n overrides?: Record<string, ModelOverrideDef>;\n /** On a CHILD of a model/prefab node: parent this node to that INTERNAL part of the parent's\n * asset at build time (part path — the same grammar `overrides` keys use), e.g. a flashlight\n * in a hand. The transform stays local to the part. A stale path (asset changed) falls back\n * to the parent root with a console warning. */\n mount?: string;\n position?: Vec3Like;\n eulerAngles?: Vec3Like;\n scale?: Vec3Like | number;\n visible?: boolean;\n /** Editor-only: viewport manipulation won't target this node (fields still edit). No runtime effect. */\n locked?: boolean;\n /** Editor-only, `model` nodes: the POSE the scene editor shows — a clip looped while editing\n * (`time` freezes it at that second instead), so attachments / sight lines / a first-person eye\n * are placed against the animated pose, not the rest pose. Never applied when the scene runs. */\n editor?: {\n clip?: string;\n time?: number;\n };\n /** `mesh` / `model` nodes: real-time shadow flags. On a `model` they reach every renderable of\n * the GLB instance, so `castShadows: false` on a first-person viewmodel covers the whole gun. */\n castShadows?: boolean;\n receiveShadows?: boolean;\n /** Baked lighting (a scene with `env.lightmap`): is this model/mesh node a lightmap STATIC — a\n * receiver and an occluder in the bake, real-time shadow casting off once the bake applies?\n * Default: static unless a `Physics` aspect moves the node (`dynamic` — Physics' default — or\n * `kinematic`). Set it only to override that rule; prefab subtrees inherit the verdict. */\n lightmap?: boolean;\n /** `model` nodes: vegetation — load through the FOLIAGE tier (wind, touch bending, per-copy tint; see\n * `Foliage`). `{ fade: [start, end] }` also thins the cards out over that distance range (m) and drops the\n * copy past `end` — for ground cover. The fade is per ASSET: every node of the same GLB shares it. */\n foliage?: boolean | {\n fade?: [number, number];\n };\n /** Navigation (a scene with `env.navmesh`, see navmesh.md): every STATIC body is walkable by\n * default. `false` leaves this one out of the bake; `'unwalkable'` cuts its footprint out\n * (nobody stands on or crosses it). */\n nav?: false | \"unwalkable\";\n /** The named navmesh area this static body's surface belongs to (a key of `env.navmesh.areas`). */\n navArea?: string;\n aspects?: readonly AspectEntry<any>[];\n children?: Record<string, SceneNodeDef>;\n};\nexport type SceneCameraDef = CameraProjectionDef & {\n position?: Vec3Like;\n /** Point the camera looks at. */\n target?: Vec3Like;\n};\n/** `env.lightmap` — the level's baked lighting (engines/bake): the files `lecodes lightmap bake`\n * writes. Absent = real-time only. */\nexport type SceneLightmapDef = {\n /** `asset('./assets/lightmap/level.bake')` */\n data: string;\n /** `asset('./assets/lightmap/level-light.ktx2')` — or, for a bake that took more than one atlas PAGE\n * (`lecodes lightmap bake --pages`), every page in order: `[asset('x-light.ktx2'), asset('x-light_1.ktx2')]`. */\n light: string | string[];\n /** `asset('./assets/lightmap/level-aux.ktx2')` (pages like `light`) — sun / sky visibility + light direction. */\n aux: string | string[];\n /** DEBUG: the page sets a `lecodes lightmap bake --split` wrote (`<stem>-direct[_n].ktx2`, `<stem>-indirect[_n].ktx2`),\n * pages like `light` — the `Lightmap.debug(\"direct\" | \"indirect\")` views bind them in place of `light`. */\n direct?: string | string[];\n indirect?: string | string[];\n /** `asset('./assets/lightmap/level-probes.ktx2')` — the bake's reflection probes (one prefiltered cubemap of the level's\n * radiance per probe; every static reflects the nearest). Absent = statics reflect the sky's SH alone. */\n probes?: string;\n /** FOR THE BAKE: the radiance in cd / m² of emission 1.0 on this level (emissive factor x strength x map) - every lit\n * region of an emissive surface bakes as a rectangle lamp. An imported pack's emission is a LOOK (the school's panels\n * say 10); this is where the level says what they give: a 1.3 m ceiling panel of ~8000 lm is ~1600 nits. Default: what\n * the camera makes of 1.0 (`1.2 x 2^EV100`). 0 = emissive surfaces light nothing. `--emissive-nits` overrides. */\n emissiveNits?: number;\n /** `false` = the emissive surfaces light nothing in the bake - the level is lit by its lamps (`Light.point` with a\n * `bakeArea` next to every panel, the Unity packs' way) and the panels are decoration; `emissiveNits` then only says how\n * bright their glow is DRAWN (scene-referred: nits through the camera's exposure). Default true. */\n emissiveBake?: boolean;\n /** FOR THE BAKE: materials that let light THROUGH them, by glTF material name (`\"name*\"` = every name with that start) →\n * the share of a shadow ray that passes, tinted by the material's base colour x map: `{ mat_awning: 0.3 }` puts the\n * awning's warm, patterned light on the sand. The surface stays opaque - baked, drawn as before, a shadow caster.\n * `{ through, diffuse }` splits it: `through` goes straight (the picture of the map), `diffuse` is scattered by the\n * fibres (the underside glows, a soft fill with no picture) - dense canvas: `{ through: 0.08, diffuse: 0.25 }`. */\n transmit?: Record<string, LightmapTransmit>;\n /** `asset('./assets/lightmap/level.lgrid')` — THE LIGHT GRID for movers: every node a Physics aspect or a\n * CharacterController moves (and what code marks with `Lightmap.track`) takes its ambient light from the bake at the\n * place it is at, whatever its shader. Absent = movers keep the scene's IBL. */\n volume?: string;\n /** A DEBUG multiplier on the atlas' lux (default 1). */\n lightScale?: number;\n};\n/** `env.navmesh` — the level's navigation mesh (see navmesh.md): the file `lecodes navmesh bake`\n * writes, the agent size it is built for, and the named areas. Absent = no navigation. */\nexport type SceneNavmeshDef = {\n /** `asset('./assets/nav/<scene>.navmesh')` */\n data: string;\n /** The agent the mesh is built for (radius 0.4 · height 1.8 · climb 0.4 · slope 50 by default). */\n agent?: {\n radius?: number;\n height?: number;\n climb?: number;\n slope?: number;\n };\n /** Named areas → traversal cost (1 = plain ground); nodes join one with `navArea`. */\n areas?: Record<string, number>;\n};\nexport type SceneDef = {\n env?: SceneOptions & {\n lightmap?: SceneLightmapDef;\n navmesh?: SceneNavmeshDef;\n foliage?: FoliageOptions;\n };\n camera?: SceneCameraDef;\n nodes?: Record<string, SceneNodeDef>;\n};\ntype SourceNodeOf<N extends SceneNodeDef> = N extends {\n model: string;\n} ? Model : N extends {\n mesh: MeshDef;\n} ? Mesh : N extends {\n light: LightDef;\n} ? Light : Node;\ntype AspectsOf<N extends SceneNodeDef> = N extends {\n aspects: readonly AspectEntry<infer A>[];\n} ? A : never;\ntype NodeOf<N extends SceneNodeDef> = [\n AspectsOf<N>\n] extends [never] ? SourceNodeOf<N> : With<SourceNodeOf<N>, AspectsOf<N>>;\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\ntype ChildMapsOf<T extends Record<string, SceneNodeDef>, P extends string> = {\n [K in keyof T & string]: T[K] extends {\n children: infer C extends Record<string, SceneNodeDef>;\n } ? NodesOf<C, `${P}${K}/`> : never;\n}[keyof T & string];\ntype NodesOf<T extends Record<string, SceneNodeDef>, P extends string = \"\"> = {\n [K in keyof T & string as `${P}${K}`]: NodeOf<T[K]>;\n} & ([ChildMapsOf<T, P>] extends [never] ? unknown : UnionToIntersection<ChildMapsOf<T, P>>);\nexport type SceneNodes<D extends SceneDef> = D[\"nodes\"] extends Record<string, SceneNodeDef> ? NodesOf<D[\"nodes\"]> : Record<string, Node>;\nexport type LoadedScene<D extends SceneDef> = {\n scene: Scene;\n nodes: SceneNodes<D>;\n /** Path lookup — typed for this scene's literal paths, `Node | null` for arbitrary strings. */\n get: {\n <P extends keyof SceneNodes<D> & string>(path: P): SceneNodes<D>[P];\n (path: string): Node | null;\n };\n};\n/** One instance of a scene file built as a subtree (`handle.instantiate`). */\nexport type SceneInstance<D extends SceneDef> = {\n /** The wrapper node the file's nodes build under — position it, parent it, hide it. */\n root: Node;\n nodes: SceneNodes<D>;\n /** Anchor the instance on one of its own nodes: `root`'s local transform is set so that\n * `inner` coincides with the frame `root` is parented to (its origin and axes). One-shot,\n * from the CURRENT pose of `inner` — a rig's attachment frame (the eye place of a\n * first-person arms scene, the grip of a held prop). */\n alignTo(inner: Node): void;\n get: LoadedScene<D>[\"get\"];\n /** Remove the subtree from the scene and destroy it. */\n dispose(): void;\n};\n/** One INTERNAL node of a loaded GLB (editor introspection). */\nexport type ModelPartRow = {\n path: string;\n name: string;\n depth: number;\n node: Node;\n};\n/** Flatten a model's (or prefab instance's) internal hierarchy to rows (depth-first, the root\n * excluded). `__generated` containers are derived output, and def-built nodes (`_sceneDef` —\n * plain or `mount`ed children of the model) are addressed by their own def paths — both are\n * not parts, skipped. Filtering BEFORE segment math keeps `name[i]` indices stable no matter\n * what defs are parented in. */\nexport declare const modelPartRows: (root: Node) => ModelPartRow[];\n/** Where a def node attaches: its `mount` part when it resolves, else the parent itself. */\nexport declare const attachHost: (parent: Node, def: SceneNodeDef, path: string) => Node;\n/** The static verdict for one node def (the editor's \"Baked lighting\" switch shows the same rule).\n * Children of a mover are movers too — buildNodes carries that down, this is the node's own verdict. */\nexport declare const isLightmapStatic: (def: SceneNodeDef) => boolean;\n/** Edit mode: play the preview pose on a model node (`editor: { clip, time }`) — idempotent, the\n * harness re-applies it on inspector edits. No clip = back to the rest pose. */\nexport declare const applyEditorPose: (node: Node, pose: {\n clip?: string;\n time?: number;\n} | undefined) => void;\n/** Edit mode: otherwise-invisible nodes (empties, `camera:` nodes) get an ANCHORED gizmo marker —\n * an axis cross / a frustum in the node's local frame (scene/gizmos.ts) — so they show and pick\n * in the viewport. Never scene content: nothing renders in Filament, nothing outlines, and the\n * engine follows the node live, so the buffer is filled once and lives on the node\n * (`_editorMarker`) — `sceneEditor.gizmos()` reads it off the handle's own def nodes, so a removed\n * node's marker goes with its record and prefab / instance internals (not selectable) draw none. */\nexport declare const addEditorMarker: (node: Node, def: SceneNodeDef) => void;\n/** fov / near / far from a camera block onto the live camera. The build path leaves an empty block\n * alone (a host may run with its own configured fov); `reset` — the editor's live patch — fills\n * omitted keys with the defaults instead, so clearing a field in the inspector takes effect. */\nexport declare const applyCameraProjection: (scene: Scene, def: CameraProjectionDef, reset?: boolean) => void;\nexport declare const foreignRuns: Map<Node, EditorRun[]>;\n/** One live editor-run aspect instance (edit mode only). */\nexport type EditorRun = {\n /** Absolute path of the host def node (re-keyed on rename/reparent). */\n hostPath: string;\n node: Node;\n /** Index within the def's `aspects` array — the doc's aspect index addresses it. */\n index: number;\n inst: {\n rebuild?(): void | Promise<void>;\n };\n /** Async rebuild() supersession counter (see safeRebuild). */\n generation: number;\n /** Mutable props snapshot — `sceneEditor.setProp` updates it and re-derives `deps`. Holds the\n * DOC-LITERAL `$ref` strings (never resolved paths): the inspector's doc-sync compares these\n * against the file's props, so rewriting them would re-fire on every render. */\n props: Record<string, unknown>;\n /** ABSOLUTE paths the ref() props resolved to — a change to any of them (or anything inside\n * their subtrees) re-runs rebuild(). Re-derived after every structural change. */\n deps: Set<string>;\n /** Editor lines drawn by the last rebuild() (`Gizmos.*` calls — see scene/gizmos.ts). */\n gizmos: GizmoBuffer;\n};\n/** Re-assign every ref-carrying prop from the CURRENT nodes map — a live patch replaces node\n * instances, so a generator's resolved fields would otherwise point at destroyed nodes. */\nexport declare const assignRefProps: (run: EditorRun, nodes: Record<string, Node>) => void;\n/** EditorRun.index for a node's make() run (aspect runs use their array index, always >= 0). */\nexport declare const MAKE_INDEX = -1;\nexport declare class SceneHandle<D extends SceneDef = SceneDef> {\n readonly def: D;\n private _loading?;\n constructor(def: D);\n /** Instantiate the scene (idempotent — subsequent calls return the same instance). Does not open. */\n load(): Promise<LoadedScene<D>>;\n /** Load and make active. */\n open(): Promise<LoadedScene<D>>;\n /**\n * Build this scene file as a reusable SUBTREE inside an existing scene — a weapon under a hand\n * bone, a streetlamp per street corner — as many times as you like (unlike `load()`, which is\n * the one-instance \"scene as a level\" path). The nodes build under a fresh wrapper node (`root`)\n * parented to `parent` (or left unparented); `env` / `camera` are ignored like a prefab's. The\n * file's transforms are local to the wrapper, so author it with the wrapper as the attachment\n * point. `ref()`s resolve per instance; aspects attach per instance. `dispose()` removes the\n * subtree from the scene and destroys it.\n */\n instantiate(opts: {\n scene: Scene;\n parent?: Node | null;\n name?: string;\n }): Promise<SceneInstance<D>>;\n}\n/**\n * Define a scene as data — the default export of a `.scene.ts` file. Returns a typed handle:\n * `const { scene, nodes, get } = await handle.open()` gives `nodes[path]` typed by its source\n * block (Mesh / Model / Light / Node) with its `use(...)`d aspects attached — root nodes read as\n * plain properties (`nodes.hero`), nested ones by path (`nodes['hero/halo']` / `get('hero/halo')`).\n */\nexport declare const defineScene: <const D extends SceneDef>(def: D) => SceneHandle<D>;\n","types/scene/editor.d.ts":"import { type AspectClassInfo } from \"../core/fields\";\nimport { InspectorUI, type InspectorEvent, type InspectorWidget } from \"../core/InspectorUI\";\nimport type { Material } from \"../gl/Material\";\nimport type { Node } from \"../gl/Node\";\nimport { type ModelPartRow, type SceneHandle, type SceneNodeDef } from \"./defineScene\";\nimport { GizmoBuffer, type GizmoBatch } from \"./gizmos\";\ntype Handle = SceneHandle<any>;\nexport declare const sceneEditor: {\n patchNode: (handle: Handle, path: string, def: SceneNodeDef | null) => Promise<Node | null>;\n renameNode: (handle: Handle, path: string, newName: string) => string | null;\n reparentNode: (handle: Handle, path: string, newParentPath: string | null) => string | null;\n nodeChanged: (handle: Handle, path: string) => void;\n modelParts: (handle: Handle, path: string) => Promise<ModelPartRow[]>;\n describeAspects: (handle: Handle) => AspectClassInfo[];\n setProp: (handle: Handle, hostPath: string, index: number, key: string, value: unknown) => boolean;\n setMakeArg: (handle: Handle, hostPath: string, key: string, value: unknown) => boolean;\n gizmos: (handle: Handle) => {\n version: number;\n batches: GizmoBatch[];\n };\n inspectorRender: (handle: Handle, hostPath: string, index: number, props: Record<string, unknown>, event?: InspectorEvent) => InspectorWidget[] | null;\n /** The preview pose of a model node (`editor: { clip, time }`) — idempotent; no clip = the rest pose. */\n applyPose: (node: Node, pose: {\n clip?: string;\n time?: number;\n } | undefined) => void;\n isLocked: (node: Node) => boolean;\n setLocked: (node: Node, locked: boolean) => void;\n /** Assign a material def to one slot of a node (a material asset handle, an inline def, a shader). */\n assignMaterial: (node: Node, slot: number, def: import(\"./material\").MaterialDef) => Promise<Material>;\n /** One parameter into a live material: a value, or a texture URL that loads in. */\n setMaterialParam: (material: Material, name: string, value: import(\"./material\").MaterialParamValue | null) => Promise<void>;\n isBuiltinMaterial: (material: Material) => boolean;\n forgetMaterial: (node: Node, slot: number) => void;\n GizmoBuffer: typeof GizmoBuffer;\n withGizmoScope: <T>(buffer: GizmoBuffer, fn: () => T) => T;\n runCard: (ui: InspectorUI, render: (ui: InspectorUI) => void, event?: InspectorEvent) => InspectorWidget[];\n /** The registry `registerEditorWindow` / `registerEditorTool` fill (`*.editor.ts` files). */\n plugins: {\n windows: {\n title: string;\n render: import(\"./editorPlugins\").EditorWindowFn;\n }[];\n tools: {\n name: string;\n hooks: import(\"./editorPlugins\").EditorToolHooks;\n }[];\n };\n};\n/** The contract of an editor's in-world half with the SDK — the type of the `__sceneEditor` global. */\nexport type SceneEditorApi = typeof sceneEditor;\nexport {};\n","types/scene/editorPlugins.d.ts":"import type { InspectorUI } from \"../core/InspectorUI\";\n/** A geometry hit under the viewport pointer, handed to tools. Physics builds raycast the scene's\n * meshes (precise); otherwise (and on misses) the hit falls back to the ground plane (y = 0). */\nexport type EditorRayHit = {\n point: [number, number, number];\n normal: [number, number, number];\n /** Absolute path of the scene-file node the hit belongs to (\"city/in1/pt1\") — null for\n * ground-plane fallback hits. */\n node: string | null;\n};\n/**\n * The editor scripting API handed to windows and tools. Nodes are addressed by ABSOLUTE PATH —\n * '/'-joined names from the scene root; a root node's path is its bare name. Doc-op methods write\n * the scene DOCUMENT through the editor's normal commit path (undo, file, live patching all\n * included); they return false / no-op when the document can't take the edit (sibling-name\n * collision, unknown path).\n */\nexport type EditorApi = {\n /** The currently selected node path (or `path::part` key for asset internals), null when\n * nothing is selected. */\n readonly selection: string | null;\n select(path: string | null): void;\n /** The scene document's nodes: absolute path, sibling-unique display name, source kind\n * (mesh / model / light / group / …). */\n nodes(): {\n path: string;\n name: string;\n kind: string;\n }[];\n /** First unused \"base\", \"base2\", \"base3\", … name among the SIBLINGS under `parentPath`\n * (scene root when omitted). */\n uniqueName(base: string, parentPath?: string): string;\n /** Add a ROOT node from plain def data (scene-file grammar; a string `model` value means an\n * asset path). `name` may not contain '/' or ':'. One undo step unless grouped by `transact`. */\n addNode(name: string, def: Record<string, unknown>): boolean;\n /** Write one def prop (transforms apply live; anything else patches/re-runs the node). */\n setProp(path: string, key: string, value: unknown): boolean;\n removeNode(path: string): void;\n /** Duplicate a node; returns the copy's path (null when it can't). */\n duplicate(path: string): string | null;\n /** Raycast the scene under a viewport pixel (same hit rules as tool clicks). */\n raycast(screenX: number, screenY: number): EditorRayHit | null;\n /** Group every doc edit inside `fn` into ONE undo step. */\n transact(fn: () => void): void;\n /** Read one def prop of a node as document data (`asset()` refs come as `{ $asset: \"./x\" }`);\n * undefined when the node or key doesn't exist. */\n getProp(path: string, key: string): unknown;\n /** Write a BINARY asset file for a node (a terrain's `.terrain`, a baked mask…). `ref` = the\n * node's existing def-relative `asset()` ref to overwrite, or null to create `./<name>` at the\n * project root (a free name is picked on collisions). Resolves to the ref to store in the node's\n * def (`{ $asset: ref }` via `setProp`), null when the host can't write files. Not a doc edit —\n * it is not undoable; keep the doc pointing at the file. */\n writeAsset(path: string, ref: string | null, name: string, bytes: Uint8Array): Promise<string | null>;\n};\nexport type EditorWindowFn = (ui: InspectorUI, editor: EditorApi) => void;\nexport type EditorToolHooks = {\n /** CSS cursor for the viewport while this tool is active (default \"crosshair\"). */\n cursor?: string;\n /** A short glyph (one character / emoji) for the tool's toolbar button — tools without one all\n * share the generic wand icon, so any editor with two or more tools should set it. */\n icon?: string;\n /** A viewport click while the tool is active — `hit` is the raycast result under the pointer.\n * Viewport clicks route to the tool while it is active. */\n onViewportClick?(hit: EditorRayHit, editor: EditorApi): void;\n /** Drag tools (brushes): a primary-button drag in the viewport routes here instead of orbiting\n * the camera — start / every pointer move (with the hit under it, null while off-world) /\n * release. A tool with `onDragStart` gets NO `onViewportClick` for the same gesture. */\n onDragStart?(hit: EditorRayHit, editor: EditorApi): void;\n onDrag?(hit: EditorRayHit | null, editor: EditorApi): void;\n onDragEnd?(editor: EditorApi): void;\n /** The pointer moved over the viewport with no button down (throttled to the frame) — draw a\n * brush cursor through `Gizmos`; null when nothing is under it. */\n onHover?(hit: EditorRayHit | null, editor: EditorApi): void;\n};\n/** Register an editor panel — a collapsible overlay docked over the viewport (the inspector rail\n * stays selection-scoped). A window that emits `ui.toolButton` for a tool becomes that tool's\n * settings panel: activating the tool expands and highlights it. `render` re-runs immediate-mode\n * on every interaction — same protocol as `static inspector` cards. */\nexport declare const registerEditorWindow: (title: string, render: EditorWindowFn) => void;\n/** Register a viewport tool — a toolbar entry beside move/rotate/scale (activate it there or via\n * `ui.toolButton(label, name)`). While active, viewport clicks arrive as raycast hits. */\nexport declare const registerEditorTool: (name: string, hooks: EditorToolHooks) => void;\n","types/scene/gizmos.d.ts":"import { type ColorInput } from \"../core/color\";\nimport { type Mat4Like } from \"../math/mat4\";\nimport type { Vec3Like } from \"../math/vec\";\n/** The anchor of a gizmo call: any object with an engine entity id (a `Node`). */\nexport type GizmoAnchor = {\n readonly id: number;\n};\nexport type GizmoStyle = {\n /** Any color (a CSS color string, `0xRRGGBB`, `[r, g, b(, a)]`; its alpha multiplies `alpha`);\n * default a neutral light gray. */\n color?: ColorInput;\n /** 0..1, default 1. */\n alpha?: number;\n /** Anchor: points are in this node's LOCAL frame (scale ignored); the lines follow the node\n * live, are pickable (a click selects the node) and turn the selection accent when it is\n * selected. Omit for world-space lines (not pickable). */\n node?: GizmoAnchor | null;\n};\n/** One color batch of LINES (flat `[x,y,z, x,y,z]` per segment) — what a host hands the engine\n * (`color` a CSS color string, '#rrggbbaa' from here). With `entityId` the segments are in that\n * entity's local frame (see GizmoStyle.node). */\nexport type GizmoBatch = {\n color: string;\n alpha: number;\n segments: number[];\n entityId?: number;\n};\n/** The per-run collector (owned by the scene loader's EditorRun). Batches are keyed by style so a\n * hundred same-colored segments cost one draw. */\nexport declare class GizmoBuffer {\n batches: GizmoBatch[];\n private _byStyle;\n clear(): void;\n segments(style: GizmoStyle | undefined): number[];\n}\n/**\n * Editor-only line drawing, available inside generator `rebuild()`, `make()` factories and editor\n * tool hooks. Points are WORLD space. Drawn by the scene editor's viewport overlay (depth-test\n * off — a path through a wall is still a path); invisible everywhere else.\n */\nexport declare const Gizmos: {\n /** One segment from `a` to `b`. */\n line(a: Vec3Like, b: Vec3Like, style?: GizmoStyle): void;\n /** Consecutive segments through `points`; `closed` joins the last point back to the first. */\n polyline(points: readonly Vec3Like[], style?: GizmoStyle & {\n closed?: boolean;\n }): void;\n /** A wireframe camera frustum looking down −Z: the four edges from the origin to a rect\n * `length` metres ahead sized by `fov` (vertical, degrees) × `aspect` (default 16:9), plus an\n * \"up\" fin above the rect. Anchor it (`{ node }`) for a camera node's marker — the frustum\n * then follows the node's pose; `matrix` places an unanchored one in world space. */\n frustum(fov: number, style?: GizmoStyle & {\n aspect?: number;\n length?: number;\n matrix?: Mat4Like;\n }): void;\n /** A three-axis cross centred on `p` (a point marker); `size` = half extent, default 0.1. */\n cross(p: Vec3Like, size?: number, style?: GizmoStyle): void;\n};\n","types/scene/grammar.d.ts":"import type { Aspect, AspectCtor } from \"../core/Aspect\";\nimport type { Node } from \"../gl/Node\";\n/** One aspect to attach, created by `use(Ctor, props)`. */\nexport type AspectEntry<A extends Aspect<any, any> = Aspect<any, any>> = {\n ctor: AspectCtor<A>;\n props?: Partial<A>;\n};\n/** Reference an aspect in a scene file: `aspects: [use(Physics, { motion: 'static' })]`. Props are\n * typechecked against the aspect's fields, exactly like `node.aspect(Ctor, props)`. */\nexport declare const use: <A extends Aspect<any, any>>(ctor: AspectCtor<A>, props?: Partial<A>) => AspectEntry<A>;\n/** A `make(fn, args)` source entry — see {@link make}. `N` is the node family the factory returns\n * (3D `Node` by default; a `.scene2d.ts` file's factories return `Node2D`). */\nexport type MakeEntry<A extends Record<string, unknown> = Record<string, unknown>, N = Node> = {\n fn: (args: A) => N | Promise<N>;\n args?: A;\n};\n/**\n * A code-created source in a scene file: `tower: { make: make(buildTower, { floors: 5 }), … }`.\n * The factory runs after every scene node exists (so `ref()` args resolve, forward references\n * included) and its returned subtree mounts under the def node — the def's transform stays\n * editor-owned, so moving the node never re-calls the factory. Args must be literal data (same\n * grammar as aspect props); in the editor they edit as fields, and an arg change re-CALLS the\n * factory live — the code is already in the bundle, so no compile happens. Keep factories pure\n * builders: same args → same subtree, no side effects outside the returned nodes.\n */\nexport declare const make: <A extends Record<string, unknown>, N>(fn: (args: A) => N | Promise<N>, args?: A) => MakeEntry<A, N>;\n/**\n * Reference another scene node by PATH in an aspect's props:\n * `use(Road, { from: ref('pointA'), to: ref('lane/pointB') })`. Resolves to the live node when\n * aspects attach — after EVERY node of the scene exists, so declaration order doesn't matter.\n * Resolution is scoped upward from the host node (like variable scoping): the host's own children\n * first, then its siblings, then each ancestor's scope up to the scene root. The FIRST segment\n * binds the scope; the remaining segments descend from there. Refs address def nodes only (no\n * `::`/`name[i]` asset-internal segments); an unknown path resolves to `null` (type your aspect\n * field `Node | null`). Scene files only — hand-written code passes nodes directly:\n * `node.aspect(Road, { from: nodes.pointA })`.\n */\nexport declare const ref: <T = Node>(path: string) => T;\nexport declare const isNodeRef: (v: unknown) => v is {\n $ref: string;\n};\n/** Resolve one ref string against a path-keyed nodes record, scoped upward from `hostPath` (own\n * children → parent's scope (siblings + the host itself) → each ancestor scope → root, `\"\"`).\n * The ref's FIRST segment binds the scope — a match there is final even when the rest of the\n * path doesn't exist (lexical shadowing). Returns the target's ABSOLUTE path, or null.\n * `Object.hasOwn`, not indexing: a node named `constructor` must not resolve via the prototype. */\nexport declare const resolveRefPath: (nodes: Record<string, unknown>, hostPath: string, ref: string) => string | null;\n/** Swap `ref()` markers in aspect props for the live nodes (top level + one array level deep),\n * resolved scoped-upward from `hostPath` (\"\" = root scope only — the 2D flat-map case). */\nexport declare const resolveRefs: <N>(props: Record<string, unknown> | undefined, nodes: Record<string, N>, hostPath?: string) => Record<string, unknown> | undefined;\n/** ABSOLUTE paths of the nodes a props record's ref() values resolve to (editor dep tracking).\n * An unresolved ref contributes no dep — the handle re-derives deps after structural changes. */\nexport declare const collectRefDeps: (props: Record<string, unknown>, nodes: Record<string, unknown>, hostPath: string) => Set<string>;\n/** The edit-mode flag an editor host sets before running the bundle (shared by both formats). */\nexport declare const EDIT_FLAG = \"__lecodesSceneEdit\";\nexport declare const isEditMode: () => boolean;\n","types/scene/level.d.ts":"import { Node } from \"../gl/Node\";\nimport { type Vec3Like } from \"../math/vec\";\n/** One placement handed to a `build` function (all coordinates local to the group). */\nexport type LevelSpot = {\n /** 0-based placement index. */\n index: number;\n /** Local position the node will be placed at (before jitter was already applied). */\n position: [number, number, number];\n /** Yaw in degrees the node will face (already resolved from the `yaw` option). */\n yaw: number;\n /** Deterministic per-call random stream (seeded) — use for per-spot variation. */\n rng: () => number;\n};\n/** What to place: a GLB url (loaded once, cloned per spot), or a builder function. A builder\n * returning `null` skips that spot (thin a line, punch a gap in a grid). */\nexport type LevelBuild = string | ((spot: LevelSpot) => Node | null | Promise<Node | null>);\n/** Static collision for url builds: 'mesh' = exact triangles, 'convex' = convex hull,\n * 'box' = auto box from the mesh bounds, 'none' (default) = no collider. */\nexport type LevelCollider = \"mesh\" | \"convex\" | \"box\" | \"none\";\ntype PlaceCommon = {\n build: LevelBuild;\n /** Static Shape+Physics attached to url-built nodes (default 'none'). Function builds attach\n * their own aspects instead. */\n collider?: LevelCollider;\n /** Facing: degrees, 'random', 'face' (forward +Z toward the helper's direction), or 'align'\n * (the model's X length-axis along the direction — what fence/wall panels want). Each helper\n * picks its natural default. */\n yaw?: number | \"random\" | \"face\" | \"align\";\n /** Random XZ offset per spot, meters: a radius, or [maxX, maxZ]. */\n jitter?: number | [number, number];\n /** Seed for the deterministic random stream (default 1). */\n seed?: number;\n /** Child name prefix (default: the url's basename, else 'item'). */\n name?: string;\n};\nexport type LevelLineOptions = PlaceCommon & {\n from: Vec3Like;\n to: Vec3Like;\n /** Fixed number of placements (endpoints included when count > 1)… */\n count?: number;\n /** …or a spacing in meters (placements from `from` toward `to`, last one ≤ `to`). */\n step?: number;\n};\nexport type LevelGridOptions = PlaceCommon & {\n /** Grid center (default [0,0,0]). */\n center?: Vec3Like;\n cols: number;\n rows: number;\n /** Cell size in meters: one number or [alongX, alongZ]. */\n spacing: number | [number, number];\n};\nexport type LevelRingOptions = PlaceCommon & {\n /** Ring center (default [0,0,0]). */\n center?: Vec3Like;\n radius: number;\n count: number;\n /** Start angle in degrees (default 0 = +X). */\n start?: number;\n /** Arc to cover in degrees (default 360 = full ring, end exclusive). */\n arc?: number;\n /** 'face' orientation for rings: toward the center ('in', default) or away ('out'). */\n facing?: \"in\" | \"out\";\n};\nexport type LevelScatterOptions = PlaceCommon & {\n /** Rectangle center (default [0,0,0]). */\n center?: Vec3Like;\n /** Rectangle extent in meters: [sizeX, sizeZ] or one number for a square. */\n size: number | [number, number];\n count: number;\n /** Minimum distance between any two placements (rejection-sampled; the helper places as many\n * as fit within the attempt budget and logs when it falls short). */\n minSpacing?: number;\n /** Keep-out circles `{ x, z, r }` (local), or a predicate — return true to REJECT a point. */\n avoid?: {\n x: number;\n z: number;\n r: number;\n }[] | ((x: number, z: number) => boolean);\n /** Y for every placement (default 0 — scatter is planar; vary height in a build fn). */\n y?: number;\n};\nexport type LevelPlaceOptions = PlaceCommon & {\n /** Explicit spots: [x, y, z] or [x, y, z, yawDegrees]. */\n at: (readonly number[])[];\n};\n/** Procedural level building — see the module header. All helpers return a Promise<Node> group to\n * return from a `make()` factory (or add to a scene from plain code). */\nexport declare const Level: {\n line: (opts: LevelLineOptions) => Promise<Node>;\n grid: (opts: LevelGridOptions) => Promise<Node>;\n ring: (opts: LevelRingOptions) => Promise<Node>;\n scatter: (opts: LevelScatterOptions) => Promise<Node>;\n place: (opts: LevelPlaceOptions) => Promise<Node>;\n /** The seeded PRNG the helpers use (mulberry32) — for custom generators that must stay\n * deterministic alongside them. */\n rng: (seed: number) => (() => number);\n};\nexport {};\n","types/scene/material.d.ts":"import type { ColorInput } from \"../core/color\";\nimport { Material, type LitMaterialOptions, type UnlitMaterialOptions } from \"../gl/Material\";\nimport type { Node } from \"../gl/Node\";\n/** A shader parameter value as scene files write it: number, boolean, `#colour`, texture URL\n * (`asset('./x.png')`), or a numeric vector. */\nexport type MaterialParamValue = number | boolean | string | number[];\ntype WithMapUrl<T> = Omit<T, \"map\"> & {\n /** Base-colour texture — a `Texture`, a `Canvas`, or `asset('./x.png')` (a URL string). */\n map?: LitMaterialOptions[\"map\"] | string;\n};\nexport type LitMaterialDef = WithMapUrl<LitMaterialOptions>;\nexport type UnlitMaterialDef = WithMapUrl<UnlitMaterialOptions>;\n/** A custom Filament shader (`asset('./x.mat')` — compiled by the platform / `lecodes shaders`)\n * plus its parameter values. */\nexport type ShaderMaterialDef = {\n shader: string;\n params?: Record<string, MaterialParamValue>;\n};\nexport type MaterialDef = {\n lit: LitMaterialDef;\n} | {\n unlit: UnlitMaterialDef;\n} | {\n shadow: ColorInput;\n} | ShaderMaterialDef\n/** A material asset (`import m from './x.material'`) — one shared instance. */\n | MaterialHandle\n/** A code-level Material instance — valid at runtime; the editor shows it read-only. */\n | Material;\n/** The data forms of MaterialDef (everything but a live instance / handle). */\nexport type MaterialData = Exclude<MaterialDef, MaterialHandle | Material>;\n/** Push one parameter into a live material. Textures load asynchronously — the returned promise\n * settles once the value is applied (immediately for scalars). */\nexport declare const applyMaterialParam: (material: Material, name: string, value: MaterialParamValue | null) => Promise<void>;\n/** Build a live Material from a data def. Resolves once every texture it names has loaded. */\nexport declare const createMaterialFromData: (def: MaterialData) => Promise<Material>;\n/**\n * A material asset: the default export of a `*.material.ts` file. `load()` yields ONE shared\n * `Material` (cached); scene files hand the handle to `material:` and the loader resolves it.\n * The editor edits the asset live through `setParam` / `reset` — every node the handle was\n * applied to follows (`_users`).\n */\nexport declare class MaterialHandle {\n def: MaterialData;\n private _instance;\n private _loading;\n /** Every (node, slot) this handle was applied to through a scene — the editor re-assigns them\n * when the asset's shader changes. */\n readonly _users: Set<{\n node: Node;\n slot: number;\n }>;\n constructor(def: MaterialData);\n /** The shared material instance (built on first use). */\n load(): Promise<Material>;\n /** The live instance, if built yet. */\n get material(): Material | null;\n /** Editor: assign this material to `node`'s `slot`, remembering the user. */\n _applyTo(node: Node, slot: number): Promise<Material>;\n /** Editor: one parameter value, applied live to the shared instance (a texture loads in). */\n setParam(name: string, value: MaterialParamValue | null): void;\n /** Editor: replace the whole definition (a shader/kind switch) — rebuilds the instance and\n * re-assigns every user. */\n reset(def: MaterialData): Promise<Material>;\n}\n/** Resolve any `material:` value to a live Material (a handle's shared instance, a data def's\n * fresh one, a code instance as is). */\nexport declare const resolveMaterialDef: (def: MaterialDef) => Promise<Material>;\n/** Resolve and assign a `material:` value to one slot of a node (tracking handle users). */\nexport declare const assignMaterialDef: (node: Node, slot: number, def: MaterialDef) => Promise<Material>;\n/**\n * Define a material as data — the default export of a `*.material.ts` file. Import it into scene\n * files (`material: handle`) or code (`const m = await handle.load()`).\n */\nexport declare const defineMaterial: (def: MaterialData) => MaterialHandle;\nexport {};\n","types/server/auth/api.d.ts":"/**\n * `db.auth` — the BUNDLE side of sign-in, what `*.server.ts` code calls on a db made with\n * `defineDb({...}).withAuth({ model: \"User\" })`:\n *\n * const db = defineDb({ User, Post }).withAuth({ model: \"User\" })\n *\n * export async function register(login: string, password: string, name: string) {\n * await db.auth.signUpWithPassword(login, password, { name })\n * }\n * export async function me() { return db.auth.user().select({ id: true, name: true }) }\n * export async function removePost(id: number) {\n * await db.auth.requireUser({ role: \"admin\" }).select({ id: true })\n * …\n * }\n *\n * The platform knows a request's session and the ID of its user (the host resolved the token before\n * the endpoint ran). Everything else about a user is a row of the project's own model, and is READ:\n * `user()` / `requireUser()` are queries over that model — typed by it, run when awaited — narrowed to\n * the user of the request. Sign-in operations forward to the host's `AuthOps` on\n * `globalThis.__lecodesAuth` (a seam: the compiled bundle carries its own SDK copy).\n */\n/** The collections of a db with auth, by role (defineDb.ts). */\nexport type AuthCollections = {\n model: string;\n user: any;\n session: any;\n identity: any;\n};\nexport declare const createAuthApi: (tables: () => AuthCollections) => {\n user: () => any;\n requireUser: (where?: Record<string, unknown>) => any;\n readonly sessionId: number;\n signUpWithPassword: (login: string, password: string, data?: Record<string, unknown>) => Promise<void>;\n signInWithPassword: (login: string, password: string) => Promise<void>;\n setPassword: (password: string) => Promise<void>;\n sendCode: (email: string) => Promise<void>;\n signInWithCode: (email: string, code: string) => Promise<void>;\n signIn: (userId: number) => Promise<void>;\n signOut: () => Promise<void>;\n readonly sessions: any;\n readonly identities: any;\n};\n","types/server/auth/appConfig.d.ts":"/**\n * The project's `app.json` subset the server runtime reads: the app's name (the sign-in mail).\n *\n * This module is a placeholder the COMPILER REPLACES: `compileServerBundle({ app })` puts a module with the\n * real values at this same path in chisel's file map (project files win over SDK files), so every SDK module\n * that imports `app` gets the project's config as a plain dependency — no globals, no evaluation-order games.\n * Outside a compiled bundle (tests, tooling) `globalThis.__lecodesApp` can stand in.\n */\nexport type AppConfig = {\n name?: string;\n};\nexport declare const app: AppConfig;\n","types/server/auth/models.d.ts":"/**\n * The two models sign-in adds to a database — `defineDb({...}).withAuth({ model: \"User\" })`:\n *\n * Session one device: the hash of its token, and the user it is signed in as (none = a guest)\n * Identity one way a user signs in: `email:<address>` or `login:<name>` (with the password's hash\n * when one is set) — several per user.\n *\n * They are the PLATFORM's: a project never declares them and never writes to them — it may refer to a\n * session (`t.one(\"Session\")`: a guest's cart) and read both through `db.auth.sessions` /\n * `db.auth.identities`, which leave the secrets out. The user model is the project's own, an ordinary\n * `model({...})`: the platform creates a row of it the first time someone signs in and knows nothing\n * of it but the id.\n */\nexport type { AppConfig } from \"./appConfig\";\n/** What an `Identity` row is of: an email, or a login (a name with no address behind it). */\nexport type IdentityProvider = \"email\" | \"login\";\nexport declare const AUTH_SESSION_MODEL = \"Session\";\nexport declare const AUTH_IDENTITY_MODEL = \"Identity\";\n/** A session as a project reads it (`db.auth.sessions`, a `t.one(\"Session\")` relation). */\nexport declare const sessionPublicFields: () => {\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n lastSeenAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n revoked: import(\"../db\").Field<boolean, {\n kind: \"scalar\";\n scalar: \"bool\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n};\nexport type SessionPublicFields = ReturnType<typeof sessionPublicFields>;\n/** The whole `Session`; `user` points at the model `withAuth` named. */\nexport declare const sessionFields: (userModel: string) => {\n pendingEmail: import(\"../db\").Field<string, {\n kind: \"scalar\";\n scalar: \"string\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n codeHash: import(\"../db\").Field<string, {\n kind: \"scalar\";\n scalar: \"string\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n codeExpires: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n codeAttempts: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"int\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n user: import(\"../db\").Field<never, {\n kind: \"one\";\n scalar: \"\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: string;\n }>;\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n lastSeenAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n revoked: import(\"../db\").Field<boolean, {\n kind: \"scalar\";\n scalar: \"bool\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n /** sha256 of the bearer token the device holds — the token itself is never stored. */\n tokenHash: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n};\n/** A sign-in method as a project reads it (`db.auth.identities`) — no hash. */\nexport declare const identityPublicFields: () => {\n /** `\"email\" | \"login\"` */\n provider: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** What the person types to sign in: the address, or the login. */\n subject: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** When the subject was proven (a code). Unset = a password sign-up whose address wasn't confirmed. */\n verifiedAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n};\nexport type IdentityPublicFields = ReturnType<typeof identityPublicFields>;\n/** The whole `Identity`. */\nexport declare const identityFields: (userModel: string) => {\n /** `<provider>:<subject>` — marcidb has no composite @unique, this is the one-row-per-identity guarantee. */\n key: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** scrypt hash of the password (`email` / `login` identities). */\n hash: import(\"../db\").Field<string, {\n kind: \"scalar\";\n scalar: \"string\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n /** `\"email\" | \"login\"` */\n provider: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** What the person types to sign in: the address, or the login. */\n subject: import(\"../db\").Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** When the subject was proven (a code). Unset = a password sign-up whose address wasn't confirmed. */\n verifiedAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n createdAt: import(\"../db\").Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n user: import(\"../db\").Field<never, import(\"../db/fields\").Meta<{\n kind: \"one\";\n model: string;\n }>>;\n};\n","types/server/auth/types.d.ts":"/**\n * Shared shapes of the auth layer. Two sides meet through them:\n * - the BUNDLE side (`db.auth`, ./api.ts) — what `*.server.ts` code calls;\n * - the HOST side (./host.ts) — sessions, passwords and email codes, run by the runner with the\n * project's db handle. Installed on `globalThis.__lecodesAuth`.\n */\nimport type { RequestContext } from \"../context\";\n/** Per-request auth state, resolved by the host before the endpoint runs (`RequestContext.auth`): the\n * device's session and the id of the user it is signed in as. Nothing of the user's row — a project\n * reads that itself (`db.auth.user()`). */\nexport type AuthState = {\n sessionId: number;\n userId: number | null;\n /** A token to hand back to the client in this response (a new guest session, or a rotation). */\n issuedToken?: string;\n};\n/** Host operations `db.auth` forwards to (all request-scoped through `ctx`). A sign-in resolves once the\n * session is bound; who it is bound to is read through `db.auth.user()`. */\nexport type AuthOps = {\n /** `data` = the fields of the new user's row (the project's own model). */\n signUpWithPassword(ctx: RequestContext, login: string, password: string, data?: Record<string, unknown>): Promise<void>;\n signInWithPassword(ctx: RequestContext, login: string, password: string): Promise<void>;\n setPassword(ctx: RequestContext, password: string): Promise<void>;\n sendCode(ctx: RequestContext, email: string): Promise<void>;\n signInWithCode(ctx: RequestContext, email: string, code: string): Promise<void>;\n signIn(ctx: RequestContext, userId: number): Promise<void>;\n signOut(ctx: RequestContext): Promise<void>;\n /** The sessions of the current user (or just this device's, when signed out), as a query. */\n sessions(ctx: RequestContext): any;\n /** The current user's sign-in methods, as a query — the hash is not in it. */\n identities(ctx: RequestContext): any;\n};\n","types/server/channel.d.ts":"/**\n * Channels: the server's messages to the app. A server function is a call from the app to the\n * server; a channel is the other direction, typed by the same export.\n *\n * export const postsChannel = channel<Post>() // to everyone listening\n * export const noticesChannel = channel<Notice>() // to each their own\n * .groupBy(async () => (await db.auth.requireUser().select({ id: true })).id)\n *\n * postsChannel.publish(post) // server\n * noticesChannel.publish(userId, notice)\n *\n * postsChannel.subscribe(post => …) // app\n * noticesChannel.subscribe(notice => …)\n *\n * `groupBy` runs on the server when an app subscribes, with what the app passed to `subscribe`\n * before the handler, and answers the group that subscriber is in; `publish(group, message)` reaches\n * that group. `authorize` only decides who may listen. Both refuse by throwing (`ApiError`), and\n * both run in the request scope of the subscriber, so `db.auth` works in them.\n *\n * A channel's identity is its export (`<path>#<name>`), assigned by the runtime when the bundle is\n * loaded (`loadServerModules`); `publish` before that is an error. Delivery goes through the\n * `globalThis.__lecodesPublish` seam the host installs (same reason as ./context.ts: the bundle\n * carries its own SDK copy). In the app the export is another object altogether — the proxy\n * `__channel` of src/runtime/rpc.ts — which is why `subscribe` here only throws.\n */\nimport type { ChannelGroup } from \"../runtime/wire\";\nexport type { ChannelGroup };\n/** What `subscribe` answers: the subscription lives until `close()`. */\nexport type ChannelSubscription = {\n close(): void;\n};\nexport type SubscribeOptions = {\n /** The connection dropped and came back: what was published in between is lost — read the state again. */\n reconnect?: () => void;\n /** The server refused the subscription (a hook threw): an `RpcError`, its `status` the hook's.\n * Without it the refusal is logged. The subscription is not over: the server is asked again\n * when the session changes, so this may be called more than once. */\n error?: (e: Error & {\n readonly status: number;\n }) => void;\n};\n/** A channel every subscriber hears alike. */\nexport interface Channel<M> {\n /** Who may listen: runs on the server at every subscription, throw to refuse. */\n authorize(check: () => void | Promise<void>): Channel<M>;\n /** Split the subscribers: `group` runs on the server at every subscription — with what the app\n * passed to `subscribe` — and answers the group of that subscriber. Throw to refuse. */\n groupBy<K extends ChannelGroup, A extends unknown[] = []>(group: (...args: A) => K | Promise<K>): GroupedChannel<M, K, A>;\n /** Server: send `message` to every subscriber (at most once — nothing is kept for a socket that is away). */\n publish(message: M): void;\n /** App: listen until `close()`. */\n subscribe(handler: (message: M) => void, options?: SubscribeOptions): ChannelSubscription;\n}\n/** A channel whose subscribers are in groups (`groupBy`). */\nexport interface GroupedChannel<M, K extends ChannelGroup, A extends unknown[]> {\n /** Server: send `message` to the subscribers of `group`. */\n publish(group: K, message: M): void;\n /** App: listen until `close()`; the arguments before the handler go to the channel's `groupBy`. */\n subscribe(...args: [...args: A, handler: (message: M) => void, options?: SubscribeOptions]): ChannelSubscription;\n}\ntype Publisher = (channelId: string, group: ChannelGroup | null, message: unknown) => void;\n/** Host hook (runner / local backend / test harness): where `publish` delivers to. */\nexport declare const setChannelPublisher: (publisher: Publisher | null) => void;\nexport declare const isChannelGroup: (v: unknown) => v is ChannelGroup;\nexport declare const channel: <M = unknown>() => Channel<M>;\nexport declare const isChannel: (v: unknown) => v is ChannelRecord;\n","types/server/context.d.ts":"/**\n * Request context for server code. The runner keeps the current request in an AsyncLocalStorage\n * and exposes it through `globalThis.__lecodesRequest` — a *global* seam on purpose: the compiled\n * server bundle carries its own copy of this module (chisel bundles the SDK in), so the host can't\n * hand it a value by import. `request` reads through that seam; outside a request (module load,\n * timers after the response) every member is undefined.\n */\nexport type RequestContext = {\n /** Endpoint id `<path>#<export>` (or the channel id for a subscription's hooks). */\n id: string;\n headers: Record<string, string>;\n ip?: string;\n /** Bearer session token as sent by the client transport (raw; auth resolves it). */\n sessionToken?: string;\n /** Set by the auth runtime after resolving the token — read via `db.auth`, not here. */\n auth?: unknown;\n /** The files a multipart call carried, as the receiving process left them (./files/host.ts `Upload`). */\n uploads?: unknown[];\n /** What `/files/<id>/<name>` is appended to in a stored file's url: the backend's own base, as this request reached it. */\n filesBase?: string;\n};\ntype Provider = () => RequestContext | undefined;\n/** Host hook (runner / test harness): install the current-request provider. */\nexport declare const setRequestProvider: (provider: Provider | null) => void;\n/** The current request (server global). Undefined members outside a request. */\nexport declare const request: {\n readonly id: string | undefined;\n readonly headers: Record<string, string>;\n readonly ip: string | undefined;\n};\nexport {};\n","types/server/db/defineDb.d.ts":"/**\n * `model({...})` + `defineDb({ User, Post })` — the schema registry and the typed db handle.\n *\n * Runtime responsibilities: validate relation names, resolve `t.many()` back-fields, emit the `.marci`\n * schema text (`db.$schema`), and turn collection calls into lazy `Op`s over a `MarciTransport`\n * (`marcidb-embedded` handle, HTTP client, or a test fake). The transport is either passed to\n * `defineDb(models, { transport })` or provided by the host through `setDbTransport()` — user code\n * never sees a connection string.\n */\nimport { type FieldDef } from \"./fields\";\nimport { type MarciTransport } from \"./marci/query\";\nimport type { Db, Fields, Model, Schema, ValidateRefs } from \"./types\";\nexport declare const model: <F extends Fields>(fields: F) => Model<F>;\n/** Host hook: the runner/dev-server installs the project's transport before loading user code. */\nexport declare const setDbTransport: (transport: MarciTransport | null) => void;\n/**\n * Every `defineDb` call registers its handle here so the host finds the schema whether or not the\n * project exports `db` (`const db = defineDb(...)` used only inside endpoints is the common case).\n * The host reads and clears the list after evaluating a bundle (`loadServerModules`).\n */\nexport declare const takeRegisteredDbs: () => Db<any>[];\n/** A reference to a previous operation's result inside `$transaction` (resolved server-side): `ref(\"0.id\")`. */\nexport declare const ref: (path: string) => any;\ntype ModelMeta = {\n name: string;\n fields: Record<string, FieldDef>;\n idKeys: string[];\n /** id is a single uuid key we generate on insert. */\n uuidId: boolean;\n};\nexport declare const toMarci: (metas: Record<string, ModelMeta>) => string;\nexport type DefineDbOptions = {\n transport?: MarciTransport;\n};\n/**\n * The schema registry: model name = key (`db.user` ← `User`). Relation strings are checked against the\n * keys both at the type level (`ValidateRefs`) and at runtime.\n *\n * A db is SEALED by its first use — a query, a read of its schema, the host taking it after the file\n * has loaded. Until then `.withAuth({ model })` may still change what it holds: it adds the platform's\n * `Session` and `Identity` models (../auth/models.ts) pointing at the project's model of a user, and\n * gives the db its `auth`. So `withAuth` belongs to the definition, written on `defineDb(...)` itself;\n * on a db that has been used it throws.\n */\nexport declare const defineDb: <const S extends Schema>(declared: S & ValidateRefs<S>, options?: DefineDbOptions) => Db<S>;\nexport {};\n","types/server/db/fields.d.ts":"/**\n * `t` — field builders for `model({...})`. Each builder returns an immutable `Field` carrying a runtime\n * `FieldDef` (what `.marci` is emitted from) and two phantom type parameters: the TS value type and a\n * `FieldMeta` record (kind / optional / default / …) that `defineDb`'s type layer projects into row,\n * insert, update, select and where types. Chained modifiers return a NEW field (builders are never\n * mutated), so `const s = t.string(); { a: s, b: s.optional() }` behaves as expected.\n */\nimport type { JsonValue } from \"./marci/query\";\nimport type { StoredFile, StoredImage } from \"../files/models\";\nexport type ScalarKind = \"string\" | \"int\" | \"float\" | \"bool\" | \"date\" | \"uuid\" | \"\";\nexport type FieldKind = \"scalar\" | \"json\" | \"enum\" | \"struct\" | \"one\" | \"many\" | \"list\" | \"file\";\nexport type OnDelete = \"cascade\" | \"setNull\" | \"restrict\";\n/** Phantom metadata — the type-level twin of `FieldDef`. */\nexport type FieldMeta = {\n kind: FieldKind;\n scalar: ScalarKind;\n optional: boolean;\n hasDefault: boolean;\n array: boolean;\n isId: boolean;\n /** Related model name for one/many/list; \"\" otherwise. */\n model: string;\n};\ntype DefaultMeta = {\n kind: \"scalar\";\n scalar: \"\";\n optional: false;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n};\nexport type Meta<O extends Partial<FieldMeta>> = {\n [P in keyof FieldMeta]: P extends keyof O ? O[P] : DefaultMeta[P];\n};\ntype SetMeta<M extends FieldMeta, K extends keyof FieldMeta, V> = {\n [P in keyof FieldMeta]: P extends K ? V : M[P];\n};\n/** Runtime field definition — everything the `.marci` emitter and the runtime need. */\nexport type FieldDef = {\n kind: FieldKind;\n scalar?: ScalarKind;\n optional: boolean;\n unique: boolean;\n index: boolean;\n hasDefault: boolean;\n default?: unknown;\n array: boolean;\n isId: boolean;\n onDelete?: OnDelete;\n fulltext?: \"multi\" | \"english\" | \"russian\";\n vector?: {\n size: number;\n metric: \"cosine\" | \"euclidean\";\n };\n /** enum */\n values?: readonly string[];\n /** struct */\n fields?: Record<string, Field<any, any>>;\n /** one / many / list */\n model?: string;\n /** file: a picture (`t.image()`) — `max` is the most its longer side may be, px. */\n image?: {\n max: number;\n };\n /** many: the field on the related model that holds the reference (`@bind`); resolved by defineDb when omitted. */\n back?: string;\n};\ntype DefaultOf<T, M extends FieldMeta> = M[\"scalar\"] extends \"date\" ? \"now\" | number : M[\"array\"] extends true ? T[] : T;\nexport interface Field<T, M extends FieldMeta = FieldMeta> {\n /** phantom (type-level only — never set at runtime) */ readonly __t?: T;\n /** phantom (type-level only — never set at runtime) */ readonly __m?: M;\n readonly def: FieldDef;\n /** Nullable column (`String?`). */\n optional(): Field<T, SetMeta<M, \"optional\", true>>;\n /** `@unique` (on a relation: one-to-one). */\n unique(): Field<T, M>;\n /** `@index` — used by `$where`, `$order`, aggregations. */\n index(): Field<T, M>;\n /** `@default(...)`; `\"now\"` on `t.date()` → `now()`. Makes the field optional on insert. */\n default(value: DefaultOf<T, M>): Field<T, SetMeta<M, \"hasDefault\", true>>;\n /** Primitive list (`String[]`). */\n array(): Field<T, SetMeta<M, \"array\", true>>;\n /** `@id` — primary key (several → composite). A field literally named `id` is the key implicitly. */\n id(): Field<T, SetMeta<M, \"isId\", true>>;\n /** Referential policy for `t.one()` (defaults: required → restrict, optional → setNull). */\n onDelete(policy: OnDelete): Field<T, M>;\n /** `@fulltext(...)` module index on a string field; query with `$search`. */\n fulltext(lang?: \"multi\" | \"english\" | \"russian\"): Field<T, M>;\n /** `Float[n] @vector(metric)` — nearest-neighbour index; query with `$near`. */\n vector(size: number, metric?: \"cosine\" | \"euclidean\"): Field<T, M>;\n}\nexport declare const t: {\n string: () => Field<string, Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n /** 64-bit signed integer. */\n int: () => Field<number, Meta<{\n kind: \"scalar\";\n scalar: \"int\";\n }>>;\n /** 64-bit float. */\n float: () => Field<number, Meta<{\n kind: \"scalar\";\n scalar: \"float\";\n }>>;\n bool: () => Field<boolean, Meta<{\n kind: \"scalar\";\n scalar: \"bool\";\n }>>;\n /** Epoch milliseconds — reads and writes as `number`. */\n date: () => Field<number, Meta<{\n kind: \"scalar\";\n scalar: \"date\";\n }>>;\n /** UUID string (16 bytes in storage). On an `id` field the runtime generates it on insert. */\n uuid: () => Field<string, Meta<{\n kind: \"scalar\";\n scalar: \"uuid\";\n }>>;\n /** Any JSON value; `J` is TS-only (marcidb stores it schemaless). Filter by dot-path in `$where`. */\n json: <J = JsonValue>() => Field<J, Meta<{\n kind: \"json\";\n }>>;\n /** String enum: `t.enum(\"draft\", \"published\")`. */\n enum: <const V extends readonly [string, ...string[]]>(...values: V) => Field<V[number], Meta<{\n kind: \"enum\";\n }>>;\n /** Owned nested object (marcidb `struct`): created/updated with the parent, no id of its own. */\n struct: <F extends Record<string, Field<any, any>>>(fields: F) => Field<F, Meta<{\n kind: \"struct\";\n }>>;\n /** Reference to one row of `model` (by id). Required unless `.optional()`. */\n one: <N extends string>(model: N) => Field<never, Meta<{\n kind: \"one\";\n model: N;\n }>>;\n /** Reverse side of a `t.one()` on `model` (the field is inferred when unambiguous). Read-only list. */\n many: <N extends string>(model: N, backField?: string) => Field<never, Meta<{\n kind: \"many\";\n model: N;\n }>>;\n /**\n * A stored file: written as a `File` (an upload — an endpoint's parameter), read as\n * `{ url, name, type, size, width?, height? }`. `.optional()` = may be empty, `.array()` = an ordered\n * list of files. It is deleted with its row — or when the field is given another file, or `null`.\n */\n file: () => Field<StoredFile, Meta<{\n kind: \"file\";\n }>>;\n /**\n * A stored PICTURE — a `t.file()` that takes images only and keeps them fit to show: turned the way\n * the camera meant, without its metadata (a photo's place and time), as WebP, and no larger than\n * `max` px on its longer side (2048 when not said; a picture is never enlarged).\n * Read as a `StoredFile` whose `width` and `height` are always there. A GIF is kept as it is.\n */\n image: (options?: {\n max?: number;\n }) => Field<StoredImage, Meta<{\n kind: \"file\";\n }>>;\n /** Ordered relation list stored inline (`@list`) — hand-arranged collections, duplicates allowed. */\n list: <N extends string>(model: N) => Field<never, Meta<{\n kind: \"list\";\n model: N;\n }>>;\n};\nexport type T = typeof t;\nexport {};\n","types/server/db/index.d.ts":"export { t } from \"./fields\";\nexport type { Field, FieldDef, FieldMeta } from \"./fields\";\nexport { model, defineDb, ref, setDbTransport, toMarci } from \"./defineDb\";\nexport type { DefineDbOptions } from \"./defineDb\";\nexport type { Auth, Db, DbWithAuth, UserQuery, Model, Schema, Row, Id, Insert, Update, Select, Where, Query, QueryObject, Result, Collection, ScalarSelect, Types } from \"./types\";\nexport type { Op, MarciOp, MarciTransport, JsonValue, Sub } from \"./marci/query\";\n","types/server/db/marci/query.d.ts":"export type ServiceKeys = \"$where\" | \"$order\" | \"$limit\" | \"$skip\" | \"$cursor\";\nexport type JsonValue = string | number | boolean | null | JsonValue[] | {\n [key: string]: JsonValue;\n};\nexport type AggregateKeys = {\n $count: true;\n} | {\n $sum: string;\n} | {\n $avg: string;\n} | {\n $min: string;\n} | {\n $max: string;\n};\nexport type GetResult<TModel, TSelect> = TModel extends any ? {\n -readonly [K in keyof Omit<TSelect, ServiceKeys> as TSelect[K] extends false | undefined ? never : K extends keyof TModel ? K : never]: K extends keyof TModel ? TSelect[K] extends true ? TModel[K] : TSelect[K] extends Record<string, any> ? TModel[K] extends readonly object[] ? TSelect[K] extends AggregateKeys ? AggregateResult<NonNullable<TModel[K][number]>, TSelect[K]> : GetResult<NonNullable<TModel[K][number]>, TSelect[K]>[] : GetResult<NonNullable<TModel[K]>, TSelect[K]> | Extract<TModel[K], null> : TModel[K] : never;\n} : never;\nexport type RefUpdate<I> = {\n \"$connect\"?: I;\n};\nexport type RefUpdateStruct<I, U> = {\n \"$update\"?: U;\n \"$ensure\"?: I;\n \"$set\"?: I;\n};\n/** Relation to independent rows — link operations only, the rows themselves are never created\n * or deleted. `$set` replaces link membership with exactly the given set (missing links are\n * disconnected, new ones connected); `$connect` links (idempotent); `$remove` unlinks. */\nexport type RefListUpdate<I> = {\n \"$set\"?: I[];\n \"$connect\"?: I | I[];\n \"$remove\"?: I | I[];\n};\n/** `@list` relation: an ordered inline id array — a sequence, so the same id may appear several\n * times. `$set` replaces the whole array (also the reorder operation); `$connect` appends at the\n * end (an already-present id gains another occurrence); `$connectUnique` appends only ids not\n * already present; `$remove` removes every occurrence. */\nexport type RefListUpdateOrdered<I> = {\n \"$set\"?: I[];\n \"$connect\"?: I | I[];\n \"$connectUnique\"?: I | I[];\n \"$remove\"?: I | I[];\n};\n/** Owned (struct) list: the children live and die with the parent. `$push` creates children,\n * `$update` edits single children in place (each item is the child's id fields — the shape\n * query results return — plus the changes under `data`), `$remove` deletes children by id,\n * `$set` replaces all children (deletes the current ones, creates the new). */\nexport type RefListUpdateStruct<I, U, Id> = {\n \"$push\"?: I | I[];\n \"$update\"?: (Id & {\n data: U;\n }) | (Id & {\n data: U;\n })[];\n \"$remove\"?: Id | Id[];\n \"$set\"?: I[];\n};\n/** Variable-length primitive array — a sequence, so the same value may appear several times.\n * `$push` appends at the end (duplicates kept); `$pushUnique` appends only values not already\n * present; `$remove` removes every occurrence; `$set` replaces the whole array (also the\n * positional-edit path — send the full new array). One operator per update. */\nexport type PrimitiveListUpdate<T> = {\n \"$set\"?: T[];\n \"$push\"?: T | T[];\n \"$pushUnique\"?: T | T[];\n \"$remove\"?: T | T[];\n};\nexport type Never<T> = {\n [K in keyof T]?: never;\n};\nexport type FieldOps = {\n \"$eq\": unknown;\n \"$ne\": unknown;\n \"$not\": unknown;\n \"$in\": unknown;\n \"$notIn\": unknown;\n \"$gt\": unknown;\n \"$gte\": unknown;\n \"$lt\": unknown;\n \"$lte\": unknown;\n \"$startsWith\": unknown;\n \"$includes\": unknown;\n \"$every\": unknown;\n \"$some\": unknown;\n \"$none\": unknown;\n \"$near\": unknown;\n \"$search\": unknown;\n};\nexport type Only<K extends keyof FieldOps, V> = {\n [P in K]: V;\n} & Never<Omit<FieldOps, K>>;\nexport type WhereValue<T> = (T & Never<{\n \"$and\": unknown;\n \"$or\": unknown;\n \"$not\": unknown;\n}>) | ({\n \"$and\": WhereValue<T>[];\n} & Never<T> & Never<{\n \"$or\": unknown;\n \"$not\": unknown;\n}>) | ({\n \"$or\": WhereValue<T>[];\n} & Never<T> & Never<{\n \"$and\": unknown;\n \"$not\": unknown;\n}>) | ({\n \"$not\": WhereValue<T>;\n} & Never<T> & Never<{\n \"$and\": unknown;\n \"$or\": unknown;\n}>);\nexport type ValueOps<T> = {\n \"$eq\"?: T;\n \"$ne\"?: T;\n \"$not\"?: T;\n \"$in\"?: T[];\n \"$notIn\"?: T[];\n};\nexport type NumOps<T> = {\n \"$gt\"?: T;\n \"$gte\"?: T;\n \"$lt\"?: T;\n \"$lte\"?: T;\n};\nexport type StrOps = {\n \"$includes\"?: string;\n \"$startsWith\"?: string;\n};\nexport type CompareValue<T> = T | (ValueOps<T> & Never<Omit<FieldOps, keyof ValueOps<T>>>);\nexport type CompareNumValue<T> = ValueOps<T> & NumOps<T> & Never<Omit<FieldOps, keyof ValueOps<T> | keyof NumOps<T>>>;\nexport type CompareStrValue<T> = ValueOps<T> & StrOps & Never<Omit<FieldOps, keyof ValueOps<T> | keyof StrOps>>;\nexport type UpdateNumValue = {\n \"$increment\": number;\n};\nexport type JsonType = \"string\" | \"number\" | \"boolean\" | \"object\" | \"array\" | \"null\";\nexport type JsonCondition = JsonValue | {\n \"$eq\"?: JsonValue;\n \"$ne\"?: JsonValue;\n \"$not\"?: JsonValue;\n \"$gt\"?: number | string;\n \"$gte\"?: number | string;\n \"$lt\"?: number | string;\n \"$lte\"?: number | string;\n \"$in\"?: JsonValue[];\n \"$notIn\"?: JsonValue[];\n \"$startsWith\"?: string;\n \"$includes\"?: string;\n \"$contains\"?: JsonValue;\n \"$exists\"?: boolean;\n \"$type\"?: JsonType;\n};\nexport type JsonPathWhere = {\n [path: string]: JsonCondition;\n};\nexport type CompareRefValue<T> = T | Only<\"$not\", T>;\nexport type CompareRefListValue<T> = Only<\"$every\", T> | Only<\"$some\", T> | Only<\"$none\", T>;\nexport type VectorSearch = {\n vector: number[];\n k?: number;\n threshold?: number;\n};\nexport type FullTextSearch = string | {\n query: string;\n limit?: number;\n};\nexport type CustomSearch = Record<string, any>;\nexport type CustomSearchValue<P> = Only<\"$near\", P> | Only<\"$search\", P>;\nexport type AggregateResult<TModel, T> = (T extends {\n $count: true;\n} ? {\n count: number;\n} : {}) & (T extends {\n $sum: string;\n} ? {\n sum: number | null;\n} : {}) & (T extends {\n $avg: string;\n} ? {\n avg: number | null;\n} : {}) & (T extends {\n $min: infer F;\n} ? {\n min: (F extends keyof TModel ? TModel[F] : never) | null;\n} : {}) & (T extends {\n $max: infer F;\n} ? {\n max: (F extends keyof TModel ? TModel[F] : never) | null;\n} : {});\ndeclare const __op: unique symbol;\nexport type Op<T> = PromiseLike<T> & {\n readonly [__op]: T;\n};\nexport type MarciOp = {\n model: string;\n action: string;\n query?: any;\n data?: any;\n id?: any;\n journal?: JournalArgs;\n};\n/** The arguments of a journal action (`$journalOpen` / `$journalRead` / `$journalDrop`). `wait` is in seconds. */\nexport type JournalArgs = {\n name: string;\n on?: readonly JournalOp[];\n after?: number;\n limit?: number;\n wait?: number;\n};\nexport type MarciTransport = {\n exec(op: MarciOp): Promise<any>;\n batch(ops: MarciOp[]): Promise<any[]>;\n};\nexport type ModelTypes = {\n name: string;\n model: any;\n id: Record<string, any>;\n /** What an empty select returns: id + every scalar field, as a `{ field: true }` shape. */\n scalars: Record<string, true>;\n select: Record<string, any>;\n query: Record<string, any>;\n where: any;\n order: Record<string, any>;\n insert: any;\n update: any;\n aggregate: Record<string, any>;\n reindex: boolean;\n};\ndeclare const __sub: unique symbol;\ndeclare const __sel: unique symbol;\nexport type Sub<Name extends string, Shape = any> = {\n readonly [__sub]: Name;\n readonly [__sel]: Shape;\n};\nexport type Effective<T extends ModelTypes, S> = [Exclude<keyof S, ServiceKeys>] extends [never] ? T[\"scalars\"] : S;\nexport type Resolve<S> = S extends {\n readonly [__sel]: infer X;\n} ? Resolve<X> : S extends object ? {\n [K in keyof S]: K extends `$${string}` ? S[K] : Resolve<S[K]>;\n} : S;\nexport type Rows<T extends ModelTypes, Sel> = GetResult<T[\"model\"], Resolve<Effective<T, Sel>>>;\nexport type BareId<I> = I extends {\n id: infer V;\n} ? V : never;\nexport type IdArg<I> = I | BareId<I>;\n/**\n * A lazy, immutable query over one model — `db.user` itself is one. Every clause returns a new query, so\n * queries compose (`const active = db.user.where({ active: true })`). `await` runs it as `findMany`; passing\n * it to `$transaction` batches it; placing it in another query's select makes it a sub-select. `Sel` is the\n * projection: id + scalars until `select(...)` sets a shape.\n */\nexport interface Query<T extends ModelTypes, Sel = T[\"scalars\"]> extends PromiseLike<Rows<T, Sel>[]> {\n readonly [__op]: Rows<T, Sel>[];\n readonly [__sub]: T[\"name\"];\n readonly [__sel]: Effective<T, Sel>;\n /** Filter (marcidb `$where`). Repeated calls are ANDed. */\n where(where: T[\"where\"]): Query<T, Sel>;\n /** Sort by one field: `order(\"age\", \"desc\")` or `order({ age: \"desc\" })`. */\n order(field: keyof T[\"order\"] & string, direction?: \"asc\" | \"desc\"): Query<T, Sel>;\n order(order: T[\"order\"]): Query<T, Sel>;\n limit(n: number): Query<T, Sel>;\n skip(n: number): Query<T, Sel>;\n /** Keyset cursor: rows strictly after this id in the current order (`$cursor`). */\n after(id: IdArg<T[\"id\"]>): Query<T, Sel>;\n /**\n * The projection. Values are `true`, a nested shape, or a sub-query of the relation's model\n * (`posts: db.post.limit(5)`, `posts: db.post.where({ published: true }).count()`). No argument, or no\n * field keys, selects id + every scalar. `$`-clauses are accepted here too (the object form).\n */\n select<S extends T[\"query\"] = T[\"scalars\"]>(shape?: S): Query<T, S>;\n /** The first matching row or `null`. */\n first(): Op<Rows<T, Sel> | null>;\n /** Row count; inside a select it becomes `{ count }` for the relation. */\n count(): Op<number> & Sub<T[\"name\"], {\n $count: true;\n }>;\n /** @deprecated pass the filter through the chain: `db.user.where(w).count()` (removed in the next minor). */\n count(query: {\n $where?: T[\"where\"];\n }): Op<number> & Sub<T[\"name\"], {\n $count: true;\n }>;\n aggregate<A extends T[\"aggregate\"]>(query: A): Op<AggregateResult<T[\"model\"], A>> & Sub<T[\"name\"], NoInfer<A>>;\n insert(data: T[\"insert\"]): Op<T[\"id\"]>;\n update(id: IdArg<T[\"id\"]>, data: T[\"update\"]): Op<void>;\n /** Applies `data` to every row the chain's `where` matches (all rows without one); resolves to the number of rows. */\n updateMany(data: T[\"update\"]): Op<number>;\n /** @deprecated pass the filter through the chain: `db.user.where(w).updateMany(data)` (removed in the next minor). */\n updateMany(query: {\n $where?: T[\"where\"];\n }, data: T[\"update\"]): Op<number>;\n delete(id: IdArg<T[\"id\"]>): Op<void>;\n /**\n * Deletes every row the chain's `where` matches (cascades apply, as for `delete`); resolves to the number\n * deleted. Refuses to run without a `where` — write `.where({})` to mean \"every row\".\n */\n deleteMany(): Op<number>;\n /** @deprecated use `.select(query)` — it takes the same object, merged with the chain (removed in the next minor). */\n findMany<Q extends T[\"query\"] = {}>(query?: Q): Op<Rows<T, Q>[]>;\n /** @deprecated use `.select(query).first()` (removed in the next minor). */\n findFirst<Q extends T[\"query\"] = {}>(query?: Q): Op<Rows<T, Q> | null>;\n}\n/** What a journal can record. Only deletes so far. */\nexport type JournalOp = \"delete\";\n/** One recorded change. `row` is the row as it last was: its id and every scalar field. */\nexport type JournalEntry<T extends ModelTypes, O extends JournalOp = JournalOp> = {\n seq: number;\n op: O;\n row: Rows<T, T[\"scalars\"]>;\n};\nexport type JournalOptions<O extends JournalOp> = {\n /** The operations to record. A journal that exists with other ones is an error, not a redefinition. */\n on: O | readonly O[];\n /** `false`: the loop ends when the journal is read through. By default it waits for the next entry. */\n wait?: boolean;\n};\n/**\n * A named, durable log of a model's changes. It starts recording when it is first asked for and keeps\n * every entry until the loop that reads it has moved past it — an entry whose loop body threw, or that\n * was never reached, is delivered again to the next reader of the same name.\n */\nexport interface Journal<T extends ModelTypes, O extends JournalOp = JournalOp> extends AsyncIterable<JournalEntry<T, O>> {\n /** Drops the journal with whatever it still holds; the model's writes stop paying for it. */\n drop(): Promise<void>;\n}\n/**\n * `db.<model>`: the root query, plus `reindex()` for models with a `@custom` (vector / full-text) index and\n * `$journal(name, { on })` — the journal of this model's changes under that name, created on first use.\n */\nexport type Collection<T extends ModelTypes> = Query<T> & (T[\"reindex\"] extends true ? {\n reindex(): Op<{\n ok: boolean;\n indexed: number;\n }>;\n} : {}) & {\n $journal<O extends JournalOp>(name: string, options: JournalOptions<O>): Journal<T, O>;\n};\n/** One field of a model, in slot order: `n` name, `k` key | body | one | many, `m` the relation's target model. */\nexport type FieldDesc = {\n n: string;\n k: \"key\" | \"body\" | \"one\" | \"many\";\n t?: string | null;\n m?: string;\n};\n/** Model name → its field descriptors (structs included, as relation targets). */\nexport type ModelsMeta = Record<string, readonly FieldDesc[]>;\nexport type QueryLayerOptions = {\n models: ModelsMeta;\n /** Runs one operation (a query, or a write) and resolves its result. */\n run(op: MarciOp): Promise<any>;\n /** Hook for `insert` payloads (the lecodes SDK generates uuid ids here). */\n prepareInsert?(model: string, data: any): any;\n};\n/**\n * The query builder over a set of models and a `run` function. Returns `op(descriptor)` — a lazy operation\n * (`await` runs it, `$transaction` takes its `__op`) — and `collection(model)`, the immutable `db.<model>`\n * root query. Transport-agnostic: the generated client and the embedded/HTTP transports supply `run`.\n */\nexport declare function createQueryLayer(options: QueryLayerOptions): {\n op: (descriptor: MarciOp) => any;\n collection: (model: string) => any;\n};\nexport {};\n","types/server/db/types.d.ts":"/**\n * Type layer: projects a `defineDb({ User: model({...}), … })` literal into marcidb's generic query\n * types (./marci/query.ts — vendored from marcidb, see scripts/sync-marcidb.ts): each model becomes the\n * `ModelTypes` bag marcidb's codegen would have emitted, and `db.<model>` is marcidb's own `Query<T>`.\n * Everything here is type-only; the runtime lives in ./defineDb.ts.\n *\n * Naming: `S` = the schema record (model name → Model), `N` = a model name, `F` = a fields record.\n */\nimport type { Field, FieldMeta } from \"./fields\";\nimport type { IdentityPublicFields, SessionPublicFields } from \"../auth/models\";\nimport type { StoredFile, UploadedFile as File } from \"../files/models\";\nimport type { CompareNumValue, CompareRefListValue, CompareRefValue, CompareStrValue, CompareValue, CustomSearchValue, FullTextSearch, JsonCondition, JsonPathWhere, Op, PrimitiveListUpdate, Query as MarciQuery, RefListUpdate, RefListUpdateOrdered, RefUpdate, RefUpdateStruct, Rows, Sub, UpdateNumValue, VectorSearch, WhereValue } from \"./marci/query\";\nexport type Fields = Record<string, Field<any, any>>;\nexport type Model<F extends Fields = Fields> = {\n readonly fields: F;\n readonly __model: true;\n};\nexport type Schema = Record<string, Model<any>>;\nexport type FieldsOf<M> = M extends Model<infer F> ? F : never;\ntype TsOf<Fld> = Fld extends Field<infer T, any> ? T : never;\ntype StructFieldsOf<Fld> = TsOf<Fld> extends Fields ? TsOf<Fld> : never;\ntype MetaOf<Fld> = Fld extends Field<any, infer M> ? M : never;\ntype ModelName<S, Fld> = MetaOf<Fld>[\"model\"] & keyof S & string;\ntype Nullable<M extends FieldMeta, T> = M[\"optional\"] extends true ? T | null : T;\ntype Arr<M extends FieldMeta, T> = M[\"array\"] extends true ? T[] : T;\ntype IsNum<M extends FieldMeta> = M[\"scalar\"] extends \"int\" | \"float\" | \"date\" ? true : false;\n/** Explicit `.id()` fields, or a field literally named `id`. */\ntype IdKeys<F extends Fields> = {\n [K in keyof F]: MetaOf<F[K]>[\"isId\"] extends true ? K : K extends \"id\" ? K : never;\n}[keyof F];\ntype IdValue<S, Fld> = MetaOf<Fld>[\"kind\"] extends \"one\" ? Id<S, ModelName<S, Fld>> : TsOf<Fld>;\n/** The id object of a model: `{ id: number }` implicitly, or the declared key fields. */\nexport type Id<S, N extends keyof S> = [\n IdKeys<FieldsOf<S[N]>>\n] extends [never] ? {\n id: number;\n} : {\n [K in IdKeys<FieldsOf<S[N]>>]: IdValue<S, FieldsOf<S[N]>[K]>;\n};\n/** What `update`/`delete` accept: the id object, or the bare value when the key is a single scalar. */\nexport type IdArg<S, N extends keyof S> = Id<S, N> | (Id<S, N> extends {\n id: infer V;\n} ? V : never);\ntype FieldRow<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Nullable<M, Row<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"many\" | \"list\" ? Row<S, ModelName<S, Fld>>[] : M[\"kind\"] extends \"struct\" ? Nullable<M, StructRow<S, StructFieldsOf<Fld>>> : Nullable<M, Arr<M, TsOf<Fld>>>;\n/** Full row type of a model (relations included) — the `TModel` marcidb's `GetResult` selects from. */\nexport type Row<S, N extends keyof S> = Id<S, N> & {\n [K in Exclude<keyof FieldsOf<S[N]>, IdKeys<FieldsOf<S[N]>>>]: FieldRow<S, FieldsOf<S[N]>[K]>;\n};\ntype StructRow<S, F extends Fields> = {\n [K in keyof F]: FieldRow<S, F[K]>;\n};\n/** What a query without a selection returns besides the id: the scalars, and the files. */\ntype ScalarKeys<F extends Fields> = {\n [K in keyof F]: MetaOf<F[K]>[\"kind\"] extends \"scalar\" | \"enum\" | \"json\" | \"file\" ? K : never;\n}[keyof F];\n/** The fields a row is ordered and aggregated by. */\ntype ValueKeys<F extends Fields> = {\n [K in keyof F]: MetaOf<F[K]>[\"kind\"] extends \"scalar\" | \"enum\" | \"json\" ? K : never;\n}[keyof F];\ntype NumKeys<F extends Fields> = {\n [K in keyof F]: IsNum<MetaOf<F[K]>> extends true ? (MetaOf<F[K]>[\"array\"] extends true ? never : K) : never;\n}[keyof F];\n/** What an empty select returns: id + every scalar field. */\nexport type Scalars<S, N extends keyof S> = Pick<Row<S, N>, (ScalarKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>>;\n/** The same, as the `{ field: true }` select shape a query starts with. */\nexport type ScalarSelect<S, N extends keyof S> = {\n [K in (ScalarKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>]: true;\n};\ntype FieldInsert<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Nullable<M, Id<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"many\" | \"list\" ? Id<S, ModelName<S, Fld>>[] : M[\"kind\"] extends \"struct\" ? Nullable<M, StructInsert<S, StructFieldsOf<Fld>>> : M[\"kind\"] extends \"file\" ? Nullable<M, Arr<M, File>> : Nullable<M, Arr<M, TsOf<Fld>>>;\ntype RequiredKeys<F extends Fields> = {\n [K in keyof F]: K extends IdKeys<F> ? never : MetaOf<F[K]>[\"optional\"] extends true ? never : MetaOf<F[K]>[\"hasDefault\"] extends true ? never : MetaOf<F[K]>[\"kind\"] extends \"many\" | \"list\" ? never : MetaOf<F[K]>[\"kind\"] extends \"file\" ? (MetaOf<F[K]>[\"array\"] extends true ? never : K) : K;\n}[keyof F];\ntype Simplify<T> = {\n [K in keyof T]: T[K];\n} & {};\ntype InsertOf<S, F extends Fields> = Simplify<{\n [K in RequiredKeys<F>]: FieldInsert<S, F[K]>;\n} & {\n [K in Exclude<keyof F, RequiredKeys<F>>]?: FieldInsert<S, F[K]>;\n}>;\nexport type Insert<S, N extends keyof S> = InsertOf<S, FieldsOf<S[N]>>;\ntype StructInsert<S, F extends Fields> = InsertOf<S, F>;\ntype FieldUpdate<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Nullable<M, RefUpdate<Id<S, ModelName<S, Fld>>>> : M[\"kind\"] extends \"many\" ? RefListUpdate<Id<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"list\" ? RefListUpdateOrdered<Id<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"struct\" ? RefUpdateStruct<StructInsert<S, StructFieldsOf<Fld>>, UpdateOf<S, StructFieldsOf<Fld>>> | null : M[\"kind\"] extends \"file\" ? Nullable<M, Arr<M, File | StoredFile>> : M[\"array\"] extends true ? TsOf<Fld>[] | PrimitiveListUpdate<TsOf<Fld>> : Nullable<M, TsOf<Fld> | (IsNum<M> extends true ? UpdateNumValue : never)>;\ntype UpdateOf<S, F extends Fields> = {\n [K in Exclude<keyof F, IdKeys<F>>]?: FieldUpdate<S, F[K]>;\n};\nexport type Update<S, N extends keyof S> = UpdateOf<S, FieldsOf<S[N]>>;\ntype FieldSelect<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? Select<S, ModelName<S, Fld>> | boolean | Sub<ModelName<S, Fld>> : M[\"kind\"] extends \"many\" | \"list\" ? QueryObject<S, ModelName<S, Fld>> | AggregateQuery<S, ModelName<S, Fld>> | boolean | Sub<ModelName<S, Fld>> : M[\"kind\"] extends \"struct\" ? StructSelect<S, StructFieldsOf<Fld>> | boolean : boolean;\nexport type Select<S, N extends keyof S> = {\n [K in keyof Row<S, N>]?: K extends keyof FieldsOf<S[N]> ? FieldSelect<S, FieldsOf<S[N]>[K]> : boolean;\n};\ntype StructSelect<S, F extends Fields> = {\n [K in keyof F]?: FieldSelect<S, F[K]>;\n};\ntype ScalarWhere<T, M extends FieldMeta> = Nullable<M, CompareValue<T>> | (IsNum<M> extends true ? CompareNumValue<T> : M[\"scalar\"] extends \"string\" ? CompareStrValue<T> : never);\ntype FieldWhere<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M[\"kind\"] extends \"one\" ? CompareRefValue<Where<S, ModelName<S, Fld>> | null> : M[\"kind\"] extends \"many\" | \"list\" ? CompareRefListValue<Where<S, ModelName<S, Fld>>> : M[\"kind\"] extends \"struct\" ? CompareRefValue<WhereValue<StructWhereFields<S, StructFieldsOf<Fld>>> | null> : M[\"kind\"] extends \"json\" ? JsonPathWhere | JsonCondition : M[\"kind\"] extends \"file\" ? never : M[\"array\"] extends true ? TsOf<Fld>[] : ScalarWhere<TsOf<Fld>, M> | CustomSearchValue<FullTextSearch> | CustomSearchValue<VectorSearch>;\ntype WhereFieldsOf<S, F extends Fields> = {\n [K in keyof F]?: FieldWhere<S, F[K]>;\n};\ntype IdWhere<S, N extends keyof S> = {\n [K in keyof Id<S, N> as K extends keyof FieldsOf<S[N]> ? never : K]?: CompareValue<Id<S, N>[K]> | CompareNumValue<number>;\n};\nexport type Where<S, N extends keyof S> = WhereValue<WhereFieldsOf<S, FieldsOf<S[N]>> & IdWhere<S, N>>;\ntype StructWhereFields<S, F extends Fields> = WhereFieldsOf<S, F>;\ntype OrderKeys<S, N extends keyof S> = (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>;\n/** ONE field and its direction: the engine sorts by a single field, so a second key is a type error. */\nexport type Order<S, N extends keyof S> = {\n [K in OrderKeys<S, N>]: {\n [P in K]: \"asc\" | \"desc\";\n } & {\n [P in Exclude<OrderKeys<S, N>, K>]?: never;\n };\n}[OrderKeys<S, N>];\n/** The query object — marcidb's wire form: a select shape plus the `$`-clauses. */\nexport type QueryObject<S, N extends keyof S> = Select<S, N> & {\n $where?: Where<S, N>;\n $order?: Order<S, N>;\n $limit?: number;\n $skip?: number;\n $cursor?: Id<S, N>;\n};\nexport type AggregateQuery<S, N extends keyof S> = {\n $where?: Where<S, N>;\n $count?: true;\n $sum?: NumKeys<FieldsOf<S[N]>> & string;\n $avg?: NumKeys<FieldsOf<S[N]>> & string;\n $min?: (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & string;\n $max?: (ValueKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & string;\n};\n/** The per-model type bag marcidb's generic `Query<T>` is parametrised by (what its codegen emits as `UserTypes`). */\nexport type Types<S, N extends keyof S> = {\n name: N & string;\n model: Row<S, N>;\n id: Id<S, N>;\n scalars: ScalarSelect<S, N>;\n select: Select<S, N>;\n query: QueryObject<S, N>;\n where: Where<S, N>;\n order: Order<S, N>;\n insert: Insert<S, N>;\n update: Update<S, N>;\n aggregate: AggregateQuery<S, N>;\n reindex: false;\n};\n/**\n * `db.<model>` — marcidb's lazy, immutable query over one model: clauses (`where/order/limit/skip/after`)\n * return a new query, `select(shape)` sets the projection, `await` runs it, `first/count/aggregate` terminate,\n * `updateMany(data)`/`deleteMany()` write through the chain's `where`; a query placed in another query's\n * select is a sub-query. `Sel` is the projection: id + scalars until `select(...)` sets a shape.\n */\nexport type Query<S, N extends keyof S, Sel = ScalarSelect<S, N>> = MarciQuery<Types<S, N>, Sel>;\n/** The rows a query with projection `Q` resolves to (no field keys = id + scalars; sub-queries resolved). */\nexport type Result<S, N extends keyof S, Q> = Rows<Types<S, N>, Q>;\n/** `db.<model>` — the root query of a model. */\nexport type Collection<S, N extends keyof S> = Query<S, N>;\n/** The platform's models a project's own may point at (`t.one(\"Session\")`) — see ../auth/models.ts. */\ntype PlatformModels = {\n Session: Model<SessionPublicFields>;\n};\n/** What a db's queries are typed against: the project's models and what they may point at. */\ntype Full<S> = S & PlatformModels;\ntype DbBase<S extends Schema> = {\n [N in keyof S & string as Uncapitalize<N>]: Query<Full<S>, N>;\n} & {\n /** Atomic batch: all ops commit or none. `ref(\"0.id\")` feeds a generated id into a later op. */\n $transaction<P extends readonly Op<any>[]>(ops: [...P]): Promise<{\n [K in keyof P]: P[K] extends Op<infer T> ? T : never;\n }>;\n /** The `.marci` schema text this db syncs with. */\n readonly $schema: string;\n};\nexport type Db<S extends Schema> = DbBase<S> & {\n /**\n * Sign-in for this database: `model` is the project's model of a user. Adds the platform's `Session`\n * and `Identity` models beside it and gives the db its `auth`. Part of the definition — call it on\n * `defineDb(...)` itself, before the db is used. Every field of the user model must be optional or\n * have a default: the platform creates the row the first time someone signs in.\n */\n withAuth<N extends keyof S & string>(options: {\n model: N;\n }): DbWithAuth<S, N>;\n};\nexport type DbWithAuth<S extends Schema, N extends keyof S & string> = DbBase<S> & {\n readonly auth: Auth<S, N>;\n};\n/**\n * The user of the current request, as a query over the project's user model: `select(shape)` picks the\n * fields (id + scalars without it), `await` runs it. Nothing happens until it is awaited — a query that\n * is never awaited checks nothing, which is why the compiler refuses one.\n */\nexport interface UserQuery<S, N extends keyof S, Sel, Nil> extends PromiseLike<Result<S, N, Sel> | Nil> {\n select<Q extends Select<S, N>>(shape: Q): UserQuery<S, N, Q, Nil>;\n}\ntype AuthTables = {\n Session: Model<SessionPublicFields>;\n Identity: Model<IdentityPublicFields>;\n};\n/** `db.auth` — see ../auth/api.ts. */\nexport type Auth<S extends Schema, N extends keyof S & string> = {\n /** The signed-in user, or `null` for a guest. */\n user(): UserQuery<Full<S>, N, ScalarSelect<Full<S>, N>, null>;\n /**\n * The signed-in user; a guest is a 401. With `where` it is a check of access too: a user the filter\n * does not match is a 403 — `await db.auth.requireUser({ role: \"admin\" }).select({ id: true })`.\n */\n requireUser(where?: Where<Full<S>, N>): UserQuery<Full<S>, N, ScalarSelect<Full<S>, N>, never>;\n /** The device's session — there from the first request, before any sign-in (a guest's cart points at it). */\n readonly sessionId: number;\n /** A new account: `login` is an email or a name (3–32 letters, digits, `. _ -`), `data` the fields of the\n * user's row. 409 when the login is taken. Signs this device in. */\n signUpWithPassword(login: string, password: string, data?: Insert<Full<S>, N>): Promise<void>;\n /** Signs this device in; 401 on any failure (rate-limited per login and ip). */\n signInWithPassword(login: string, password: string): Promise<void>;\n /** Sets the current user's password; every other device is signed out. */\n setPassword(password: string): Promise<void>;\n /** Emails a 6-digit code (always resolves — no \"email exists\" oracle; rate-limited). */\n sendCode(email: string): Promise<void>;\n /** Checks the code sent to this device, finds or creates the user, signs this device in. */\n signInWithCode(email: string, code: string): Promise<void>;\n /** For a person the project verified itself (a provider's sign-in, Telegram initData, SSO): binds this device to the user. */\n signIn(userId: number): Promise<void>;\n /** The device stays, as a guest. */\n signOut(): Promise<void>;\n /** The current user's devices, as a query: `await`, `.select()`, `.where(...).updateMany({ revoked: true })`. */\n readonly sessions: Query<AuthTables, \"Session\">;\n /** How the current user signs in, as a query: provider (`\"email\"` | `\"login\"`), subject, verifiedAt. */\n readonly identities: Query<AuthTables, \"Identity\">;\n};\ntype RelKinds = \"one\" | \"many\" | \"list\";\ntype CheckField<S, Fld> = MetaOf<Fld>[\"kind\"] extends RelKinds ? MetaOf<Fld>[\"model\"] extends keyof S | keyof PlatformModels ? Fld : `Unknown model \"${MetaOf<Fld>[\"model\"]}\" — not a key of defineDb({...})` : Fld;\n/** Intersected with `S` in `defineDb`'s parameter: an unknown relation target fails to type-check on that field. */\nexport type ValidateRefs<S extends Schema> = {\n [N in keyof S]: {\n readonly fields: {\n [K in keyof FieldsOf<S[N]>]: CheckField<S, FieldsOf<S[N]>[K]>;\n };\n };\n};\nexport {};\n","types/server/errors.d.ts":"/**\n * `throw new ApiError(404, \"Not found\")` inside an endpoint → the client's promise rejects with the\n * same status + message. Any other throw is a 500 (message hidden, logged to the server console).\n */\nexport declare class ApiError extends Error {\n readonly status: number;\n constructor(status: number, message?: string);\n}\n","types/server/files/db.d.ts":"/**\n * The db layer's half of stored files (./models.ts): what turns a file FIELD — a value in a row — into\n * operations on the platform's `File` model, and back.\n *\n * read the field is selected as the reverse relation it is (the `File` rows that point at the\n * row, in order) and comes back as a `StoredFile`, or a list of them\n * insert the row is inserted without the field; each upload's `File` row is then pointed at it\n * (`ref` to the insert's id) — one transaction\n * update the row's files that are no longer listed are deleted, the uploads are pointed at it —\n * one transaction with the update itself\n *\n * An upload written to a `t.image()` field is first made a picture fit to show (the host's work,\n * ./host.ts): that is why a plan is awaited. What it became — its type, its size — goes to its row\n * in the operation that attaches it.\n *\n * A file is written from the FILE's side (its reference to the owner): that is the side the database\n * cascades over. Only an upload of the current request is ever attached: a `StoredFile` the app hands\n * back means \"keep this one\", and one of another row is not moved — a client that knows the url of\n * someone else's file cannot take it.\n */\nimport type { MarciOp } from \"../db/marci/query\";\nimport { type FileField } from \"./models\";\ntype Plan = {\n op: MarciOp;\n after: MarciOp[];\n};\nexport type FileLayer = {\n /** The operation as the database runs it, and the ones that follow it in the same transaction.\n * `index` is the operation's place in that transaction (what `ref` counts from). */\n plan(op: MarciOp, index: number): Promise<Plan>;\n /** The database's answer to a planned operation, as the project reads it. */\n result(op: MarciOp, value: any): any;\n};\n/**\n * `fields`: the schema's `t.file()` fields. `relations`: model → relation field → its target model.\n * `scalars`: model → what a query without a selection returns (file fields included).\n */\nexport declare const createFileLayer: (fields: FileField[], relations: Record<string, Record<string, string>>, scalars: Record<string, string[]>) => FileLayer;\nexport {};\n","types/server/files/models.d.ts":"/**\n * Stored files: `t.file()` on a model.\n *\n * A project never declares where a file lives. A model that has a `t.file()` field makes the db carry\n * one more model, the PLATFORM's `File` — a row per stored file: what it is (name, type, size, an\n * image's dimensions) and whose it is. The owner is a reference FROM the file TO its row, with\n * `onDelete(\"cascade\")`, one optional reference per `t.file()` field of the schema (`postImage`,\n * `userAvatar`): deleting a post — by name, or because its author was deleted — deletes its files in\n * the same transaction, by the database's own rule. The field on the owner is the reverse side of\n * that reference.\n *\n * The bytes are the host's (./host.ts): a file on disk named by the row's id. They go only because\n * the row went — the host reads the deletions from marcidb's journal of this model.\n *\n * What a project sees is a VALUE: it writes a `File` (an upload, an endpoint's parameter) and reads a\n * `StoredFile`. The url is computed when the row is read, never stored.\n */\nimport { type Field } from \"../db/fields\";\nexport declare const FILE_MODEL = \"File\";\n/** A stored file as a project reads it. */\nexport type StoredFile = {\n /** Where the bytes are served from. Public, not guessable; it never changes for this file. */\n url: string;\n name: string;\n /** The media type: `image/jpeg`, `video/mp4`, `application/pdf`. */\n type: string;\n /** Bytes. */\n size: number;\n /** An image's dimensions in pixels (absent for anything else). */\n width?: number;\n height?: number;\n};\n/** A stored picture (`t.image()`): its size is always known. */\nexport type StoredImage = StoredFile & {\n width: number;\n height: number;\n};\n/**\n * A file as an endpoint receives it — the app's `File` (a picked file, a photo), uploaded with the\n * call. Written to a `t.file()` field, it is stored; an endpoint that writes it nowhere drops it.\n */\nexport type UploadedFile = {\n readonly name: string;\n readonly size: number;\n readonly type: string;\n};\n/** One `t.file()` field of the schema; `image` = it is a `t.image()`, with its rule. */\nexport type FileField = {\n model: string;\n key: string;\n array: boolean;\n owner: string;\n image?: ImageRule;\n};\nexport type ImageRule = {\n max: number;\n};\n/** What a file became when it was made fit for an image field: the facts its row carries from then on. */\nexport type ImageFacts = {\n name: string;\n type: string;\n size: number;\n width: number;\n height: number;\n};\n/** The reference on `File` that says \"I am this field of that row\": `Post.image` → `postImage`. */\nexport declare const fileOwnerKey: (model: string, key: string) => string;\n/** What a data browser may show of a file (the rest is the platform's bookkeeping). */\nexport declare const filePublicFields: () => {\n name: Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n type: Field<string, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"string\";\n }>>;\n size: Field<number, import(\"../db/fields\").Meta<{\n kind: \"scalar\";\n scalar: \"int\";\n }>>;\n width: Field<number, {\n kind: \"scalar\";\n scalar: \"int\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n height: Field<number, {\n kind: \"scalar\";\n scalar: \"int\";\n optional: true;\n hasDefault: false;\n array: false;\n isId: false;\n model: \"\";\n }>;\n createdAt: Field<number, {\n kind: \"scalar\";\n scalar: \"date\";\n optional: false;\n hasDefault: true;\n array: false;\n isId: false;\n model: \"\";\n }>;\n};\n/** The whole `File` of a schema with these `t.file()` fields. */\nexport declare const fileFields: (fields: FileField[]) => Record<string, Field<any, any>>;\n/**\n * What the host (./host.ts) gives the db layer of a bundle — a global, because the bundle carries its\n * own copy of this module. Absent (a unit test without a host): nothing is an upload, urls are relative.\n */\nexport type FilesSeam = {\n /** The id of the `File` row behind an upload of the current request; undefined for anything else —\n * a value the app sent as JSON is never an upload, whatever it looks like. */\n uploaded(value: unknown): string | undefined;\n url(id: string, name: string): string;\n /** Make the upload `id` fit for a `t.image()` field (its bytes are rewritten in place) and say what\n * it is now. Throws an `ApiError` for what is no picture. */\n image(id: string, rule: ImageRule): Promise<ImageFacts>;\n /** A write that may have removed rows of `File` went through the db (a delete, a rewritten file field): their bytes are due. */\n dirty: boolean;\n};\nexport declare const filesSeam: () => FilesSeam | undefined;\nexport declare const setFilesSeam: (value: FilesSeam | null) => void;\n/** The row a `StoredFile` the app handed back stands for (by its url); undefined for anything else. */\nexport declare const storedFileId: (value: unknown) => string | undefined;\nexport declare const fileUrl: (id: string, name: string) => string;\n","types/server/inject.d.ts":"export { t, model, defineDb, ref } from \"./db\";\nexport { ApiError } from \"./errors\";\nexport { channel } from \"./channel\";\nexport { request } from \"./context\";\nexport type { StoredFile, StoredImage } from \"./files/models\";\n","types/ui/colorKeys.gen.d.ts":"/** The keys whose value IS a color — every color property with its aliases: normalize the value\n * to '#rrggbbaa'. Pass-throughs: null / undefined (a reset), any string containing \"var(\" (the\n * core resolves theme vars), rippleColor's \"default\" (a core keyword). */\nexport declare const COLOR_KEYS: ReadonlySet<string>;\n/** The shorthands that expand into a color property. A color is only ONE of their value forms:\n * never normalize the value whole — \"2px solid red\", a gradient or an image path go to the core\n * raw (its shorthand parsers read the colors inside with the same grammar), a number on\n * `border*` is a WIDTH; only a number / color array on `background` is a color. */\nexport declare const COLOR_SHORTHAND_KEYS: ReadonlySet<string>;\n","types/ui/fonts.d.ts":"type FontOptions = {\n weight?: number;\n style?: \"normal\" | \"italic\";\n};\n/** Register a font face from a URL at runtime under `fontFamily`; resolves once it's ready to\n * use in styles. For registry/project fonts prefer the compile-time `font()` macro — this is the\n * dynamic escape hatch. */\nexport declare function registerFont(fontFamily: string, url: string, options?: FontOptions): Promise<void>;\nexport {};\n","types/ui/NativeView.d.ts":"import { type UIWidgetContent } from \"./UILayer\";\nimport { type DismissOptions, type PresentOptions } from \"./presentable\";\nimport { type BaseStyle, type DrawableStyle, type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UINativeViewStyle = ElementStyle & DrawableStyle;\n/** An instance of a host-registered platform view (map, QR scanner, camera preview, …) —\n * embeddable among a screen's children AND fullscreen-presentable (`open()`); one instance lives\n * in one place at a time. Talk to it via the `call`/`on` channel. */\nexport interface NativeView extends UIElementBase<UINativeViewStyle, DrawableStyle & BaseStyle> {\n readonly type: \"native\";\n /** The registered view kind this instance resolves to (the `registerView` name). */\n readonly viewName: string;\n /** Creation params, passed to the host factory (JSON-serializable). */\n readonly params: any;\n /** Show fullscreen as the current destination (see Presentable). */\n open(options?: PresentOptions): void;\n /** Dismiss if this is the visible destination. */\n close(options?: DismissOptions): void;\n /** Became the visible destination. */\n onOpen(callback: () => void): this;\n /** Stopped being the visible destination. */\n onClose(callback: () => void): this;\n /** Hardware/system back while current. */\n onBack(callback: () => void): this;\n /** Invoke a method on the native view (`map.call(\"setCenter\", [lng, lat])`). Args and the\n * result are plain data (and Uint8Array). Rejects if the host has no such view/method. */\n call(method: string, ...args: any[]): Promise<any>;\n /** Subscribe to an event the native view emits (`map.on(\"markerTap\", cb)`). */\n on(event: string, callback: (data?: any) => void): this;\n off(event: string, callback: (data?: any) => void): this;\n /** The UI over the view when presented: widgets over it (`Presentable.setContent`). */\n setContent(content: UIWidgetContent): this;\n}\n/**\n * Create an instance of a host-registered platform view. `NativeView.isSupported(name)` reports\n * whether this host registered a factory for it. Style via the chained `.style()`.\n */\nexport declare const NativeView: {\n (name: string, params?: object): NativeView;\n /** Whether this host registered a `registerView` factory under `name`. */\n isSupported(name: string): boolean;\n /** The contract version of the host's view `name`: 0 when it has none, 1 for one written by hand. */\n version(name: string): number;\n};\n","types/ui/presentable.d.ts":"import type { EasingInput } from \"../animate/tween/easing\";\nimport type { UIWidget } from \"./UIWidget\";\n/** The built-in transitions (ui/transitions.ts holds what each one is). `push` / `pop` are the\n * stacked-navigation pair — the incoming screen slides over the other one, which drifts and dims;\n * the rest are two-screen moves. */\nexport type TransitionName = \"push\" | \"pop\" | \"slide-from-left\" | \"slide-from-right\" | \"slide-from-top\" | \"slide-from-bottom\" | \"zoom\" | \"zoom-in\" | \"zoom-out\" | \"fade\" | \"none\";\n/**\n * One screen's pose in a transition — the keys of an `animateTo` bag a transition can move, with\n * the side's own timing. An array is a list of keyframes, as there.\n */\nexport type TransitionPose = {\n /** A transform list, as in a style — and here a `%` in `translate` is a percent of the screen's\n * own box: `\"translateX(100%)\"` is one width to the right. */\n transform?: string | string[];\n opacity?: number | number[];\n /** Black over this screen, 0..1: how dark the screen UNDER the other one gets. */\n dim?: number | number[];\n /** A widget's overlay layer (its scrim) in the pose — a widget's enter / exit pose only\n * (`UIModal.transition`): `\"transparent\"` fades the scrim in with the dialog. */\n overlayColor?: string | string[];\n /** ms (default 300). */\n duration?: number;\n /** ms to wait; the screen holds its first pose through it. */\n delay?: number;\n /** Any curve `animateTo` takes (default `ease-in-out`). */\n easing?: EasingInput;\n};\n/**\n * A transition between two destinations, described by where each side is when it is NOT at rest:\n * the incoming one comes FROM `enter`, the outgoing one goes TO `exit`. A side left out stays put.\n *\n * ```ts\n * Router.push(page, { transition: { enter: { transform: \"translateY(100%)\", duration: 400 }, exit: { dim: 0.3 } } })\n * ```\n *\n * A screen's own `transform` / `opacity` are not seen while a transition moves it (put a lasting\n * effect on a child). A scene, a native view, a video never move: next to one of them only the\n * screen's side plays, above it.\n */\nexport interface TransitionSpec {\n /** The incoming destination's start: it moves from this pose to rest. */\n enter?: TransitionPose;\n /** The outgoing destination's end: it moves from rest to this pose. */\n exit?: TransitionPose;\n /** Which side is above the other while they move (default `\"enter\"`). */\n onTop?: \"enter\" | \"exit\";\n}\nexport type Transition = TransitionName | TransitionSpec;\nexport type PresentOptions = {\n /** Transition to play while this destination replaces the current one (default \"none\" for a\n * direct open(); the Router applies its own defaults — push/pop, and the theme's\n * `replaceTransition` for replace). */\n transition?: Transition;\n};\n/** `close()` / `Router.hide()`: the transition the destination leaves with (default \"none\"). */\nexport type DismissOptions = {\n transition?: Transition;\n};\n/**\n * Anything that can be shown as the app's current destination: a `UIScreen`, a `Scene` /\n * `ARScene`, a `Scene2D`, a `NativeView`, or a `UIVideo`. One Presentable is visible at a time;\n * open it directly (`p.open()` — replaces the current destination, suspending an active Router\n * until `Router.restore()`) or navigate with `Router.push/replace/pop`.\n *\n * `onOpen`/`onClose` are the presentation lifecycle (fired when the destination becomes / stops\n * being the visible one — including router pushes covering it and pops revealing it).\n */\nexport interface Presentable {\n open(options?: PresentOptions): void | this | Promise<void>;\n /** Close this destination if it is the one on screen (nothing takes its place). One that is not\n * on screen — already replaced by a `Router.init/push/replace` or another `open()` — is left as\n * it is, so `Router.init(home); scene.close()` keeps `home` visible. */\n close(options?: DismissOptions): void;\n onOpen(callback: () => void): this;\n onClose(callback: () => void): this;\n onBack(callback: () => void): this;\n /** The destination's widgets (docs/plans/widgets-plan.md): a dialog, a HUD, a sheet declared as\n * CONTENT of the place they belong to. A `UIScreen` takes them among its children; a surface — a\n * `Scene`, a `Scene2D`, a `NativeView`, a `UIVideo` — takes widgets alone, laid out over it while\n * it is presented (touches outside a widget's box reach the surface). A widget shows with its\n * destination unless its style says `display: \"none\"`; `show()` / `hide()` flip that. */\n setContent(content: (UIWidget | null | undefined | false)[] | (() => (UIWidget | null | undefined | false)[])): this;\n}\n/** Runtime companion of the `Presentable` interface (declaration merging): the navigation\n * state that isn't tied to the Router. */\nexport declare const Presentable: Readonly<{\n /** The destination visible right now (a `UIScreen`, `Scene`, `Scene2D`, `NativeView` or\n * `UIVideo`), or `null` before the first open. Distinct from `Router.current` — that is the\n * top of the router stack, which stays meaningful while the router is suspended by a direct\n * `open()`; this is what is actually on screen. `UIWidget.show()` attaches to it. */\n readonly current: Presentable | null;\n}>;\n","types/ui/router.d.ts":"import { Presentable, type DismissOptions, type PresentOptions, type Transition } from \"./presentable\";\ntype RouterOptions = {\n showDefaultBackButton?: boolean;\n};\nexport type NavigateOptions = {\n /** Transition to play. Defaults: `\"push\"` for push; replace follows the theme's\n * `replaceTransition` (`\"none\"` out of the box); a pop plays the way back the destination it\n * pops remembers. */\n transition?: Transition;\n /** The way BACK from the destination — what `Router.pop()` without a transition, the edge swipe\n * and the system's back play when they take it off the stack. Default: the transition it came\n * with, the other way round (a push goes back with a pop, a slide from the bottom leaves\n * downwards; a zoom goes back with a fade). A `replace` that names none keeps the way back of\n * the destination it replaces: it belongs to the place in the stack. */\n popTransition?: Transition;\n};\nexport type PopOptions = {\n /** Transition to play instead of the way back the popped destination remembers. */\n transition?: Transition;\n};\n/** Stack navigation over `Presentable` destinations. `init` once with the home page, then\n * `push`/`replace`/`pop`; the back gesture/button pops natively. A direct `page.open()` suspends\n * the router until `restore()`. */\ntype Router = {\n /** The top of the router stack (not necessarily what's on screen — see `Presentable.current`). */\n get current(): Presentable;\n /** Mount the router with `homePage` as the stack root — the app's navigation entry point. */\n init(homePage: Presentable, opts?: RouterOptions): void;\n /** Push a destination onto the stack — a `UIScreen`, a `Scene`, a `Scene2D`, a `NativeView`,\n * or a `UIVideo`. The back gesture/button pops it. Destinations with async preparation\n * (`ARScene`: camera permission + warm render) return a Promise — the current page stays\n * visible until they're ready, and a rejection (permission denied / superseded) leaves the\n * stack untouched. */\n push(page: Presentable, opts?: NavigateOptions): void | Promise<void>;\n /** Swap the top of the stack for `page` — no back entry to the replaced one. */\n replace(page: Presentable, opts?: NavigateOptions): void | Promise<void>;\n /** Pop the top destination (the programmatic twin of the back gesture); `to` unwinds to a\n * stack index in one step. */\n pop(to?: number, opts?: PopOptions): void;\n /** Blank the router's page, keeping the stack — `restore()` brings it back. A destination\n * opened directly stays visible. */\n hide(opts?: DismissOptions): void;\n /** Re-present the stack top after `hide()` or a direct `open()` suspended the router. */\n restore(opts?: PresentOptions): void;\n /** `\"change\"` fires on every stack change — pushes, pops, and native back gestures — with the\n * new top destination. */\n addEventListener(channel: \"change\", callback: (page: Presentable) => void): void;\n removeEventListener(channel: \"change\", callback: (page: Presentable) => void): void;\n};\nexport declare const Router: Router;\nexport {};\n","types/ui/styleColor.d.ts":"export {};\n","types/ui/theme.d.ts":"import type { Transition } from \"./presentable\";\nexport type ThemeValues = Record<string, string | number | null>;\n/** The keys the SDK itself reads — the ROLES of a theme. An app's own keys sit beside them in the\n * same call; kit components (`UITabs`) and the defaults of screens and text read these and nothing\n * else, so one palette colors the app and the kit alike. A color is a string, never a number. */\nexport type ThemeRoles = {\n /** The background of every screen. */\n bg?: string | null;\n /** A raised surface — cards, bars, sheets. The tab bar's background (without it: `bg`). */\n surface?: string | null;\n /** Hairlines and outlines. The tab bar's top line. */\n border?: string | null;\n /** Text that names no `color` of its own. */\n text?: string | null;\n /** Secondary text and inactive controls. The tab bar's inactive tabs. */\n textMuted?: string | null;\n /** The brand / active color. The tab bar's active tab. */\n accent?: string | null;\n /** The font of text that names no `fontFamily` of its own. */\n fontFamily?: string | null;\n};\n/** What only the app-wide `theme()` takes: the comfort knobs (logical px) and the Router's default\n * `replace` transition. */\nexport type ThemeAppKeys = {\n \"comfort-top\"?: number | string | null;\n \"comfort-bottom\"?: number | string | null;\n \"comfort-left\"?: number | string | null;\n \"comfort-right\"?: number | string | null;\n replaceTransition?: Transition | null;\n};\n/** The `var(--key)` strings of the keys a `theme()` call defined — plain strings, so a helper's\n * `(color = colors.accent)` parameter takes any color. */\nexport type ThemeAccessors<T> = {\n readonly [K in Exclude<keyof T, \"replaceTransition\">]: string;\n};\n/** App theme: callable to merge variables (`theme({...})` — re-calling re-styles the live UI, so\n * dark mode is just a second call), with the roles as static properties (`theme.accent`,\n * `theme[\"comfort-top\"]`, …) for code that has no tokens module to import. */\nexport declare const theme: (<T extends ThemeRoles & ThemeAppKeys & Record<string, string | number | Transition | null>>(values: T & { [K in Exclude<keyof T, \"replaceTransition\">]: string | number | null; }) => ThemeAccessors<T>) & {\n /** The background of every screen. */\n readonly bg: \"var(--bg)\";\n /** A raised surface — cards, bars, sheets. */\n readonly surface: \"var(--surface)\";\n /** Hairlines and outlines. */\n readonly border: \"var(--border)\";\n /** DEFAULT text color — text without a `color` of its own follows it (unset = the host's\n * default: white). Set it once for a light theme instead of a color on every label. */\n readonly text: \"var(--text)\";\n /** Secondary text and inactive controls. */\n readonly textMuted: \"var(--textMuted)\";\n /** The brand / active color. */\n readonly accent: \"var(--accent)\";\n /** DEFAULT text font — text without a `fontFamily` of its own follows it. */\n readonly fontFamily: \"var(--fontFamily)\";\n /** Raw comfort knobs (logical px). The bare `comfort-top` style TOKEN applies the safe-area\n * formula — these accessors read the knob value itself, for manual composition. */\n readonly \"comfort-top\": \"var(--comfort-top)\";\n readonly \"comfort-bottom\": \"var(--comfort-bottom)\";\n readonly \"comfort-left\": \"var(--comfort-left)\";\n readonly \"comfort-right\": \"var(--comfort-right)\";\n};\n","types/ui/transitions.d.ts":"import type { TransitionPose, TransitionSpec } from \"./presentable\";\n/** Wire ids: a registered transition is > 0. */\nexport declare const TRANSITION_NONE = 0;\n/** \"The caller names none\": the runtime plays what the stack entry remembers (a pop), or keeps\n * what the replaced entry remembered (a replace's way back). */\nexport declare const TRANSITION_UNSET = -1;\n/** Who a track moves. The ALONE roles play next to a destination that cannot move (a scene, a\n * native view, a video) or next to nothing (close(), the first open): only the screen plays, above. */\nexport declare const ROLE_ENTER = 0;\nexport declare const ROLE_EXIT = 1;\nexport declare const ROLE_ENTER_ALONE = 2;\nexport declare const ROLE_EXIT_ALONE = 3;\n/** `defineTransition` flags. */\nexport declare const TRANSITION_ENTER_ON_TOP = 1;\n/** The way back of a spec: the ROLES swap — the screen that came leaves into its `enter` pose, the\n * one that left comes back from its `exit` pose, the same screen stays on top — and the timing and\n * the curves stay as written. Not a rewind: that would turn an ease-out into a slow start. */\nexport declare const mirrored: (s: TransitionSpec) => TransitionSpec;\nexport declare const _widgetPoseId: (pose: TransitionPose | null) => number;\n","types/ui/tree.d.ts":"export declare const TREE_EVENT_LAYOUT = 1;\nexport declare const TREE_EVENT_TOUCH_START = 2;\nexport declare const TREE_EVENT_CLICK = 3;\nexport declare const TREE_EVENT_LONG_PRESS = 4;\nexport declare const TREE_EVENT_TOUCH_MOVE = 5;\nexport declare const TREE_EVENT_TOUCH_END = 6;\nexport declare const TREE_EVENT_TOUCH_CANCEL = 7;\nexport declare const TREE_EVENT_SCROLL = 8;\nexport declare const TREE_EVENT_OVERSCROLL = 9;\nexport declare const TREE_EVENT_SCROLL_RELEASE = 10;\nexport declare const TREE_EVENT_REFRESH = 11;\nexport declare const TREE_EVENT_CHANGE = 12;\nexport declare const TREE_EVENT_FOCUS = 13;\nexport declare const TREE_EVENT_BLUR = 14;\nexport declare const TREE_EVENT_SUBMIT = 15;\nexport declare const TREE_EVENT_OVERLAY_TAP = 16;\nexport declare const TREE_EVENT_DETENT = 17;\nexport declare const TREE_EVENT_OPEN = 18;\nexport declare const TREE_EVENT_CLOSE = 19;\nexport declare const TREE_EVENT_BACK = 20;\nexport declare const TREE_EVENT_PAGER_SELECT = 21;\nexport declare const TREE_EVENT_PAGER_POP = 22;\nexport declare const TREE_EVENT_VLIST_SYNC = 23;\nexport declare const TREE_EVENT_VLIST_EDGE = 24;\nexport declare const TREE_EVENT_VIEW_EVENT = 25;\nexport declare const TREE_EVENT_RESIZE = 26;\nexport declare const TREE_EVENT_ROUTER_CHANGE = 27;\nexport declare const TREE_EVENT_SCENE_TOUCH_START = 28;\nexport declare const TREE_EVENT_SCENE_CLICK = 29;\nexport declare const TREE_EVENT_DETACHED = 30;\nexport declare const TREE_EVENT_FREED = 31;\nexport declare const TREE_EVENT_HOVER_ENTER = 32;\nexport declare const TREE_EVENT_HOVER_MOVE = 33;\nexport declare const TREE_EVENT_HOVER_END = 34;\nexport declare const TREE_EVENT_HOVER_CANCEL = 35;\nexport declare const TREE_EVENT_WIDGET_VISIBLE = 36;\nexport declare const TREE_FLAG_INTERACTIVE: number;\nexport declare const TREE_FLAG_CLICK: number;\nexport declare const TREE_FLAG_LONG_PRESS: number;\nexport declare const TREE_FLAG_LAYOUT: number;\nexport declare const TREE_FLAG_SCROLL: number;\nexport declare const TREE_FLAG_OVERSCROLL: number;\nexport declare const TREE_FLAG_SCROLL_RELEASE: number;\nexport declare const TREE_FLAG_REFRESH: number;\nexport declare const TREE_FLAG_CHANGE: number;\nexport declare const TREE_FLAG_FOCUS: number;\nexport declare const TREE_FLAG_BLUR: number;\nexport declare const TREE_FLAG_SUBMIT: number;\nexport declare const TREE_FLAG_OVERLAY_TAP: number;\nexport declare const TREE_FLAG_DETENT: number;\nexport declare const TREE_FLAG_KEEP_ALIVE: number;\nexport declare const TREE_FLAG_BACK: number;\nexport declare const TREE_FLAG_VLIST_END: number;\nexport declare const TREE_FLAG_VLIST_START: number;\nexport declare const TREE_FLAG_HOVER: number;\nexport declare const TREE_TRACK_CLAIM_MASK = 255;\nexport declare const TREE_TRACK_TRACKED: number;\nexport declare const TREE_TRACK_MOVE: number;\nexport declare const TREE_TRACK_HANDLED: number;\nexport declare const TREE_DEST_SCREEN = 0;\nexport declare const TREE_DEST_SCENE3D = 1;\nexport declare const TREE_DEST_SCENE2D = 2;\nexport declare const TREE_DEST_NATIVE = 3;\nexport declare const TREE_DEST_VIDEO = 4;\nexport declare const TREE_DEST_NONE = 255;\nexport declare const OWNED_KIND_TREE = 0;\nexport declare const OWNED_KIND_FETCH = 1;\nexport declare const OWNED_KIND_GL_MATERIAL = 2;\nexport declare const OWNED_KIND_GL_TEXTURE = 3;\nexport declare const OWNED_KIND_GL_ENTITY = 4;\nexport declare const OWNED_KIND_ENTITY_2D = 5;\nexport declare const OWNED_KIND_MEDIA = 6;\nexport declare const OWNED_KIND_TWEEN = 7;\nexport declare const OWNED_KIND_CANVAS = 8;\nimport { DEAD_HANDLE } from \"../core/pins\";\nexport { DEAD_HANDLE };\n","types/ui/UI.d.ts":"export { UIButton, type UIButtonStyle } from './UIButton';\nexport { UIScreen, type UIScreenStyle } from './UIScreen';\nexport { UISpacer, type UISpacerStyle } from './UISpacer';\nexport { UIText, type UITextStyle } from './UIText';\nexport { registerFont } from './fonts';\nexport { UIImage, type UIImageStyle } from './UIImage';\nexport { UIVideo, type UIVideoStyle } from './UIVideo';\nexport { UIInput, UITextArea, type UIInputStyle } from './UIInput';\nexport { UIWidget, type UIWidgetStyle } from './UIWidget';\nexport { UIOverlay, type UIWidgetContent } from './UILayer';\nexport { UIModal, type UIModalStyle } from './UIModal';\nexport { UIBottomSheet, type UIBottomSheetStyle } from './UIBottomSheet';\nexport { UIPopover, type UIPopoverStyle, type UIPopoverAnchor } from './UIPopover';\nexport { UIRow, UIColumn, UIBox, type UIContainerStyle } from './UIContainer';\nexport { UIScrollable, type UIScrollableStyle } from './UIScrollable';\nexport { UIPager, type UIPagerStyle } from './UIPager';\nexport { UITabs, type UITabDef, defineTabs, type TabDef, type TabsHandle } from './UITabs';\nexport { UIVirtualizedList } from './UIVirtualizedList';\nexport { Router } from './router';\nexport { NativeView, type UINativeViewStyle } from './NativeView';\nexport { Presentable } from './presentable';\nexport type { DismissOptions, PresentOptions, Transition, TransitionName, TransitionPose, TransitionSpec } from './presentable';\nexport { __uiMap } from './UINode';\nexport { __UIColumn, __UIRow, __UIBox } from './UIContainer';\nexport { __UIButton } from './UIButton';\nexport { __UIScreen } from './UIScreen';\nexport { __UIScrollable } from './UIScrollable';\nexport { __UIWidget } from './UIWidget';\n","types/ui/UIBottomSheet.d.ts":"import { ModalElement, type UIModalStyle } from \"./UIModal\";\nimport type { UIWidget } from \"./UIWidget\";\nimport { type ChildrenFn, type UIChildArg, type UINodeChild } from \"./UINode\";\nexport type UIBottomSheetStyle = UIModalStyle;\n/**\n * A bottom sheet: a `UIWidget` pinned to the bottom edge. By default it is **content-sized** —\n * as tall as what's inside (capped at the screen), one position, drag down to dismiss (the\n * action-sheet shape). Call `detents()` for the multi-position map-app model instead: snap\n * positions the user drags between on native hosts. Ships as a widget node on the wire (no new\n * node type — docs/bottom-sheet-plan.md): hosts without sheet support show a static bottom panel.\n *\n * With detents, content lays out at the HIGHEST detent's size; lower detents show the top\n * slice. The scrim, `onOpen`/`onClose`, back-button and scrim-tap dismissal all come from the\n * modal machinery.\n *\n * ```ts\n * const actions = UIBottomSheet(rows).style({ bgColor: \"#1c1c1e\", borderRadius: 16 }) // content-sized\n *\n * const mapSheet = UIBottomSheet(results).style({ bgColor: \"#1c1c1e\", borderRadius: 16 })\n * .detents([0.3, 0.6, 1])\n * .onDetent(i => map.setPadding(...))\n * ```\n */\nexport interface UIBottomSheet extends UIWidget {\n /** Snap positions as fractions of screen height, ascending. Also sizes the sheet: its box is\n * the last (highest) detent; set this before `show()`. Without a `detents()` call the sheet\n * is CONTENT-SIZED instead — one position, as tall as its children (up to the screen). */\n detents(list: number[]): this;\n /** Snap to a detent (animated). Clamped to the detents range; fires `onDetent`. */\n setDetent(index: number): void;\n /** Current detent index. */\n readonly detent: number;\n /** Fires on every settle: a finger snap on native hosts, or a `setDetent()` call. */\n onDetent(callback: (index: number) => void): this;\n /** Mount and slide in to the current detent. No-op while already open. */\n show(): void;\n /** Slide out, fade the scrim, then unmount. No-op while closed. */\n hide(): void;\n /** True from `show()` until `hide()` starts. */\n readonly isOpen: boolean;\n /** Called when `show()` mounts the sheet. */\n onOpen(callback: () => void): this;\n /** Called when the sheet starts closing — scrim tap, back button, drag-dismiss, or `hide()`. */\n onClose(callback: () => void): this;\n /** `dismissible(false)`: scrim taps, the back button and dragging below the lowest detent no\n * longer close the sheet (a drag collapses to the lowest detent instead). Default `true`. */\n dismissible(enabled: boolean): this;\n}\nexport declare class BottomSheetElement extends ModalElement {\n _detents: number[];\n _detent: number;\n readonly _detentListeners: ((index: number) => void)[];\n constructor(style: UIBottomSheetStyle, children: UINodeChild[] | ChildrenFn);\n detents(list: number[]): this;\n get detent(): number;\n setDetent(index: number): void;\n onDetent(callback: (index: number) => void): this;\n show(): void;\n hide(): void;\n dismissible(enabled: boolean): this;\n}\n/** Create a bottom sheet (see {@link UIBottomSheet}) — content-sized by default; call\n * `.detents([...])` for snap positions. Same argument forms as `UIColumn`. */\nexport declare function UIBottomSheet(...children: UIChildArg[]): UIBottomSheet;\nexport declare function UIBottomSheet(children: UINodeChild[] | ChildrenFn): UIBottomSheet;\n","types/ui/UIButton.d.ts":"import type { ClickEvent as ClickEventType, TouchStartEvent as TouchStartEventType, LongPressEvent as LongPressEventType, MouseEnterEvent as MouseEnterEventType } from \"../runtime/touch\";\nimport { type ElementStyle, type ContainerStyle, type DrawableStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn, type BaseStyle, type Color } from \"./UINode\";\nexport type UIButtonStyle = ElementStyle & DrawableStyle & ContainerStyle & {\n rippleColor?: Color | \"default\";\n};\n/** A tappable container — row + centered children by default. Press feedback via the `$pressed`\n * class block or `rippleColor`. */\nexport interface UIButton extends UIContainerBase<UIButtonStyle, DrawableStyle & BaseStyle> {\n readonly type: \"button\";\n /** Fired on a completed tap/click. */\n onClick(callback: (ev: ClickEventType<UIButton>) => void): this;\n /** Fired when a touch begins; `ev.track(...)` takes over the rest of the gesture (dragging). */\n onTouchStart(callback: (ev: TouchStartEventType<UIButton>) => void): this;\n /** Fired when a finger is held on the button past the long-press threshold. The event can\n * `ev.track(...)` the rest of the gesture (like `onTouchStart`), so a hold can flow straight into\n * dragging the element. A handled long-press suppresses the click that would follow the release. */\n onLongPress(callback: (ev: LongPressEventType<UIButton>) => void): this;\n /** Fired when a mouse cursor (no button) enters the button — desktop / web; touch never fires it.\n * There is no leave event: `ev.track({ onMove, onEnd, onCancel })` follows the hover to its\n * end. The visual state is the reserved `$hovered` class (cascades like `$pressed`). */\n onMouseEnter(callback: (ev: MouseEnterEventType<UIButton>) => void): this;\n /** Is a finger currently down on the button? */\n readonly isPressed: boolean;\n /** Is a mouse cursor currently over the button (the topmost interactive node under it)? */\n readonly isHovered: boolean;\n}\n/** Create a button (row + centered by default — the icon+label shape). Same argument forms as\n * `UIColumn`; attach behavior with `.onClick(...)`. */\nexport declare function UIButton(...children: UIChildArg[]): UIButton;\nexport declare function UIButton(children: UINodeChild[] | ChildrenFn): UIButton;\n","types/ui/UIContainer.d.ts":"import { type ChildrenFn, type ContainerStyle, type DrawableStyle, type ElementStyle, type UIChildArg, type UIContainerBase, type UINodeChild } from \"./UINode\";\nexport type UIContainerStyle = ElementStyle & DrawableStyle & ContainerStyle;\n/** A vertical flex container — children stack top to bottom. */\nexport interface UIColumn extends UIContainerBase<UIContainerStyle> {\n readonly type: \"column\";\n}\nexport declare const __UIRow: (children: UINodeChild[] | ChildrenFn) => UIRow;\nexport declare const __UIBox: (children: UINodeChild[] | ChildrenFn) => UIBox;\n/** Create a vertical flex container. Children are variadic — arrays flatten one level, falsy\n * entries are skipped; a lone function makes the children reactive. */\nexport declare function UIColumn(...children: UIChildArg[]): UIColumn;\nexport declare function UIColumn(children: UINodeChild[] | ChildrenFn): UIColumn;\n/** A horizontal flex container — children flow left to right. */\nexport interface UIRow extends UIContainerBase<UIContainerStyle> {\n readonly type: \"row\";\n}\n/** Create a horizontal flex container (same argument forms as `UIColumn`). */\nexport declare function UIRow(...children: UIChildArg[]): UIRow;\nexport declare function UIRow(children: UINodeChild[] | ChildrenFn): UIRow;\n/** A centering container — `justifyContent`/`alignItems` default to center. */\nexport interface UIBox extends UIContainerBase<UIContainerStyle> {\n readonly type: \"box\";\n}\n/** Create a centering container — children are centered on both axes by default (icon badges,\n * avatars, empty states). Same argument forms as `UIColumn`. */\nexport declare function UIBox(...children: UIChildArg[]): UIBox;\nexport declare function UIBox(children: UINodeChild[] | ChildrenFn): UIBox;\n","types/ui/UIImage.d.ts":"import type { FetchResponse } from \"../runtime/fetch\";\nimport type { SvgSourceValue as SvgSource } from \"../runtime/misc\";\nimport type { File } from \"../runtime/fetch\";\nimport { Canvas } from \"../canvas/Canvas\";\nimport type { Scene2D } from \"../g2/Scene2D\";\nimport { type Color, type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UIImageStyle = ElementStyle & {\n borderRadius?: number;\n objectFit?: \"cover\" | \"contain\" | \"fill\";\n tintColor?: Color;\n};\n/** A baked Canvas surface as an image source. The UI backend resolves it to a UI texture. */\nexport type CanvasImageSource = {\n canvasSurface: number;\n};\n/** A live 2D scene as an image source: the host draws the scene into the node's box every frame\n * (the scene's camera, projected into the box). No intrinsic size — give the node a width and\n * height. */\nexport type Scene2DImageSource = {\n scene2d: number;\n};\n/** Accepted image sources. A Canvas is baked to a surface marker on assign; a Scene2D becomes a\n * live-scene marker. */\nexport type ImageSource = string | FetchResponse | File | SvgSource | Canvas | Scene2D;\n/** The stored/resolved image source (a Canvas is resolved to a surface marker, a Scene2D to a\n * live-scene marker). */\nexport type ResolvedImageSource = string | FetchResponse | File | SvgSource | CanvasImageSource | Scene2DImageSource;\n/** An image element. Sources: URL / `asset(...)`, fetch response / File, an SVG source\n * (`assetIcon`), a live Canvas (`canvas.update()` refreshes the node in place), or a live Scene2D\n * (drawn into the box every frame — a minimap). */\nexport interface UIImage extends UIElementBase<UIImageStyle> {\n readonly type: \"image\";\n /** The image source — writable to swap the picture in place. */\n get src(): ResolvedImageSource;\n set src(value: ImageSource);\n /** Render only a sub-rectangle of the source texture (texture pixels) — the atlas/spritesheet\n * primitive: crop once, then swap the rect per frame for sprite animation. The rect's w/h\n * become the node's intrinsic size and override `objectFit` — the cropped frame fills the box. */\n setSourceRect(x: number, y: number, w: number, h: number): this;\n}\n/** Create an image element from a source (see {@link ImageSource}). */\nexport declare function UIImage(src: ImageSource): UIImage;\n","types/ui/UIInput.d.ts":"import { type ElementStyle, type DrawableStyle, type TextStyle, type Color, type BaseStyle, type UIElementBase } from \"./UINode\";\ntype InputStyle = {\n placeholder?: string;\n placeholderColor?: Color;\n /**\n * Keyboard hint, NOT a validator — `number` does not block pasted letters; validate in your own\n * onChange. The phone-pad value is `phone` (LeCodes has no `tel`).\n *\n * `date` / `time` are PICKER kinds, not keyboards: the host opens its native picker in the\n * keyboard slot (iOS wheels / browser calendar) and free typing is disabled. `value` is always\n * canonical — `YYYY-MM-DD` for `date`, `HH:MM` (24h) for `time` — while the field displays a\n * localized string; set/compare values in the canonical form only.\n */\n type?: \"text\" | \"password\" | \"search\" | \"phone\" | \"email\" | \"number\" | \"decimal\" | \"url\" | \"date\" | \"time\";\n /**\n * What the layout does while the keyboard is up (decided by the FOCUSED input). `true` (default):\n * the layout viewport shrinks to the area above the keyboard — one relayout. `false`: the keyboard\n * overlays the UI with NO layout recalculation — for chat composers that manage their own inset\n * (pair with `app.keyboardHeight` / the app `\"keyboard\"` event) and full-screen canvases where a\n * reflow is worse than overlap.\n */\n keyboardShrink?: boolean;\n /**\n * Whether a tap on a non-interactive area dismisses the keyboard while THIS input is focused\n * (like `keyboardShrink`, the policy of the focused input). `true` (default): tapping dead\n * space blurs — but a tap on a button or another input NEVER dismisses; the control acts and\n * focus stays. `false`: taps never dismiss — the chat-composer policy. `blur()`, the return\n * key (per `enterKey`), and the platform's own gestures (iOS drag-down over the keyboard)\n * still work in both modes. Scrolling never dismisses the keyboard on any setting.\n */\n keyboardDismiss?: boolean;\n /** Hard cap on the text length — enforced by the host while typing/pasting. */\n maxLength?: number;\n /** Auto-capitalization hint; omitted = platform default. */\n autocapitalize?: \"none\" | \"words\" | \"sentences\" | \"characters\";\n /** Enable/disable the platform autocorrection & suggestions; omitted = platform default. */\n autocorrect?: boolean;\n};\nexport type UIInputStyle = ElementStyle & DrawableStyle & TextStyle & InputStyle;\n/** UIInput-only (a UITextArea's Enter is a newline, period): the return-key label. */\ntype SubmitStyle = {\n /**\n * Return-key label. On submit the keyboard dismisses UNLESS `enterKey` is `\"next\"` — then the\n * app is expected to call `otherInput.focus()` from `onSubmit`, so the keyboard never blinks.\n */\n enterKey?: \"done\" | \"go\" | \"next\" | \"search\" | \"send\";\n};\n/** A single-line text input. Keyboard/picker kind via the `type` style, return-key behavior via\n * `enterKey` + `onSubmit`; keyboard policy on `keyboardShrink`/`keyboardDismiss`. */\nexport interface UIInput extends UIElementBase<UIInputStyle & SubmitStyle, DrawableStyle & BaseStyle> {\n readonly type: \"input\";\n /** The field's text. Writable at any time; reads return the live text (the host owns the field\n * while the user types — IME composition, paste, the maxLength clamp, date/time canonicalization). */\n value: string;\n /** The text changed — fires on every user edit. */\n onChange(callback: (value: string) => void): UIInput;\n /** Gained focus (keyboard opens). */\n onFocus(callback: () => void): UIInput;\n /** Lost focus. */\n onBlur(callback: () => void): UIInput;\n /** The keyboard's return key was pressed. `value` is the current text. See `enterKey`. */\n onSubmit(callback: (value: string) => void): UIInput;\n /** Focus the input (opens the keyboard). */\n focus(): void;\n /** Release focus (dismisses the keyboard when this input held it). */\n blur(): void;\n}\n/** A multi-line text field — see the {@link UITextArea} factory for the auto-grow contract. */\nexport interface UITextArea extends UIElementBase<UIInputStyle, DrawableStyle & BaseStyle> {\n readonly type: \"textarea\";\n /** The field's text — same contract as {@link UIInput.value}. */\n value: string;\n /** The text changed — fires on every user edit. */\n onChange(callback: (value: string) => void): UITextArea;\n /** Gained focus (keyboard opens). */\n onFocus(callback: () => void): UITextArea;\n /** Lost focus. */\n onBlur(callback: () => void): UITextArea;\n /** Focus the text area (opens the keyboard). */\n focus(): void;\n /** Release focus (dismisses the keyboard when this text area held it). */\n blur(): void;\n}\n/** Create a single-line text input. Read/write the text via `.value`, listen with\n * `onChange`/`onSubmit`; style keys `placeholder`, `type`, `enterKey`, … configure it. */\nexport declare function UIInput(): UIInput;\nexport declare function UIInput(style: UIInputStyle): UIInput;\n/**\n * Multi-line text field. Enter is a newline (submit lives on UIInput / your own button).\n *\n * Auto-grow: with no explicit `height` the field measures its own content and grows line by\n * line — clamp the range with `minHeight` / `maxHeight` (past `maxHeight` the text scrolls\n * inside). A fixed `height` opts out and scrolls internally from the start. Chat composers are\n * the canonical use: a bare textarea in a padded pill, `maxHeight` at ~5 lines.\n */\nexport declare function UITextArea(): UITextArea;\nexport declare function UITextArea(style: UIInputStyle): UITextArea;\nexport {};\n","types/ui/UILayer.d.ts":"import type { UIWidget } from \"./UIWidget\";\nexport type UIWidgetContent = (UIWidget | null | undefined | false)[] | (() => (UIWidget | null | undefined | false)[]);\n/**\n * The app layer: the widgets above EVERY destination, always shown — a global loader, a mini-player\n * that follows the user across screens, a toast with actions. Widgets that belong to a place go in\n * that place instead: a dialog among its screen's children (`UIScreen(..., dialog)`), a HUD in\n * `scene.setContent([hud])`. A widget shown with `show()` while it has no parent lands here.\n *\n * ```ts\n * UIOverlay.append(miniPlayer)\n * miniPlayer.hide() // display: none — still here, ready for show()\n * ```\n */\nexport declare const UIOverlay: Readonly<{\n /** Add widgets at the end (on top). */\n append(...widgets: (UIWidget | null | undefined | false)[]): void;\n /** Insert widgets at `index` (0 = the bottom of the layer). */\n insert(index: number, ...widgets: (UIWidget | null | undefined | false)[]): void;\n /** Take widgets out of the layer (they stay valid; a dropped one is freed). */\n remove(...widgets: (UIWidget | null | undefined | false)[]): void;\n /** Replace the layer's widgets — a list, or a function for reactive content. */\n setContent(content: UIWidgetContent): void;\n /** The layer's widgets, bottom to top (a snapshot read from the runtime). */\n readonly children: UIWidget[];\n}>;\n","types/ui/UIModal.d.ts":"import { type UIWidget, type UIWidgetStyle, WidgetElement } from \"./UIWidget\";\nimport { type BaseStyle, type ChildrenFn, type Color, type DrawableStyle, type UIChildArg, type UINodeChild } from \"./UINode\";\nexport type UIModalStyle = UIWidgetStyle;\n/**\n * The modal's hidden pose: `show()` animates from it, `hide()` animates to it. `duration` (ms)\n * applies to both directions.\n */\nexport type UIModalTransition = DrawableStyle & BaseStyle & {\n overlayColor?: Color | null;\n duration?: number;\n};\n/**\n * A dialog: a `UIWidget` with the modal boilerplate built in. Comes with a scrim\n * (`overlayColor: \"rgba(0, 0, 0, 0.5)\"` unless overridden), animates on `show()`/`hide()` and on\n * a state block flipping its `display` (a 200 ms fade by default — swap the pose via\n * `transition()`; the runtime plays it as tracks that never touch the style), and closes itself\n * on a scrim tap or the Android back button (disable via `dismissible(false)`). Everything else\n * is a plain widget: declare it where it belongs — among its screen's children, hidden until a\n * tap (`display: \"none\"`), or shown with `show()` from anywhere, which puts a parentless modal in\n * the app layer. A dialog bound to data (its display from a binding) is declared\n * `dismissible(false)` and routes `onOverlayTap` / `onBack` into the data's dismiss, so the data\n * stays what the screen shows.\n */\nexport interface UIModal extends UIWidget {\n /** Show and play the entrance transition. No-op while already open. */\n show(): void;\n /** Play the exit transition, then hide. No-op while closed or already closing. */\n hide(): void;\n /** True from `show()` until `hide()` starts (already false during the exit animation). */\n readonly isOpen: boolean;\n /**\n * Replace the show/hide animation. `hidden` is the off-screen pose — `show()` animates from\n * it, `hide()` animates to it. Default `{ opacity: 0, duration: 200 }` (a fade); the pose\n * replaces it wholesale, so a slide without a fade is just the slide. The scrim keeps its own\n * fade unless the pose sets `overlayColor` itself.\n *\n * ```ts\n * sheet.transition({ transform: \"translateY(480px)\", duration: 250 }) // bottom sheet\n * ```\n */\n transition(hidden: UIModalTransition): this;\n /** Called when the modal opens — `show()`, or a state block flipping its display. */\n onOpen(callback: () => void): this;\n /** Called when the modal starts closing — scrim tap, back button, a `hide()` call, or a state\n * block flipping its display. */\n onClose(callback: () => void): this;\n /** `dismissible(false)` keeps scrim taps and the back button from closing the modal\n * (forced-choice dialogs, a dialog whose display is bound to data). Default `true`. */\n dismissible(enabled: boolean): this;\n}\nexport declare class ModalElement extends WidgetElement {\n _dismissible: boolean;\n _transition: UIModalTransition;\n readonly _openListeners: (() => void)[];\n readonly _closeListeners: (() => void)[];\n private _poseObj?;\n private _poseKey;\n constructor(style: UIModalStyle, children: UINodeChild[] | ChildrenFn);\n private _pose;\n transition(hidden: UIModalTransition): this;\n show(): void;\n hide(): void;\n get isOpen(): boolean;\n onOpen(callback: () => void): this;\n onClose(callback: () => void): this;\n dismissible(enabled: boolean): this;\n}\n/** Create a modal dialog (see {@link UIModal}): declare it among its screen's children with\n * `display: \"none\"` and `show()` it from a tap, or `show()` a parentless one from anywhere.\n * Same argument forms as `UIColumn`. */\nexport declare function UIModal(...children: UIChildArg[]): UIModal;\nexport declare function UIModal(children: UINodeChild[] | ChildrenFn): UIModal;\n","types/ui/UINode.d.ts":"import type { FetchResponse } from \"../runtime/fetch\";\nimport type { SvgSourceValue } from \"../runtime/misc\";\nimport type { ColorInput } from \"../core/color\";\nimport type { Animation } from \"../animate/tween/Animation\";\nimport { type TweenMeta } from \"../animate/tween/spec\";\nimport { type ThemeRoles } from \"./theme\";\nimport { type TreeElement } from \"./tree\";\nexport interface UINode {\n readonly type: string;\n /** Author-given semantic name (a stable selector for tests + AI review feedback). */\n name?: string;\n style: Style<this, any>;\n /** Style-class proxy — read/set/toggle/bind the `$`-classes declared in `.style()`. See {@link Classes}. */\n readonly class: Classes<this>;\n}\n/** A child slot value: a node, or falsy (conditional rendering — falsy entries are skipped). */\nexport type UINodeChild = UINode | null | undefined | false;\n/** A factory child argument: a node (or falsy for conditionals), or an array of them — arrays are\n * flattened one level at the argument position, so `UIColumn(header, items.map(row), footer)`\n * needs no spread. */\nexport type UIChildArg = UINodeChild | UINodeChild[];\n/** A color: any CSS color string (`\"#1c1c1e\"`, `\"rgba(0,0,0,0.5)\"`, `\"green\"`, `\"hsl(210 50% 40%)\"`),\n * a theme reference (`\"var(--accent)\"`), an opaque `0xRRGGBB` number or `[r, g, b(, a)]` in\n * 0..1; `null` clears. A string is the core's to parse (an unknown one is transparent, as in\n * CSS); a number or an array that is not a color throws at the write. */\nexport type Color = ColorInput | null;\n/** Style props every element accepts. */\nexport type BaseStyle = {\n opacity?: number | `${number}`;\n transform?: string | null;\n /** Pivot of `transform` (CSS `transform-origin` subset): one or two values, each a keyword\n * (`left`/`center`/`right`, `top`/`center`/`bottom`), a percentage of the box, or a px length\n * (bare numbers are px). One value sets x, y stays `50%`. Default `\"50% 50%\"` = the centre. */\n transformOrigin?: string | null;\n backgroundColor?: Color | null;\n bgColor?: Color | null;\n overflow?: \"visible\" | \"hidden\";\n boxSizing?: \"border-box\" | \"content-box\";\n};\n/** Painted-box props: background, gradient, border, radius. */\nexport type DrawableStyle = {\n backgroundImage?: FetchResponse | File | SvgSourceValue | string | null;\n bgGradient?: string;\n backgroundGradient?: string;\n bgImage?: FetchResponse | File | SvgSourceValue | string | null;\n /** How the image fills the box. \"tile\": repeated at its own size from the top-left corner. */\n backgroundSize?: \"cover\" | \"contain\" | \"fill\" | \"tile\";\n bgSize?: \"cover\" | \"contain\" | \"fill\" | \"tile\";\n border?: string | number | null;\n borderWidth?: number;\n borderColor?: Color;\n borderLeft?: string | number | null;\n borderLeftWidth?: number;\n borderLeftColor?: Color;\n borderTop?: string | number | null;\n borderTopWidth?: number;\n borderTopColor?: Color;\n borderRight?: string | number | null;\n borderRightWidth?: number;\n borderRightColor?: Color;\n borderBottom?: string | number | null;\n borderBottomWidth?: number;\n borderBottomColor?: Color;\n borderRadius?: UIValue | string;\n borderTopLeftRadius?: UIValue;\n borderTopRightRadius?: UIValue;\n borderBottomLeftRadius?: UIValue;\n borderBottomRightRadius?: UIValue;\n pointerEvents?: \"all\" | \"none\";\n};\n/** Flex-layout props of a container (how it lays out its children). */\nexport type ContainerStyle = {\n flexDirection?: \"row\" | \"column\";\n justifyContent?: \"flex-start\" | \"center\" | \"flex-end\" | \"space-between\" | \"space-evenly\";\n alignItems?: \"flex-start\" | \"center\" | \"flex-end\" | \"stretch\";\n gap?: UIValue;\n flexWrap?: \"nowrap\" | \"wrap\" | \"wrap-reverse\";\n};\n/** A dimension: a number (logical px) or a CSS-style unit / function string. */\ntype UIValue = number | `${number}px` | `${number}vw` | `${number}vh` | `${number}vmin` | `${number}vmax` | `${number}em` | `calc(${string})` | `min(${string})` | `max(${string})` | `${string}%` | `clamp(${string})` | `var(--${string})`;\n/** Padding, with `p`/`px`/`pl`… shorthands. `safe-*` insets by the device safe area,\n * `comfort-*` by the theme's comfort knobs (max of both). */\nexport type PaddingStyle = {\n paddingLeft?: UIValue | \"safe-left\" | \"comfort-left\";\n paddingTop?: UIValue | \"safe-top\" | \"comfort-top\";\n paddingRight?: UIValue | \"safe-right\" | \"comfort-right\";\n paddingBottom?: UIValue | \"safe-bottom\" | \"comfort-bottom\";\n padding?: UIValue | \"safe-all\" | \"comfort-all\";\n paddingHorizontal?: UIValue | \"comfort-x\";\n paddingVertical?: UIValue | \"comfort-y\";\n pl?: UIValue | \"safe-left\" | \"comfort-left\";\n pt?: UIValue | \"safe-top\" | \"comfort-top\";\n pr?: UIValue | \"safe-right\" | \"comfort-right\";\n pb?: UIValue | \"safe-bottom\" | \"comfort-bottom\";\n p?: UIValue | \"safe-all\" | \"comfort-all\";\n px?: UIValue | \"comfort-x\";\n py?: UIValue | \"comfort-y\";\n};\n/** Margin, with `m`/`mx`/`ml`… shorthands; `\"auto\"` centers/pushes like CSS. */\nexport type MarginStyle = {\n marginLeft?: UIValue | \"auto\" | \"safe-left\" | \"comfort-left\";\n marginTop?: UIValue | \"auto\" | \"safe-top\" | \"comfort-top\";\n marginRight?: UIValue | \"auto\" | \"safe-right\" | \"comfort-right\";\n marginBottom?: UIValue | \"auto\" | \"safe-bottom\" | \"comfort-bottom\";\n margin?: UIValue | \"auto\" | \"safe-all\" | \"comfort-all\";\n marginHorizontal?: UIValue | \"auto\" | \"comfort-x\";\n marginVertical?: UIValue | \"auto\" | \"comfort-y\";\n ml?: UIValue | \"auto\" | \"safe-left\" | \"comfort-left\";\n mt?: UIValue | \"auto\" | \"safe-top\" | \"comfort-top\";\n mr?: UIValue | \"auto\" | \"safe-right\" | \"comfort-right\";\n mb?: UIValue | \"auto\" | \"safe-bottom\" | \"comfort-bottom\";\n m?: UIValue | \"auto\" | \"safe-all\" | \"comfort-all\";\n mx?: UIValue | \"auto\" | \"comfort-x\";\n my?: UIValue | \"auto\" | \"comfort-y\";\n};\n/** Box position (for `position: \"absolute\"`) and size constraints. */\nexport type PositionStyle = {\n top?: UIValue | `${number}%` | 'safe-top' | 'comfort-top';\n left?: UIValue | `${number}%` | 'safe-left' | 'comfort-left';\n bottom?: UIValue | `${number}%` | 'safe-bottom' | 'comfort-bottom';\n right?: UIValue | `${number}%` | 'safe-right' | 'comfort-right';\n /** Shorthand for all four edges at one value. A longhand (`top`, `left`, …) overrides it. */\n inset?: UIValue | `${number}%` | \"auto\";\n width?: UIValue | `${number}%` | \"auto\";\n height?: UIValue | `${number}%` | \"auto\";\n maxWidth?: UIValue | `${number}%` | \"auto\";\n maxHeight?: UIValue | `${number}%` | \"auto\";\n minWidth?: UIValue | `${number}%` | \"auto\";\n minHeight?: UIValue | `${number}%` | \"auto\";\n};\n/** The base style of every element: box + flex-child props. */\nexport type ElementStyle = PaddingStyle & MarginStyle & BaseStyle & PositionStyle & {\n position?: \"absolute\" | \"static\" | \"relative\";\n aspectRatio?: number;\n flex?: number | string;\n flexGrow?: number;\n flexShrink?: number;\n flexBase?: UIValue | `${number}%` | \"auto\";\n alignSelf?: \"flex-start\" | \"center\" | \"flex-end\" | \"stretch\";\n display?: \"none\" | \"flex\";\n};\n/** Typography props. */\nexport type TextStyle = {\n textAlign?: \"start\" | \"center\" | \"end\" | \"left\" | \"right\";\n fontFamily?: string;\n fontSize?: UIValue;\n lineHeight?: UIValue | \"normal\";\n fontWeight?: number | `${number}` | \"normal\" | \"bold\";\n fontStyle?: \"normal\" | \"italic\";\n color?: Color;\n textDecoration?: \"underline\" | \"line-through\" | \"none\";\n letterSpacing?: UIValue;\n /** Cap the text at N lines; the box is measured to the clamped height. 0 / omitted = unbounded. */\n lineClamp?: number;\n /** How a clamped line ends. Only meaningful together with `lineClamp`. Default \"ellipsis\". */\n textOverflow?: \"ellipsis\" | \"clip\";\n};\n/** Reactive style input: every primitive-valued prop also accepts a `() => value` binding that\n * re-applies when a signal it read changes. Nested `$class` blocks stay static — bindings are\n * extracted at the top level only. */\nexport type Reactive<T> = {\n [K in keyof T]: NonNullable<T[K]> extends object ? T[K] : T[K] | (() => T[K]);\n};\n/** The curve of a `$class` block's swap (with a `duration`): a curve name (`outCubic`,\n * `inOutSine`, `smoothstep` — the default — …), `cubic-bezier(x1,y1,x2,y2)` or `steps(n)`. A\n * function cannot ride a style block; use `animateTo` for those. */\nexport type LayerEasing = string;\n/** Style states: any `$`-prefixed key in `.style()` declares a state block; `duration`/`delay`/\n * `easing` animate its swap. User classes (`$checked`, `$selected`, …) are toggled from code via the\n * `el.class` proxy and INHERIT down the tree (CSS-`.dark`-on-body style): a class set on a node also\n * activates same-name `$` blocks on all descendants within the same root (sdk/docs/ui/classes.md).\n *\n * Five classes are reserved — the system toggles them, `el.class` cannot:\n * - `$hovered` / `$pressed` / `$focused` — the host's hover (mouse only) / press / focus. They\n * cascade from the node the host toggled and STOP at the nearest interactive descendant (a\n * button inside a pressed card is not pressed; it has its own scope).\n * - `$landscape` / `$portrait` — the display orientation, GLOBAL: active on every node at once.\n *\n * Precedence on the same prop: base < `$landscape`/`$portrait` < user `$classes` (later-declared\n * beats earlier) < `$hovered` < `$pressed` < `$focused`.\n *\n * Instantiated with the node's FULL style `T` — a class block accepts everything the node's\n * `.style()` does. Narrowing it wrongly rejects valid props such as `$active: { color }`; guarded\n * by tests/ui/types.test.ts. */\nexport type ClassStyles<T> = {\n [key: `$${string}`]: T & {\n duration?: number;\n delay?: number;\n easing?: LayerEasing;\n };\n};\n/** Value accepted by a `el.class` write: a boolean sets the class, a `() => boolean` binds it —\n * the class then tracks the signals the function reads (re-evaluated on change). Reads through\n * the proxy always return a plain boolean, never the bound function. */\nexport type ClassValue = boolean | (() => boolean);\n/** The `el.class` proxy — the runtime switch for `$`-class blocks declared in `.style()`\n * (see {@link ClassStyles}). One surface, mirroring `el.style`:\n *\n * ```ts\n * el.class.checked // read: is it active on THIS element? → boolean\n * el.class.checked = true // activate (false deactivates)\n * el.class.open = !el.class.open // toggle\n * el.class.done = () => todo.done.value // reactive binding (signals)\n * el.class({ checked: true, done: () => … }) // batch form — returns the element, chainable\n * ```\n *\n * Class names are accepted with or without the declaration-site `$` prefix. A write of a reserved\n * class (`hovered` `pressed` `focused` `landscape` `portrait`) throws — the system toggles those.\n * `R` is the concrete node type, so the batch form chains like `.style()`.\n *\n * Typing note: property access is `any` because an index signature can't give reads (`boolean`)\n * and writes ({@link ClassValue}) different types — the batch form is the fully typed path;\n * single-key writes are runtime-coerced with `!!`. */\nexport type Classes<R> = ((classes: Record<string, ClassValue>) => R) & {\n [key: string]: any;\n};\n/** Members every UI element shares — element interfaces extend this so docs and types live in one\n * place. `S` is the element's style object; `A` is the subset `animateTo` accepts (defaults to `S`). */\nexport interface UIElementBase<S extends object, A extends object = S> {\n /** Style: `.style({...})` merges (chainable); `el.style.key = v` writes one prop, a `() => v`\n * value binds it to signals — see {@link Style}. */\n style: Style<this, S>;\n /** Author-given semantic name — a stable selector for tests and for marking elements in the AI\n * code-review feedback loop; surfaced in the renderer's serialized output. Set it with `.named()`\n * (chainable) or assign it. */\n name?: string;\n /** Set the semantic name (chainable). */\n named(name: string): this;\n /** Theme variables for THIS element's subtree (chainable): the same keys as the app-wide\n * `theme()`, read by everything under the element — and by the kit components there — before\n * the app's table. `null` takes a key out of the scope. Reaches the element's descendants in\n * the tree (a pager's pages and a list's items included); a screen pushed over it and a widget\n * are roots of their own. Re-calling restyles the live subtree.\n * ```ts\n * promo.theme({ accent: \"#FF3B30\" }) // one card in another accent\n * sheet.theme({ bg: \"#000\", text: \"#FFF\" }) // a dark screen in a light app\n * ``` */\n theme(values: ThemeRoles & Record<string, string | number | null>): this;\n /** Tween to the target style — meta keys `duration`/`delay`/`loop`/…, see {@link AnimateStyle}. */\n animateTo: AnimateStyle<this, A>;\n /** Tween from the given style to the current one (entrance animations). */\n animateFrom: AnimateStyle<this, A>;\n /** Fires after every layout pass with the parent-relative box. */\n onLayout(onLayout: OnLayoutCallback): this;\n /** Absolute rect in device space, read live (includes scroll); `null` before layout. */\n getBoundingClientRect(): BoundingClientRect | null;\n /** The parent element, or `null` for a root (a screen, a widget, an unmounted subtree's top). */\n readonly parent: UINode | null;\n /** Free this element's subtree now (views, layout, native state). Only for a DETACHED subtree —\n * remove / hide / close it first; an attached one is left alone. After it the element is dead. */\n destroy(): void;\n /** Style-class proxy — read `el.class.checked`, set `el.class.checked = true`, toggle with\n * `!el.class.checked`, bind `el.class.done = () => sig.value`, batch/chain `el.class({ … })`.\n * Classes cascade to descendants. See {@link Classes}. */\n readonly class: Classes<this>;\n}\n/** {@link UIElementBase} plus the child-management surface every container shares. */\nexport interface UIContainerBase<S extends object, A extends object = S> extends UIElementBase<S, A> {\n /** Append children. */\n append(...nodes: UINodeChild[]): this;\n /** Insert children at `index`. */\n insert(index: number, ...nodes: UINodeChild[]): this;\n /** Remove (unmount) the given children. */\n remove(...nodes: UINodeChild[]): this;\n /** Replace all children — an array, or a function for reactive children. */\n setContent(nodes: UINodeChild[] | ChildrenFn): this;\n /** The children — a SNAPSHOT read from the runtime; mutate via `append`/`insert`/`remove`/`setContent`. */\n readonly children: UINode[];\n}\nexport type StyleFn<R, T extends object> = ((style: Reactive<T> & ClassStyles<T>) => R);\n/** The `el.style` surface: callable — `.style({...})` merges and returns the element for\n * chaining — and per-key readable/writable (`el.style.opacity = 0.5`; a `() => value` write\n * installs a reactive binding). Reads answer what the app set. */\nexport type Style<R, T extends object> = StyleFn<R, T> & T & ClassStyles<T>;\n/** Style props of an animate bag: a single value (tween from the current value) or an array of\n * KEYFRAMES (`opacity: [1, 0.3, 1]`, offsets via `times`). */\nexport type AnimateProps<T extends object> = {\n [K in keyof T]?: T[K] | T[K][];\n};\n/** The `animateTo`/`animateFrom` surface: target style props (single values or keyframe arrays) plus\n * the flat meta keys — `duration` / `delay` / `easing` / `times` / `loop` / `loopMode` / `commit` /\n * `clock`, see {@link TweenMeta}. Returns the {@link Animation} handle (seek, rate, `finished`). */\nexport type AnimateStyle<R, T extends object> = ((style: AnimateProps<T> & TweenMeta) => Animation);\nexport type AppearStyle<R, T> = (arg: {\n from: T;\n duration?: number;\n delay?: number;\n}) => R;\nexport type DisappearStyle<R, T> = (arg: {\n to: T;\n duration?: number;\n delay?: number;\n}) => R;\n/** `onLayout` payload — the node's box in PARENT-relative coordinates. */\nexport type OnLayoutCallback = (layout: {\n left: number;\n top: number;\n width: number;\n height: number;\n}) => void;\n/** Web-DOMRect shape on purpose (getBoundingClientRect priors must hold): all eight fields, with\n * right/bottom/x/y derived SDK-side — hosts only report [left, top, width, height]. */\nexport type BoundingClientRect = {\n x: number;\n y: number;\n left: number;\n top: number;\n right: number;\n bottom: number;\n width: number;\n height: number;\n};\nexport declare class Element<T extends string> implements TreeElement {\n readonly type: T;\n private _name?;\n protected _styleProxy: any;\n constructor(type: T, style: any);\n get name(): string | undefined;\n set name(value: string | undefined);\n named(name: string): this;\n theme(values: Record<string, string | number | null>): this;\n get style(): any;\n /** Tween to the target style and commit it (unless `commit: false` or looping — a loop is an\n * effect, not a state change). A prop value may be an array of keyframes; meta keys\n * `duration`/`delay`/`easing`/`times`/`loop`/… — see {@link AnimateStyle}. Returns the\n * {@link Animation} handle. */\n animateTo(style: any): Animation;\n /** Tween FROM the given style to the element's current one (entrance animations): the element's\n * own style is the implicit last keyframe. Never modifies the stored style. */\n animateFrom(style: any): Animation;\n protected _classProxy?: any;\n /** Style-class control — flips the `$`-class blocks declared in `.style()`. One proxy, same\n * contract as `el.style`:\n *\n * - `el.class.checked` — read: is the class active on THIS element? → `boolean`\n * - `el.class.checked = true` / `= false` — activate / deactivate\n * - `el.class.open = !el.class.open` — toggle\n * - `el.class.done = () => todo.done.value` — reactive: the class tracks the signals the\n * function reads; a later write to the same class (plain or function) replaces the binding\n * - `el.class({ checked: true, done: () => … })` — batch form, returns the element (chainable)\n *\n * Names are accepted with or without the leading `$`. A class set on an element CASCADES: it is\n * also active on every descendant (their same-name `$` blocks light up), until the subtree's\n * root — hosted screens/widgets don't inherit. Reads reflect only this element's own classes;\n * there is no opt-out below an active ancestor. `Object.keys(el.class)` lists the active names.\n * The reserved classes (`$hovered` `$pressed` `$focused` `$landscape` `$portrait`) are the\n * system's: writing one throws. */\n get class(): any;\n protected ll?: OnLayoutCallback[];\n /** Observe layout: fires after every host layout pass with the parent-relative box. */\n onLayout(onLayout: OnLayoutCallback): this;\n /** Absolute rect in device space — the space `UIWidget` positions in and touch events report\n * `clientX`/`clientY` in — including scroll offsets, read live at call time (unlike `onLayout`,\n * whose coordinates are parent-relative and go stale when an ancestor scrolls). `null` before\n * the element is laid out and on hosts without the read. Anchor popovers position-once\n * at open; don't poll per frame. */\n getBoundingClientRect(): BoundingClientRect | null;\n /** The parent element, or `null`. Resolves while the parent is itself attached (mounted under a\n * presented / router-held screen, a shown widget, a pager page …); a loose subtree's root is\n * held only by its handle and is not findable from its children. */\n get parent(): any;\n destroy(): void;\n}\n/** Reactive children: re-runs when a signal it read changes; the result is reconciled against\n * the mounted children (kept nodes stay mounted, state intact). */\nexport type ChildrenFn = () => UINodeChild[];\n/**\n * Compiler-emitted memoized map for reactive children. The chisel `reactiveUi` pass rewrites\n * `list.map(fn)` inside a children binding to `__uiMap(list, fn, \"<file>:<offset>\")`, so unchanged\n * items keep their element identity across re-runs (the reconciler then leaves them mounted).\n * Cache: per (binding owner, call-site slot), keyed by item reference; duplicate items consume\n * cached nodes in order. Outside a children binding, for non-array inputs, or for non-element\n * results it behaves exactly like Array.prototype.map — a wrong rewrite can't change behavior.\n */\nexport declare function __uiMap(list: any, render: (item: any, index: number) => any, slot: string): any[];\nexport declare class ContainerElement<T extends string> extends Element<T> {\n constructor(type: T, style: any, children: any[] | ChildrenFn);\n /** The children — a snapshot read from the runtime (falsy entries were never mounted). */\n get children(): any[];\n private _insertAt;\n /** Append children (falsy entries are skipped). */\n append(...nodes: UINodeChild[]): this;\n /** Insert children at `index`. */\n insert(index: number, ...nodes: UINodeChild[]): this;\n /** Remove (unmount) the given children. The removed subtrees stay valid (re-appendable) as long\n * as you hold them; dropped ones are freed. */\n remove(...nodesToDelete: UINodeChild[]): this;\n /** Replace all children — a plain array, or a function for reactive children. */\n setContent(children: UINodeChild[] | ChildrenFn): this;\n}\nexport {};\n","types/ui/UIPager.d.ts":"import { ContainerElement, type BaseStyle, type ChildrenFn, type DrawableStyle, type ElementStyle, type UIElementBase, type UINodeChild } from \"./UINode\";\nimport type { UIScreen } from \"./UIScreen\";\nimport type { NavigateOptions, PopOptions } from \"./router\";\n/** Styles a pager accepts — layout box + drawable (background, borders, …). Pages style\n * themselves; the pager only owns its own slot. */\nexport type UIPagerStyle = ElementStyle & DrawableStyle;\n/**\n * The screen-navigation element: sibling **tabs** that swipe natively side to side, each with its\n * own navigation **stack**. `push` opens a screen on top of the current tab (within the pager);\n * `pop` / the native edge back-swipe unwinds it. A one-tab pager is a plain navigation stack.\n *\n * ```ts\n * const pager = UIPager([ HomeScreen(), ProfileScreen() ]) // two tabs, side by side\n * Router.init(UIScreen([ pager.style({ flexGrow: 1 }), tabBar ]))\n *\n * // from anywhere inside a hosted screen — no reference threading:\n * UIPager.push(PostScreen(id))\n * ```\n *\n * To open something over *everything* (above bars, above the pager), use `Router.push` instead.\n */\nexport interface UIPager extends UIElementBase<UIPagerStyle, DrawableStyle & BaseStyle> {\n readonly type: \"pager\";\n /** Replace the pager's tabs — one screen per tab, in order. Every tab becomes a fresh\n * one-screen stack (pushed screens are dropped) and the selection is clamped into range;\n * screens that were already tabs keep their state. Pass a function for reactive tabs. */\n setContent(tabs: UIScreen[] | (() => UIScreen[])): this;\n /** Switch to tab `index`. **Instant by default** — the tab-bar convention (tabs are parallel\n * modes, not neighbors); pass `animated: true` for the direction-aware slide of top-tab /\n * pager UIs. Out-of-range and same-index calls are no-ops. Tabs keep their stacks: selecting\n * away and back restores the tab exactly where it was, pushed screens included. */\n select(index: number, animated?: boolean): this;\n /** The selected tab index (0-based). */\n readonly index: number;\n /** Fires when the selected tab changes and has settled — a user swipe or `select()`. */\n onSelect(callback: (index: number) => void): this;\n /** Push `screen` on top of the **current tab**; the edge back-swipe (or `pop()`) removes it.\n * Other tabs are unaffected. Transitions as in `Router.push`: `\"push\"` unless one is named, and\n * the screen remembers its way back (`popTransition`, or the mirror of the way it came). */\n push(screen: UIScreen, opts?: NavigateOptions): this;\n /** Pop the current tab's top screen (no-op at the tab root — the root never pops). The\n * programmatic twin of the native edge back-swipe. Plays the way back the screen remembers\n * unless a transition is named. */\n pop(opts?: PopOptions): this;\n /** Unwind the current tab back to its root screen in one step: the top screen leaves with its\n * way back (or the named transition), the ones between are never shown. */\n popToRoot(opts?: PopOptions): this;\n /** Swap the current tab's top screen for `screen` without growing the stack (at depth 1 this\n * swaps the tab's root). `\"fade\"` unless a transition is named; the way back stays the one of\n * the place in the stack unless `popTransition` names another. */\n replace(screen: UIScreen, opts?: NavigateOptions): this;\n /** The current tab's screens, root → top (read-only snapshot). */\n readonly stack: UIScreen[];\n /** The current tab's stack depth — 1 means only the root. While `depth > 1`, swiping between\n * tabs is disabled (the horizontal gesture belongs to the back-swipe). */\n readonly depth: number;\n /** Fires when the current tab's depth changes — push, pop, replace, or a back-swipe. */\n onChange(callback: (depth: number) => void): this;\n /** The pages, tab-major (every tab's stack root → top). */\n readonly children: UIScreen[];\n}\nexport declare class PagerElement extends ContainerElement<\"pager\"> {\n _openCount: number;\n private scl;\n private ncl;\n constructor(style: UIPagerStyle | null, tabs: UIScreen[]);\n /** Start offset of tab `i`'s segment in the flat `_pages`. */\n private _offset;\n /** Push the whole picture to the runtime. */\n private _sync;\n get children(): any[];\n get index(): number;\n get stack(): UIScreen[];\n get depth(): number;\n onSelect(callback: (index: number) => void): this;\n onChange(callback: (depth: number) => void): this;\n select(index: number, animated?: boolean): this;\n push(screen: UIScreen, opts?: NavigateOptions): this;\n pop(opts?: PopOptions): this;\n popToRoot(opts?: PopOptions): this;\n replace(screen: UIScreen, opts?: NavigateOptions): this;\n private _rebuild;\n setContent(children: UINodeChild[] | ChildrenFn): this;\n append(...nodes: UINodeChild[]): this;\n insert(index: number, ...nodes: UINodeChild[]): this;\n remove(...nodesToDelete: UINodeChild[]): this;\n _reconcile(next: UINodeChild[]): void;\n private _emitSelect;\n private _emitChange;\n private _track;\n _activate(): void;\n _deactivate(): void;\n}\n/** Callable factory + ambient statics. The name `UIPager` is a value (this factory) and a type\n * (the instance interface above) — a standard value/type merge. */\ninterface UIPagerConstructor {\n /** Tabs — each argument is a screen or an array of screens (arrays flatten one level, falsy\n * entries are skipped). One screen → a plain navigation stack rooted at it (push/pop, no tab\n * swiping); several → swipeable sibling tabs, fixed at construction, each starting as its own\n * one-screen stack. */\n (...tabs: (UIScreen | UIScreen[] | false | null | undefined)[]): UIPager;\n /** The pager that owns the currently visible screen, or `null` when the visible screen isn't\n * hosted by one. With pagers nested inside pages, resolves to the **innermost** — so ambient\n * calls act on the pager the user is actually looking at. */\n readonly current: UIPager | null;\n /** `UIPager.current.push(screen)` — push onto the pager owning the visible screen, no\n * reference threading. No-op with a console warning when there is no current pager. */\n push(screen: UIScreen, opts?: NavigateOptions): void;\n /** `UIPager.current.pop()` — pop the visible pager's current tab (no-op at the tab root, or\n * with a warning when there is no current pager). */\n pop(opts?: PopOptions): void;\n /** `UIPager.current.popToRoot()` — unwind the visible pager's current tab to its root. */\n popToRoot(opts?: PopOptions): void;\n}\n/**\n * Create a pager — THE screen-navigation element: an array of screens becomes swipeable sibling\n * tabs, a single screen becomes a plain stack. Navigate within it via `pager.push/pop/replace`\n * (per-tab) and `pager.select(i)` (between tabs), or from any child screen via the ambient\n * `UIPager.push` / `UIPager.pop` / `UIPager.current`. Pages are full `UIScreen`s (own\n * `onOpen`/`onClose`); give the pager `flexGrow: 1` or a size so it doesn't\n * collapse. `Router` stays the way to open a destination ON TOP of the pager.\n */\nexport declare const UIPager: UIPagerConstructor;\nexport {};\n","types/ui/UIPopover.d.ts":"import { ModalElement, type UIModal, type UIModalStyle } from \"./UIModal\";\nimport { type BoundingClientRect, type ChildrenFn, type UIChildArg, type UINodeChild } from \"./UINode\";\nexport type UIPopoverStyle = UIModalStyle;\n/** What a popover can anchor to: any element (it reads `getBoundingClientRect()`), or a raw\n * `{x, y}` point — a long-press context menu anchors to the touch position. */\nexport type UIPopoverAnchor = {\n getBoundingClientRect(): BoundingClientRect | null;\n} | {\n x: number;\n y: number;\n};\n/**\n * An anchored menu: a `UIModal` whose scrim is transparent (invisible but still intercepting —\n * an outside tap dismisses, and nothing underneath can scroll while it's open) and whose\n * position comes from the anchor passed to `show(anchor)`: below the anchor's left edge,\n * flipped above when there's no room, clamped into the viewport. Position is computed once per\n * show — anchored popovers don't follow their anchor. Backs dropdowns, context menus, and\n * tooltips; create it **once** at module scope and reuse it.\n */\nexport interface UIPopover extends UIModal {\n /** Position next to `anchor` (an element or an `{x, y}` point), put the popover where the\n * anchor is — the anchor's screen, page or surface content, found through the tree, so the\n * menu lands where it was opened and goes with it — and play the entrance transition. A\n * popover with no anchor and no parent goes to the app layer; without an anchor it shows\n * wherever its own style puts it. */\n show(anchor?: UIPopoverAnchor): void;\n}\nexport declare class PopoverElement extends ModalElement {\n private _anchorRect?;\n private _placedLeft?;\n private _placedTop?;\n constructor(style: UIPopoverStyle, children: UINodeChild[] | ChildrenFn);\n show(anchor?: UIPopoverAnchor): void;\n private _place;\n}\n/** Create an anchored popover (see {@link UIPopover}) — create once at module scope, then\n * `show(anchor)` next to an element or `{x, y}` point. Same argument forms as `UIColumn`. */\nexport declare function UIPopover(...children: UIChildArg[]): UIPopover;\nexport declare function UIPopover(children: UINodeChild[] | ChildrenFn): UIPopover;\n","types/ui/UIScreen.d.ts":"import { TouchStartEvent } from \"../runtime/touch\";\nimport { type DismissOptions, type PresentOptions } from \"./presentable\";\nimport { ContainerElement, type BaseStyle, type ContainerStyle, type DrawableStyle, type PaddingStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn } from \"./UINode\";\nexport type UIScreenStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle;\n/** A screen — the root the router/host mounts, sized to its slot. A screen NEVER scrolls: it is\n * fixed chrome (header, tab bar) plus, when the content overflows, one `UIScrollable` body child\n * (`flexGrow: 1`). Scroll events and pull-to-refresh live on the scroll containers\n * (`UIScrollable`, `UIVirtualizedList`). */\nexport interface UIScreen extends UIContainerBase<UIScreenStyle, DrawableStyle & BaseStyle> {\n readonly type: \"screen\";\n /** Show this screen as the current destination (replaces whatever is visible — a screen, a\n * scene, a native view — suspending an active Router until `Router.restore()`). */\n open(options?: PresentOptions): void;\n /** Dismiss if this screen is the visible destination. */\n close(options?: DismissOptions): void;\n /** Hardware/system back while this screen is current. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n /** The screen became the visible destination (first open, or revealed by a pop). */\n onOpen(callback: () => void): this;\n /** The screen stopped being visible — closed, replaced, or covered by a push. */\n onClose(callback: () => void): this;\n /**\n * Keep this screen's native state when a pager releases it: instead of dropping its view, the\n * host keeps it (scroll position, input text), so re-pushing the SAME screen object restores it\n * in place. `onClose`/`onOpen` still fire on detach/re-attach. Free it with `destroy()`.\n */\n keepAlive(enabled?: boolean): this;\n /**\n * The screen's ADDRESS on the web: while the screen is the one shown, the browser's address\n * bar shows it, and a link copied from there opens the app with it (`app.launchUrl`). A route,\n * not a page's address: `\"/product/42\"`, `\"/search?q=shoes\"` — the app never sees where the\n * page is served from. Call it again to change the address of a screen that is shown (a\n * filter, a search): the entry of the browser's history is replaced, not added to. `null`\n * takes the address away; a screen with none keeps the address of the one under it.\n *\n * The way in is the app's: read `app.launchUrl` at start and listen to the `\"url\"` event, as\n * for a deep link on a phone. No-op on hosts without an address bar.\n *\n * ```ts\n * const ProductScreen = (id: string) => UIScreen(...).url(`/product/${id}`)\n * ```\n */\n url(route: string | null): this;\n /** Touch began on the screen; `ev.track(...)` takes over the rest of the gesture. */\n onTouchStart(callback: (ev: TouchStartEvent<UIScreen>) => void): this;\n}\nexport declare class ScreenElement extends ContainerElement<\"screen\"> {\n constructor(type: \"screen\", style: any, children: any);\n open(options?: PresentOptions): void;\n close(options?: DismissOptions): void;\n protected ol: (() => void)[];\n onOpen(callback: () => void): this;\n protected cl: (() => void)[];\n onClose(callback: () => void): this;\n keepAlive(enabled?: boolean): this;\n url(route: string | null): this;\n readonly touchStartListeners: any[];\n onTouchStart(callback: any): this;\n private _backButtonCallback?;\n onBack(callback: any): this;\n /** @deprecated see the interface */\n onBackPressed(callback: any): this;\n}\n/** Create a screen. Present it with `.open()`, or via `Router` / `UIPager`. Same argument forms\n * as `UIColumn`. */\nexport declare function UIScreen(...children: UIChildArg[]): UIScreen;\nexport declare function UIScreen(children: UINodeChild[] | ChildrenFn): UIScreen;\n","types/ui/UIScrollable.d.ts":"import type { UIContainerStyle } from \"./UIContainer\";\nimport { type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn, type Color } from \"./UINode\";\nexport type ScrollStyle = {\n showScrollbar?: boolean;\n overscrollMode?: \"none\" | \"absorb\" | \"default\";\n /** Tint of the native pull-to-refresh spinner (pairs with `onRefresh`). */\n refreshControlColor?: Color;\n /** How a scroll gesture in THIS scrollable dismisses the keyboard: `\"interactive\"` (default) —\n * dragging over the keyboard slides it away (chat feel); `\"scroll\"` — any drag dismisses\n * immediately; `\"none\"` — never (tap-outside policy still applies). */\n keyboardDismissMode?: \"interactive\" | \"scroll\" | \"none\";\n /** Paging: when the drag ends, rest on a direct child's boundary along the scroll axis — the\n * value picks where the child sits in the viewport; `\"none\"` (default) is free scrolling. Snap\n * targets are the children themselves, so item widths can differ (card-carousel-with-peek); a\n * carousel is a horizontal scrollable of full-width children + `snap: \"start\"`. */\n snap?: \"none\" | \"start\" | \"center\" | \"end\";\n};\nexport type UIScrollableStyle = UIContainerStyle & ScrollStyle & {\n scrollDirection?: \"horizontal\" | \"vertical\";\n};\n/** A scroll container — vertical by default, `scrollDirection: \"horizontal\"` for carousels/chip\n * rows. The scrolling body of a screen (screens themselves never scroll). */\nexport interface UIScrollable extends UIContainerBase<UIScrollableStyle> {\n readonly type: \"scrollable\";\n /** Scroll position changed (px from the start edge). */\n onScroll(callback: (scrollPosition: number) => void): UIScrollable;\n /** The scroll gesture ended (finger lifted). */\n onScrollRelease(callback: () => void): UIScrollable;\n /** Pulled past the content edge by `delta` px. */\n onOverscroll(callback: (delta: number) => void): UIScrollable;\n /** Pull-to-refresh: the spinner stays until the returned promise settles. Vertical only. */\n onRefresh(callback: () => void | Promise<void>): UIScrollable;\n}\n/** Create a scroll container (same argument forms as `UIColumn`). As a screen body, pair with\n * `flexGrow: 1`. */\nexport declare function UIScrollable(...children: UIChildArg[]): UIScrollable;\nexport declare function UIScrollable(children: UINodeChild[] | ChildrenFn): UIScrollable;\n","types/ui/UISpacer.d.ts":"import { type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UISpacerStyle = ElementStyle;\n/** A flexible gap — `flexGrow: 1` by default, pushes its siblings apart. */\nexport interface UISpacer extends UIElementBase<UISpacerStyle> {\n readonly type: \"spacer\";\n}\n/** Create a flexible gap (`flexGrow: 1`) — e.g. between a header's title and its actions. */\nexport declare function UISpacer(): UISpacer;\nexport declare function UISpacer(style: UISpacerStyle): UISpacer;\n","types/ui/UITabs.d.ts":"import { type UIPager } from \"./UIPager\";\nimport { ScreenElement, UIScreen } from \"./UIScreen\";\nimport { type UIRow as UIRowType } from \"./UIContainer\";\nimport { type ImageSource } from \"./UIImage\";\nimport type { UIChildArg } from \"./UINode\";\nexport type UITabDef = {\n label: string;\n /** Tab icon — typically `assetIcon(\"lucide:…\")`. Tinted active/inactive by the bar. */\n icon?: ImageSource;\n /** The tab's root screen. Tabs are fixed at construction (like UIPager's). */\n screen: UIScreen;\n};\n/**\n * A bottom-tab app shell: swipeable tabs (a `UIPager`) plus a themed tab bar, as one\n * `UIScreen` — present it directly (`Router.init(tabs)`). Keys are tab ids, in tab order:\n *\n * ```ts\n * const tabs = UITabs({\n * home: { label: \"Home\", icon: assetIcon(\"lucide:house\"), screen: homeScreen },\n * profile: { label: \"Profile\", icon: assetIcon(\"lucide:user\"), screen: profileScreen },\n * })\n * Router.init(tabs)\n * ```\n *\n * In-tab navigation stays the pager's: `UIPager.push(detail)` from any screen (bar stays);\n * `Router.push` opens above the shell (bar covered). The bar is colored by the theme's roles\n * (`accent`, `textMuted`, `surface`, `border`); `tabs.bar.theme({...})` overrides them for this\n * bar alone, the `bar` handle restyles its box; for a fully custom bar build on `UIPager`.\n */\nexport interface UITabs extends UIScreen {\n /** The active tab id. */\n readonly tab: string;\n /** Switch tabs (instant, the tab-bar convention; `animated: true` slides). */\n select(id: string, animated?: boolean): this;\n /** Fires when the active tab changes and has settled — a bar tap, swipe, or `select()`. */\n onSelect(callback: (id: string, index: number) => void): this;\n /** Show a badge on a tab: `true` = dot, a number/string = count pill, `false`/`null`/`0` clears. */\n badge(id: string, value: number | string | boolean | null): this;\n /** The pager under the bar — in-tab stacks (`push`/`pop`/`depth`). */\n readonly pager: UIPager;\n /** The bar row (named \"tabbar\") — `bar.theme({ accent, textMuted, surface, border })` for this\n * bar's own colors, `bar.style({...})` for its box. */\n readonly bar: UIRowType;\n}\nexport declare class TabsElement extends ScreenElement {\n private readonly ids;\n private readonly _pagerEl;\n private readonly _bar;\n private readonly _icons;\n private readonly _labels;\n private readonly _badges;\n private readonly _badgeTexts;\n private readonly _buttons;\n private readonly _selectListeners;\n constructor(defs: Record<string, UITabDef>);\n private _applyActive;\n get tab(): string;\n get pager(): any;\n get bar(): any;\n select(id: string, animated?: boolean): this;\n onSelect(callback: (id: string, index: number) => void): this;\n badge(id: string, value: number | string | boolean | null | undefined): this;\n}\n/** Create the standard bottom-tab shell — see {@link UITabs}. Keys are tab ids in tab order;\n * each tab needs a `label` and its root `screen` (plus an optional `icon`). */\nexport declare function UITabs(tabs: Record<string, UITabDef>): UITabs;\n/** A `defineTabs` tab: `label` + optional `icon` (an `assetIcon(\"lucide:…\")` call — never a\n * hand-written source object). `UITabDef` is this plus the tab's root `screen`. */\nexport type TabDef = Omit<UITabDef, \"screen\">;\n/** What `defineTabs` returns: the bar (mount it yourself when the screen owns its whole layout)\n * and the standard screen shell around it. `active` must be a declared tab id, as a literal. */\nexport type TabsHandle<T extends Record<string, TabDef>> = {\n /** Tab ids in declaration order. */\n ids: (keyof T & string)[];\n /** The bar alone — one button per tab, the `active` one highlighted. */\n bar(active: keyof T & string): UIRowType;\n /** A screen sitting ON the bar: `[ padded content column, bar ]`. */\n screen(active: keyof T & string, ...children: UIChildArg[]): UIScreen;\n};\n/**\n * Declare a tab bar WITHOUT screens — the design-stage twin of {@link UITabs} (same keys, same\n * `tab-<id>` button names, same theme variables), for mockups where every screen is its own file\n * and mounts the bar with a literal tab id:\n *\n * ```ts\n * export const mainTabs = defineTabs({\n * home: { label: \"Home\", icon: assetIcon(\"lucide:house\") },\n * profile: { label: \"Profile\", icon: assetIcon(\"lucide:user\") },\n * })\n * // in a screen file:\n * export default () => mainTabs.screen(\"home\", [ ...content ])\n * ```\n *\n * The bar reads the theme's roles (`accent`, `textMuted`, `surface`, `border`), the screen its\n * `bg` — one `theme({...})` colors every bar at once. The built app passes the same keys (plus\n * each tab's root screen) to `UITabs`, which renders the identical bar interactively.\n */\nexport declare function defineTabs<T extends Record<string, TabDef>>(tabs: T): TabsHandle<T>;\n","types/ui/UIText.d.ts":"import { Element, type BaseStyle, type DrawableStyle, type ElementStyle, type TextStyle, type UIElementBase } from \"./UINode\";\nexport type UITextStyle = ElementStyle & TextStyle & DrawableStyle;\n/** A text label. */\nexport interface UIText extends UIElementBase<UITextStyle, DrawableStyle & BaseStyle & TextStyle> {\n readonly type: \"text\";\n /** The displayed string — writable at any time. */\n text: string;\n}\nexport declare class TextElement extends Element<\"text\"> {\n private _text;\n constructor(style: any, text: string | (() => string));\n get text(): string;\n set text(value: string);\n}\n/** Create a text label — a string, or `() => string` for reactive text that re-renders when a\n * signal it read changes. */\nexport declare function UIText(text: string | (() => string)): UIText;\n","types/ui/UIVideo.d.ts":"import type { VideoPlayer } from \"../runtime/media\";\nimport { type UIWidgetContent } from \"./UILayer\";\nimport { type DismissOptions, type PresentOptions } from \"./presentable\";\nimport { type BaseStyle, type DrawableStyle, type ElementStyle, type UIElementBase } from \"./UINode\";\nexport type UIVideoStyle = ElementStyle & DrawableStyle & {\n objectFit?: \"cover\" | \"contain\" | \"fill\";\n};\n/** A video surface showing a `VideoPlayer`'s output — embeddable in a screen AND\n * fullscreen-presentable (`open()`), with seamless promotion between the two. */\nexport interface UIVideo extends UIElementBase<UIVideoStyle, DrawableStyle & BaseStyle> {\n readonly type: \"video\";\n /** The player driving this surface (playback control lives on it). */\n player: VideoPlayer;\n /** Show fullscreen as the current destination. Promotion: if this video is mounted in a screen,\n * the SAME native player moves fullscreen — playback uninterrupted; a pop moves it back. */\n open(options?: PresentOptions): void;\n /** Dismiss if this is the visible destination. */\n close(options?: DismissOptions): void;\n /** Became the visible destination. */\n onOpen(callback: () => void): this;\n /** Stopped being the visible destination. */\n onClose(callback: () => void): this;\n /** Hardware/system back while current. */\n onBack(callback: () => void): this;\n /** The UI over the video when presented: widgets over it (`Presentable.setContent`). */\n setContent(content: UIWidgetContent): this;\n}\n/** Create a video node showing `player`'s output. */\nexport declare function UIVideo(player: VideoPlayer): UIVideo;\n","types/ui/UIVirtualizedList.d.ts":"import { Element, type Color, type DrawableStyle, type ElementStyle, type UIElementBase, type UINodeChild } from \"./UINode\";\nexport type UIVirtualizedListStyle = DrawableStyle & ElementStyle & {\n /** Tint of the native pull-to-refresh spinner (pairs with `onRefresh`). */\n refreshControlColor?: Color;\n /** Same key and semantics as UIScrollable's; `\"none\"` keeps a chat composer's keyboard up no\n * matter how the history is scrolled. */\n keyboardDismissMode?: \"interactive\" | \"scroll\" | \"none\";\n};\nexport interface VListConfig<T> {\n /** Stable unique key of an item. */\n keyOf: (item: T) => string;\n /** Subtree factory — called when the item enters the window; the subtree lives until it\n * leaves. */\n render: (item: T) => UINodeChild;\n /** Height estimate (px) used before the first measurement — a number, or a per-item function\n * (chat: `msg => 40 + Math.ceil(msg.text.length / 35) * 20`). Computed once when the item is\n * added. */\n estimatedHeight: number | ((item: T) => number);\n /** Extra px around the viewport kept mounted. Default: one viewport height. */\n overscan?: number;\n /** Chat mode: the first layout starts scrolled to the end, and appends auto-scroll while the\n * list sits at the bottom. */\n inverted?: boolean;\n}\n/** A windowed (virtualized) list: only the items near the viewport are mounted — for long feeds\n * and chats. Items are keyed; feed it via `setData`/`append`/`prepend`. */\nexport interface UIVirtualizedList<T = unknown> extends UIElementBase<UIVirtualizedListStyle> {\n readonly type: \"vlist\";\n /** Replace the data wholesale — vanished keys are unmounted by the window sync. */\n setData(items: T[]): this;\n /** Append items to the end (auto-scrolls when `inverted` and resting at the bottom). */\n append(...items: T[]): this;\n /** Insert at the start WITHOUT a scroll jump (the runtime compensates the offset). */\n prepend(...items: T[]): this;\n /** Update items with the same keys: mounted ones re-render; the cached height persists until\n * re-measured. */\n update(...items: T[]): this;\n /** Remove items by key. */\n removeByKey(...keys: string[]): this;\n /** Number of data items (mounted or not). */\n readonly itemCount: number;\n /** The data item under `key`, if any. */\n getItem(key: string): T | undefined;\n /** Scroll to `offset` px. */\n scrollTo(offset: number, animated?: boolean): void;\n /** Scroll to the item with `key`. */\n scrollToKey(key: string, animated?: boolean): void;\n /** Scroll to the end of the content. */\n scrollToEnd(animated?: boolean): void;\n /** Scroll position changed (px from the start edge). */\n onScroll(callback: (scrollPosition: number) => void): this;\n /** Pull-to-refresh: the spinner stays until the returned promise settles. */\n onRefresh(callback: () => void | Promise<void>): this;\n /** Fires within `thresholdPx` of the content's bottom edge — once, re-armed after leaving the\n * edge (a runtime-side latch). Infinite-scroll loading. */\n onEndReached(thresholdPx: number, callback: () => void): this;\n /** Same, for the top edge — chat history loading. */\n onStartReached(thresholdPx: number, callback: () => void): this;\n}\nexport declare class VListElement<T> extends Element<\"vlist\"> implements UIVirtualizedList<T> {\n private readonly sl;\n private readonly erl;\n private readonly strl;\n private _refreshCallback?;\n private items;\n private mounted;\n private keyOf;\n private renderItem;\n private estimate;\n private readonly _overscan;\n private readonly _inverted;\n private _endThreshold;\n private _startThreshold;\n private _inited;\n constructor(config: VListConfig<T>);\n private _ensure;\n private register;\n setData(items: T[]): this;\n append(...items: T[]): this;\n prepend(...items: T[]): this;\n update(...items: T[]): this;\n removeByKey(...keys: string[]): this;\n get itemCount(): number;\n getItem(key: string): T | undefined;\n scrollTo(offset: number, animated?: boolean): void;\n scrollToKey(key: string, animated?: boolean): void;\n scrollToEnd(animated?: boolean): void;\n onScroll(callback: (scrollPosition: number) => void): this;\n onRefresh(callback: () => void | Promise<void>): this;\n onEndReached(thresholdPx: number, callback: () => void): this;\n onStartReached(thresholdPx: number, callback: () => void): this;\n}\n/** Create a virtualized list from a config (`keyOf` + `render` + `estimatedHeight` required),\n * then feed it via `setData`/`append`/`prepend`. Give it a size (`flexGrow: 1` as a screen body). */\nexport declare function UIVirtualizedList<T>(config: VListConfig<T>): UIVirtualizedList<T>;\n","types/ui/UIWidget.d.ts":"import { TouchStartEvent } from \"../runtime/touch\";\nimport { ContainerElement, type BaseStyle, type Color, type ContainerStyle, type DrawableStyle, type PaddingStyle, type PositionStyle, type UIChildArg, type UIContainerBase, type UINodeChild, type ChildrenFn } from \"./UINode\";\nexport type UIWidgetStyle = ContainerStyle & DrawableStyle & PaddingStyle & BaseStyle & PositionStyle & {\n /** Shown (`\"flex\"`, the default) or not: what `show()` / `hide()` write, what a state block may\n * flip (`$open: { display: \"flex\" }`). */\n display?: \"none\" | \"flex\";\n /** A layer behind the widget that intercepts clicks — `\"transparent\"` still intercepts, `null`\n * removes the layer. A tap on it fires `onOverlayTap`. */\n overlayColor?: Color | null;\n};\n/** A floating overlay that belongs to a WINDOW, not to a box (docs/plans/widgets-plan.md): a dialog,\n * a sheet, a HUD, a mini-player. A widget is a CHILD of the place it belongs to — a `UIScreen`\n * (among its children), a surface's content (`scene.setContent([hud])`) or the app layer\n * (`UIOverlay`) — and is laid out and painted in the box of the outermost presented destination\n * that contains it: absolutely positioned in that box, above everything else in it. A widget on a\n * tab page covers the tab bar and rides the shell's push and pop. A widget inside a `UIColumn` or\n * any other box is an error: a floating element of a box is an absolute child, not a widget.\n *\n * It shows with its place unless its style says `display: \"none\"`; `show()` / `hide()` flip that,\n * and so does a state block (`$class: { display: \"flex\" }`). `UIModal` / `UIPopover` /\n * `UIBottomSheet` build on it. */\nexport interface UIWidget extends UIContainerBase<UIWidgetStyle, DrawableStyle & BaseStyle & {\n overlayColor?: Color | null;\n}> {\n readonly type: \"widget\";\n /** Show the widget: `display: \"flex\"`, on top of its root — it moves to the end of its parent's\n * children, so a dialog opened later covers an earlier one and a HUD declared after it. A widget\n * with no parent is appended to the app layer first (`UIOverlay`) — a global overlay above every\n * destination, up until `hide()`. */\n show(): void;\n /** Hide the widget: `display: \"none\"`. It stays where it is (its place, the app layer), ready\n * for the next `show()`. */\n hide(): void;\n /** Shown right now by its own display (`show()` ran, `hide()` hasn't, no state block hides\n * it). True for a widget hidden WITH its page or its covered screen: that is its place's\n * visibility, not the widget's. */\n readonly isShown: boolean;\n /** Touch began on the widget; `ev.track(...)` takes over the rest of the gesture. */\n onTouchStart(callback: (ev: TouchStartEvent<UIWidget>) => void): this;\n /** Tap on the overlay layer (requires an `overlayColor`). */\n onOverlayTap(callback: () => void): this;\n /** Hardware/system back while the widget is shown. */\n onBack(callback: () => void): this;\n /** @deprecated Renamed `onBack` (2026-09-26). An alias for the projects compiled before the\n * rename; removed with the release that recompiles them. */\n onBackPressed(callback: () => void): this;\n}\nexport declare class WidgetElement extends ContainerElement<\"widget\"> {\n scrollable: false;\n constructor(type: \"widget\", style: UIWidgetStyle, children: UINodeChild[] | ChildrenFn);\n show(): void;\n hide(): void;\n get isShown(): boolean;\n readonly touchStartListeners: any[];\n onTouchStart(callback: any): this;\n readonly otl: (() => void)[];\n onOverlayTap(callback: () => void): this;\n private _backButtonCallback?;\n onBack(callback: any): this;\n /** @deprecated see the interface */\n onBackPressed(callback: any): this;\n}\n/** Create a widget (same argument forms as `UIColumn`). Put it where it belongs — among a screen's\n * children, in `scene.setContent([...])`, or `UIOverlay` — position it with absolute-style props\n * (`top`/`left`/`bottom`/`right`), then `show()`/`hide()`. */\nexport declare function UIWidget(...children: UIChildArg[]): UIWidget;\nexport declare function UIWidget(children: UINodeChild[] | ChildrenFn): UIWidget;\n","types/version.d.ts":"export declare const SDK_VERSION = \"2.0.10\";\n/** The major of a semver string, or null when it is not one. */\nexport declare const sdkMajor: (version: string | null | undefined) => number | null;\n/** The `// sdk: <version>` line of a compiled bundle's header (sdk/src/compile/header.ts), read from\n * its first bytes; null for a bundle compiled before the line existed (SDK 0.x / 1.x — the\n * pre-tree contract, which no 2.x host runs). */\nexport declare const bundleSdkVersion: (head: string) => string | null;\n/** Whether a host embedding `hostVersion` can run a bundle whose header carries `bundleVersion`\n * (null = no line = pre-2.0 contract): the majors must match. */\nexport declare const bundleRunsOn: (bundleVersion: string | null, hostVersion: string) => boolean;\n"}
|