import { ChannelName } from "../materials/channels.js"; import { MaterialEffect } from "../materials/MaterialEffect.js"; import { ColorTransformFn } from "../materials/EffectMaterial.js"; import { Sprite2DMaterial } from "../materials/Sprite2DMaterial.js"; import { SpriteBatch } from "../pipeline/SpriteBatch.js"; import { Light2D } from "../lights/Light2D.js"; import { LightStore } from "../lights/LightStore.js"; import { SDFGenerator } from "../lights/SDFGenerator.js"; import { LightEffect } from "../lights/LightEffect.js"; import { OcclusionPass } from "../lights/OcclusionPass.js"; import { SystemSchedule } from "./SystemSchedule.js"; import { Sprite2D } from "../sprites/Sprite2D.js"; import { Group, Object3D, OrthographicCamera, Scene, Texture, Vector2 } from "three"; import { WebGPURenderer } from "three/webgpu"; import { Entity, Trait } from "koota"; import Node from "three/src/nodes/core/Node.js"; //#region src/ecs/traits.d.ts /** Sprite frame UV in atlas (x, y, width, height) normalized 0-1 */ declare const SpriteUV: Trait<{ x: number; y: number; w: number; h: number; }>; /** Sprite tint color and alpha (r, g, b, a) */ declare const SpriteColor: Trait<{ r: number; g: number; b: number; a: number; }>; /** Sprite flip flags: 1 = normal, -1 = flipped */ declare const SpriteFlip: Trait<{ x: number; y: number; }>; /** * Sort key for batching: numeric sortLayer value (changing this triggers * batch reassignment). Cross-primitive — sprites, particles, and future * batchers all participate through this same trait. */ declare const SortLayer: Trait<{ value: number; }>; /** Z-index within sortLayer for depth sorting (does NOT affect batch assignment) */ declare const SpriteZIndex: Trait<{ zIndex: number; }>; /** Material reference for batching (batchId from Sprite2DMaterial) */ declare const SpriteMaterialRef: Trait<{ materialId: number; }>; /** * Three's `Object3D.layers` bitmask, mirrored into the ECS so mask * mutations (via the wrapped `Layers` instance on Sprite2D) trigger * batch re-routing. Part of the batch run key — different camera masks * route to differently-masked batches (still batched, never standalone). */ declare const CameraLayersMask: Trait<{ mask: number; }>; /** Tag: entity is renderable (has all required components for rendering) */ declare const IsRenderable: import("koota").TagTrait; /** Tag: entity is currently assigned to a SpriteBatch */ declare const IsBatched: import("koota").TagTrait; /** Tag: entity is rendering standalone (not in a batch) */ declare const IsStandalone: import("koota").TagTrait; /** * SoA cache of batch assignment for hot-path systems (transform sync, buffer sync). * batchIdx indexes into BatchRegistry.batchSlots[] to get the SpriteBatch. * slot is the index within that batch's GPU buffers. * Avoids O(n) relation resolution per entity per frame. */ declare const BatchSlot: Trait<{ batchIdx: number; slot: number; }>; /** * Relation: sprite entity → batch entity (exclusive: sprite can only be in one batch). * Pure membership marker — the slot index lives in BatchSlot, which batchSortSystem * keeps in sync on every swap (a slot on the relation would go stale after a sort). */ declare const InBatch: import("koota").Relation>>; /** * AoS — reference to the SpriteBatch that owns GPU buffers AND slot management. * SpriteBatch already has: writeColor(), writeUV(), writeFlip(), * writeMatrix(), writeCustom(), writeEffectSlot(), allocateSlot(), freeSlot(). */ declare const BatchMesh: Trait<() => { mesh: SpriteBatch | null; }>; /** * SoA — batch metadata for sorting/grouping (query-visible fields only). * Used by systems for run-key computation and sorted batch ordering. * batchIdx maps into BatchRegistry.batchSlots[] for O(1) mesh lookup. */ declare const BatchMeta: Trait<{ materialId: number; sortLayer: number; layersMask: number; renderOrder: number; batchIdx: number; }>; /** Tag: batch's material alpha-blends (`transparent && alphaTest === 0`). */ declare const IsAlphaBlendedBatch: import("koota").TagTrait; /** Tag: batch's material alpha-tests (`alphaTest > 0` — opaque fast path). */ declare const IsAlphaTestedBatch: import("koota").TagTrait; /** Tag: batch's material is lit (a lighting colorTransform is attached). */ declare const IsLitBatch: import("koota").TagTrait; /** Tag: batch's material is unlit. */ declare const IsUnlitBatch: import("koota").TagTrait; /** * Which geometry path the batch renders with. `synth-quad` (default * post vertex-binding reclaim) synthesizes the unit quad from * vertexIndex; `tight-mesh` is the alpha-blend overdraw-reduction path; * `custom` is reserved for user-supplied batch geometry. */ declare const BatchGeometryStrategy: Trait<() => { kind: "synth-quad" | "tight-mesh" | "custom"; }>; /** * A run groups batches sharing the same (materialId, sortLayer, * layers.mask) run-key dimensions. Each component is a real GPU * constraint: material = shader pipeline, sortLayer = render-list * position, layers.mask = camera visibility. */ interface BatchRun { materialId: number; sortLayer: number; layersMask: number; material: Sprite2DMaterial; batches: Entity[]; } /** * World-level singleton holding batch management state. * Spawned once by SpriteGroup; systems query for it. */ declare const BatchRegistry: Trait<() => { /** Runs indexed by run key — groups batches by (materialId, sortLayer, layers.mask). */ runs: Map; /** Sorted run keys for O(log R) binary search on insert. */ sortedRunKeys: string[]; /** Pool of recycled batch entities for reuse. */ batchPool: Entity[]; /** Active batch entities in sorted render order. */ activeBatches: Entity[]; /** Whether the scene graph children need rebuilding. */ renderOrderDirty: boolean; /** Maximum sprites per batch (explicit opt-in path). */ maxBatchSize: number; /** Tiered batch sizes for the auto-orchestrate path; null = fixed maxBatchSize. */ tierLadder: readonly number[] | null; /** Material references for schema version tracking. */ materialRefs: Map; /** * Per-texture default Sprite2DMaterials, scoped to this world — * replaces the cross-world static cache footgun. Registering an * effect on one world's default never leaks into another's. */ defaultMaterials: WeakMap, Sprite2DMaterial>; /** * World-scoped effect-variant materials (the constants-effect * counterpart of `defaultMaterials`): texture → variant key → * material. See `RegistryData.effectVariants` in ecs/batchUtils.ts * for the key composition. */ effectVariants: WeakMap, Map>; /** Indexed array of active SpriteBatch meshes for O(1) lookup from BatchSlot.batchIdx. */ batchSlots: (SpriteBatch | null)[]; /** Free indices in batchSlots for reuse. */ batchSlotFreeList: number[]; /** Flat array of Sprite2D refs indexed by entity SoA index (eid). * Pure array indexing — same O(1) pattern as other SoA stores. */ spriteArr: (Sprite2D | null)[]; /** Cached effect traits across all materials. Populated by materialVersionSystem. */ effectTraits: Map; /** Entities whose destruction is deferred to the top of the next frame. */ pendingDestroy: Entity[]; /** The SpriteGroup (parent Group) for scene graph sync. */ parentGroup: Group | null; /** Bound Group.prototype.add bypassing SpriteGroup override. */ parentAdd: ((...objects: Object3D[]) => Group) | null; /** Bound Group.prototype.remove bypassing SpriteGroup override. */ parentRemove: ((...objects: Object3D[]) => Group) | null; /** Whether auto-invalidate transforms is enabled. */ autoInvalidateTransforms: boolean; transformsDirty: boolean; /** The SystemSchedule for this world. */ schedule: SystemSchedule | null; /** * Monotonic counter of how many times `schedule.run` has executed * for this registry. Entry points (`SpriteGroup.update`, * `SpriteGroup.updateMatrixWorld`, `Flatland.render`) consult the * counter against their own last-seen value so that multiple * triggers inside one logical frame collapse to a single run. * * `Flatland.render` bumps a private "this frame runs allowed" * counter before running the schedule the first time; the second * and third entry points see that a run has already happened and * skip. Without this, `shadowPipelineSystem` fires three times per * frame (direct schedule.run + spriteGroup.update + scene * updateMatrixWorld) and the whole shadow pipeline gets paid for * 3× the cost. */ scheduleRuns: number; /** * Whether any occluder changed since the last shadow generation. * Set false at the top of `flushDirtyRangesSystem`, then set true if any * batch mesh reports `isDirty` before its trackers are flushed. * `shadowPipelineSystem` reads this to skip the occluder render + SDF * regen when nothing moved. Defaults true so the first frame regenerates. */ occludersDirty: boolean; }>; /** AoS — holds a post-processing pass function, order, and enabled state. */ declare const PostPassTrait: Trait<() => { fn: ((input: Node<"vec4">, uv: Node<"vec2">) => Node<"vec4">) | null; order: number; enabled: boolean; }>; /** World-level singleton for post-processing pass dirty tracking. */ declare const PostPassRegistry: Trait<() => { dirty: boolean; }>; /** AoS — holds a lighting ColorTransformFn and enabled state. */ declare const LightEffectTrait: Trait<() => { fn: ((ctx: { color: Node<"vec4">; atlasUV: Node<"vec2">; worldPosition: Node<"vec2">; }) => Node<"vec4">) | null; enabled: boolean; }>; /** * World-level singleton holding all lighting state. * Spawned by Flatland.setLighting(); lighting ECS systems read from this. * Replaces the scattered private fields on Flatland. */ /** * World-level singleton owning the shared shadow pipeline infrastructure. * * Multiple LightEffects can depend on SDF data (DefaultLightEffect for * shadows; future GI effects could share the same generators). Rather * than each effect owning its own SDFGenerator, the pipeline is shared * at the world level. * * Lifecycle: `shadowPipelineSystem` owns this trait end-to-end — it * allocates the generators when the active effect declares * `needsShadows`, resizes them as the viewport changes, runs the * per-frame pre-pass, and disposes on detach. Flatland does not touch * these fields. * * Fast-path contract: every field here is either a nullable object * reference or a small scalar. Consumers read via `entity.get(ShadowPipeline)` * (O(1) pointer deref in Koota) and mutate in place. No per-frame * allocation. */ declare const ShadowPipeline: Trait<() => { /** JFA SDF generator. Null while inactive. */ sdfGenerator: SDFGenerator | null; /** Occluder silhouette pre-pass. Null while inactive. */ occlusionPass: OcclusionPass | null; /** Last SDF render-target width (post-resolution-scale). */ width: number; /** Last SDF render-target height (post-resolution-scale). */ height: number; /** True once the first-frame init() has allocated GPU resources. */ initialized: boolean; /** Camera frustum/position at last generation — NaN sentinels force the * first compare to read "changed" so a camera pan/zoom regenerates. */ lastLeft: number; lastRight: number; lastTop: number; lastBottom: number; lastPosX: number; lastPosY: number; lastZoom: number; }>; declare const LightingContext: Trait<() => { /** Active LightEffect instance. */ effect: LightEffect | null; /** LightStore providing light data textures. */ lightStore: LightStore | null; /** Active Light2D objects. */ lights: Light2D[]; /** Wrapped light fn with per-instance lit-bit check (for batched sprites). */ wrappedLightFn: ColorTransformFn | null; /** Per-fragment channels required by the active LightEffect. */ requiredChannels: ReadonlySet; /** All tracked sprite materials for colorTransform assignment. */ materials: Set; /** Whether the lighting colorTransform needs reassigning to materials. */ dirty: boolean; /** Whether the effect has been initialized (init() called). */ initialized: boolean; /** Effect processing dimensions after applying LightEffect.resolutionScale. */ surfaceSize: Vector2; /** Whether the active effect needs a resize before its next update. */ resizePending: boolean; /** Renderer reference for GPU passes. */ renderer: WebGPURenderer | null; /** Camera for world bounds computation. */ camera: OrthographicCamera | null; /** Scene containing the sprites being lit — needed by the shadow pre-pass. */ scene: Scene | null; /** World size in units (computed from camera frustum). */ worldSize: Vector2; /** World offset (camera left/bottom). */ worldOffset: Vector2; }>; //#endregion export { BatchGeometryStrategy, BatchMesh, BatchMeta, BatchRegistry, BatchRun, BatchSlot, CameraLayersMask, InBatch, IsAlphaBlendedBatch, IsAlphaTestedBatch, IsBatched, IsLitBatch, IsRenderable, IsStandalone, IsUnlitBatch, LightEffectTrait, LightingContext, PostPassRegistry, PostPassTrait, ShadowPipeline, SortLayer, SpriteColor, SpriteFlip, SpriteMaterialRef, SpriteUV, SpriteZIndex }; //# sourceMappingURL=traits.d.ts.map