@ggez/three-runtime 0.1.0 → 0.1.2
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 +47 -1786
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../shared/src/utils.ts","../src/loader.ts","../../runtime-format/src/types.ts","../../runtime-format/src/format.ts","../src/object-factory.ts","../../runtime-build/src/bundle.ts","../../geometry-kernel/src/polygon/polygon-utils.ts","../../geometry-kernel/src/brush/brush-kernel.ts","../../geometry-kernel/src/mesh/editable-mesh.ts","../../runtime-build/src/snapshot-build.ts","../src/bundle.ts"],"sourcesContent":["import type {\n BrushNode,\n Entity,\n GeometryNode,\n GroupNode,\n InstancingNode,\n LightNode,\n MeshNode,\n ModelNode,\n ScenePathDefinition,\n NodeID,\n PrimitiveNode,\n SceneSettings,\n Transform,\n Vec2,\n Vec3,\n WorldSettings\n} from \"./types\";\nimport { Euler, Matrix4, Quaternion, Vector3 } from \"three\";\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y };\n}\n\nexport function createBlockoutTextureDataUri(color: string, edgeColor = \"#f5f2ea\", edgeThickness = 0.018): string {\n const size = 256;\n const frame = Math.max(2, Math.min(6, Math.round(size * edgeThickness)));\n const innerInset = frame + 3;\n const seamInset = innerInset + 5;\n const corner = 18;\n const highlight = mixHexColors(edgeColor, \"#ffffff\", 0.42);\n const frameColor = mixHexColors(edgeColor, color, 0.12);\n const innerShadow = mixHexColors(edgeColor, color, 0.28);\n const svg = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"0 0 ${size} ${size}\">\n <rect width=\"${size}\" height=\"${size}\" rx=\"${corner}\" fill=\"${color}\" />\n <rect x=\"${frame / 2}\" y=\"${frame / 2}\" width=\"${size - frame}\" height=\"${size - frame}\" rx=\"${corner - 2}\" fill=\"none\" stroke=\"${frameColor}\" stroke-width=\"${frame}\" />\n <rect x=\"${innerInset}\" y=\"${innerInset}\" width=\"${size - innerInset * 2}\" height=\"${size - innerInset * 2}\" rx=\"${corner - 5}\" fill=\"none\" stroke=\"${highlight}\" stroke-opacity=\"0.42\" stroke-width=\"1\" />\n <rect x=\"${seamInset}\" y=\"${seamInset}\" width=\"${size - seamInset * 2}\" height=\"${size - seamInset * 2}\" rx=\"${corner - 9}\" fill=\"none\" stroke=\"${innerShadow}\" stroke-opacity=\"0.12\" stroke-width=\"1\" />\n <path d=\"M ${innerInset} ${size * 0.28} H ${size - innerInset}\" stroke=\"${highlight}\" stroke-opacity=\"0.08\" stroke-width=\"1\" />\n <path d=\"M ${size * 0.28} ${innerInset} V ${size - innerInset}\" stroke=\"${highlight}\" stroke-opacity=\"0.06\" stroke-width=\"1\" />\n </svg>\n `.trim();\n\n return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`;\n}\n\nexport function vec3(x: number, y: number, z: number): Vec3 {\n return { x, y, z };\n}\n\nfunction mixHexColors(left: string, right: string, t: number) {\n const normalizedLeft = normalizeHex(left);\n const normalizedRight = normalizeHex(right);\n const leftValue = Number.parseInt(normalizedLeft.slice(1), 16);\n const rightValue = Number.parseInt(normalizedRight.slice(1), 16);\n const channels = [16, 8, 0].map((shift) => {\n const leftChannel = (leftValue >> shift) & 255;\n const rightChannel = (rightValue >> shift) & 255;\n return Math.round(leftChannel + (rightChannel - leftChannel) * t)\n .toString(16)\n .padStart(2, \"0\");\n });\n\n return `#${channels.join(\"\")}`;\n}\n\nfunction normalizeHex(color: string) {\n if (/^#[0-9a-f]{6}$/i.test(color)) {\n return color;\n }\n\n if (/^#[0-9a-f]{3}$/i.test(color)) {\n return `#${color\n .slice(1)\n .split(\"\")\n .map((channel) => `${channel}${channel}`)\n .join(\"\")}`;\n }\n\n return \"#808080\";\n}\n\nexport function toTuple(vector: Vec3): [number, number, number] {\n return [vector.x, vector.y, vector.z];\n}\n\nexport function addVec3(left: Vec3, right: Vec3): Vec3 {\n return vec3(left.x + right.x, left.y + right.y, left.z + right.z);\n}\n\nexport function subVec3(left: Vec3, right: Vec3): Vec3 {\n return vec3(left.x - right.x, left.y - right.y, left.z - right.z);\n}\n\nexport function scaleVec3(vector: Vec3, scalar: number): Vec3 {\n return vec3(vector.x * scalar, vector.y * scalar, vector.z * scalar);\n}\n\nexport function dotVec3(left: Vec3, right: Vec3): number {\n return left.x * right.x + left.y * right.y + left.z * right.z;\n}\n\nexport function crossVec3(left: Vec3, right: Vec3): Vec3 {\n return vec3(\n left.y * right.z - left.z * right.y,\n left.z * right.x - left.x * right.z,\n left.x * right.y - left.y * right.x\n );\n}\n\nexport function lengthVec3(vector: Vec3): number {\n return Math.sqrt(dotVec3(vector, vector));\n}\n\nexport function normalizeVec3(vector: Vec3, epsilon = 0.000001): Vec3 {\n const length = lengthVec3(vector);\n\n if (length <= epsilon) {\n return vec3(0, 0, 0);\n }\n\n return scaleVec3(vector, 1 / length);\n}\n\nexport function averageVec3(vectors: Vec3[]): Vec3 {\n if (vectors.length === 0) {\n return vec3(0, 0, 0);\n }\n\n const total = vectors.reduce((sum, vector) => addVec3(sum, vector), vec3(0, 0, 0));\n\n return scaleVec3(total, 1 / vectors.length);\n}\n\nexport function almostEqual(left: number, right: number, epsilon = 0.0001): boolean {\n return Math.abs(left - right) <= epsilon;\n}\n\nexport function snapValue(value: number, increment: number): number {\n if (increment <= 0) {\n return value;\n }\n\n return Math.round(value / increment) * increment;\n}\n\nexport function snapVec3(vector: Vec3, increment: number): Vec3 {\n return vec3(snapValue(vector.x, increment), snapValue(vector.y, increment), snapValue(vector.z, increment));\n}\n\nexport function makeTransform(position = vec3(0, 0, 0)): Transform {\n return {\n position,\n rotation: vec3(0, 0, 0),\n scale: vec3(1, 1, 1)\n };\n}\n\nexport function resolveTransformPivot(transform: Transform): Vec3 {\n return transform.pivot ?? vec3(0, 0, 0);\n}\n\nexport type SceneGraphResolution = {\n entityChildrenByParentId: Map<NodeID, Entity[\"id\"][]>;\n entityWorldTransforms: Map<Entity[\"id\"], Transform>;\n nodeChildrenByParentId: Map<NodeID, NodeID[]>;\n nodeWorldTransforms: Map<NodeID, Transform>;\n rootEntityIds: Entity[\"id\"][];\n rootNodeIds: NodeID[];\n};\n\nconst tempPosition = new Vector3();\nconst tempQuaternion = new Quaternion();\nconst tempScale = new Vector3();\n\nexport function composeTransforms(parent: Transform, child: Transform): Transform {\n const matrix = transformToMatrix(parent).multiply(transformToMatrix(child));\n return matrixToTransform(matrix, child.pivot);\n}\n\nexport function localizeTransform(world: Transform, parentWorld?: Transform): Transform {\n if (!parentWorld) {\n return structuredClone(world);\n }\n\n const matrix = transformToMatrix(parentWorld).invert().multiply(transformToMatrix(world));\n return matrixToTransform(matrix, world.pivot);\n}\n\nexport function resolveSceneGraph(\n nodes: Iterable<Pick<GeometryNode, \"id\" | \"parentId\" | \"transform\">>,\n entities: Iterable<Pick<Entity, \"id\" | \"parentId\" | \"transform\">> = []\n): SceneGraphResolution {\n const nodeList = Array.from(nodes);\n const entityList = Array.from(entities);\n const nodesById = new Map(nodeList.map((node) => [node.id, node]));\n const nodeWorldTransforms = new Map<NodeID, Transform>();\n const entityWorldTransforms = new Map<Entity[\"id\"], Transform>();\n const nodeChildrenByParentId = new Map<NodeID, NodeID[]>();\n const entityChildrenByParentId = new Map<NodeID, Entity[\"id\"][]>();\n const rootNodeIds: NodeID[] = [];\n const rootEntityIds: Entity[\"id\"][] = [];\n const nodeStack = new Set<NodeID>();\n\n const appendNodeChild = (parentId: NodeID, childId: NodeID) => {\n const children = nodeChildrenByParentId.get(parentId);\n\n if (children) {\n children.push(childId);\n return;\n }\n\n nodeChildrenByParentId.set(parentId, [childId]);\n };\n\n const appendEntityChild = (parentId: NodeID, childId: Entity[\"id\"]) => {\n const children = entityChildrenByParentId.get(parentId);\n\n if (children) {\n children.push(childId);\n return;\n }\n\n entityChildrenByParentId.set(parentId, [childId]);\n };\n\n const resolveNodeTransform = (node: Pick<GeometryNode, \"id\" | \"parentId\" | \"transform\">): Transform => {\n const cached = nodeWorldTransforms.get(node.id);\n\n if (cached) {\n return cached;\n }\n\n if (nodeStack.has(node.id)) {\n const fallback = structuredClone(node.transform);\n nodeWorldTransforms.set(node.id, fallback);\n return fallback;\n }\n\n nodeStack.add(node.id);\n\n const parent =\n node.parentId && node.parentId !== node.id\n ? nodesById.get(node.parentId)\n : undefined;\n const resolved = parent\n ? composeTransforms(resolveNodeTransform(parent), node.transform)\n : structuredClone(node.transform);\n\n nodeWorldTransforms.set(node.id, resolved);\n nodeStack.delete(node.id);\n return resolved;\n };\n\n nodeList.forEach((node) => {\n resolveNodeTransform(node);\n\n const hasValidParent = Boolean(\n node.parentId &&\n node.parentId !== node.id &&\n nodesById.has(node.parentId)\n );\n\n if (hasValidParent) {\n appendNodeChild(node.parentId!, node.id);\n return;\n }\n\n rootNodeIds.push(node.id);\n });\n\n entityList.forEach((entity) => {\n const parent =\n entity.parentId && nodesById.has(entity.parentId)\n ? nodesById.get(entity.parentId)\n : undefined;\n\n entityWorldTransforms.set(\n entity.id,\n parent ? composeTransforms(resolveNodeTransform(parent), entity.transform) : structuredClone(entity.transform)\n );\n\n if (parent) {\n appendEntityChild(parent.id, entity.id);\n return;\n }\n\n rootEntityIds.push(entity.id);\n });\n\n return {\n entityChildrenByParentId,\n entityWorldTransforms,\n nodeChildrenByParentId,\n nodeWorldTransforms,\n rootEntityIds,\n rootNodeIds\n };\n}\n\nexport function createDefaultSceneSettings(): SceneSettings {\n return {\n events: [],\n paths: [],\n player: {\n cameraMode: \"fps\",\n canCrouch: true,\n canJump: true,\n canRun: true,\n crouchHeight: 1.2,\n height: 1.8,\n jumpHeight: 1.2,\n movementSpeed: 4.5,\n runningSpeed: 7.5\n },\n world: {\n ambientColor: \"#ffffff\",\n ambientIntensity: 0.4,\n fogColor: \"#0b1118\",\n fogFar: 2000,\n fogNear: 500,\n gravity: vec3(0, -9.81, 0),\n lod: {\n bakedAt: \"\",\n enabled: false,\n lowDetailRatio: 0.22,\n midDetailRatio: 0.52\n },\n physicsEnabled: true,\n skybox: {\n affectsLighting: false,\n blur: 0,\n enabled: false,\n format: \"image\",\n intensity: 1,\n lightingIntensity: 1,\n name: \"\",\n source: \"\"\n }\n }\n };\n}\n\nexport function normalizeSceneSettings(settings?: Partial<SceneSettings> | SceneSettings): SceneSettings {\n const defaults = createDefaultSceneSettings();\n\n return {\n ...defaults,\n ...settings,\n events: normalizeSceneEvents(settings?.events),\n paths: normalizeScenePaths(settings?.paths),\n player: {\n ...defaults.player,\n ...(settings?.player ?? {})\n },\n world: normalizeWorldSettings(settings?.world)\n };\n}\n\nfunction normalizeWorldSettings(world?: Partial<WorldSettings> | WorldSettings): WorldSettings {\n const defaults = createDefaultSceneSettings().world;\n const fogNear = clampFiniteNumber(world?.fogNear, defaults.fogNear);\n const fogFar = clampFiniteNumber(world?.fogFar, defaults.fogFar);\n const resolvedFogNear = Math.max(0, fogNear);\n const lod = normalizeWorldLodSettings(world?.lod);\n const skybox = normalizeSceneSkybox(world?.skybox);\n\n return {\n ...defaults,\n ...world,\n fogNear: resolvedFogNear,\n fogFar: Math.max(resolvedFogNear + 0.01, fogFar),\n gravity: world?.gravity ?? defaults.gravity,\n lod,\n skybox,\n };\n}\n\nfunction normalizeWorldLodSettings(lod?: Partial<WorldSettings[\"lod\"]> | WorldSettings[\"lod\"]): WorldSettings[\"lod\"] {\n const defaults = createDefaultSceneSettings().world.lod;\n const resolvedMidDetailRatio = clampUnitInterval(clampFiniteNumber(lod?.midDetailRatio, defaults.midDetailRatio));\n const resolvedLowDetailRatio = Math.min(\n clampUnitInterval(clampFiniteNumber(lod?.lowDetailRatio, defaults.lowDetailRatio)),\n resolvedMidDetailRatio\n );\n\n return {\n ...defaults,\n ...lod,\n bakedAt: typeof lod?.bakedAt === \"string\" ? lod.bakedAt : defaults.bakedAt,\n enabled: Boolean(lod?.enabled),\n lowDetailRatio: resolvedLowDetailRatio,\n midDetailRatio: Math.max(resolvedMidDetailRatio, resolvedLowDetailRatio)\n };\n}\n\nfunction normalizeSceneSkybox(skybox?: Partial<WorldSettings[\"skybox\"]> | WorldSettings[\"skybox\"]): WorldSettings[\"skybox\"] {\n const defaults = createDefaultSceneSettings().world.skybox;\n const format = skybox?.format === \"hdr\" ? \"hdr\" : \"image\";\n\n return {\n ...defaults,\n ...skybox,\n affectsLighting: Boolean(skybox?.affectsLighting),\n blur: Math.min(1, Math.max(0, clampFiniteNumber(skybox?.blur, defaults.blur))),\n enabled: Boolean(skybox?.enabled),\n format,\n intensity: Math.max(0, clampFiniteNumber(skybox?.intensity, defaults.intensity)),\n lightingIntensity: Math.max(0, clampFiniteNumber(skybox?.lightingIntensity, defaults.lightingIntensity)),\n name: typeof skybox?.name === \"string\" ? skybox.name.trim() : defaults.name,\n source: typeof skybox?.source === \"string\" ? skybox.source.trim() : defaults.source\n };\n}\n\nfunction normalizeSceneEvents(events?: SceneSettings[\"events\"]): NonNullable<SceneSettings[\"events\"]> {\n return (events ?? []).map((eventDefinition) => ({\n ...eventDefinition,\n custom: eventDefinition.custom ?? true\n }));\n}\n\nfunction normalizeScenePaths(paths?: SceneSettings[\"paths\"]): NonNullable<SceneSettings[\"paths\"]> {\n return (paths ?? []).map((pathDefinition, index) => ({\n id: pathDefinition.id?.trim() || `path_${index + 1}`,\n loop: pathDefinition.loop ?? false,\n name: pathDefinition.name?.trim() || `Path ${index + 1}`,\n points: normalizeScenePathPoints(pathDefinition.points)\n }));\n}\n\nfunction normalizeScenePathPoints(points?: ScenePathDefinition[\"points\"]): ScenePathDefinition[\"points\"] {\n return (points ?? []).map((point) => ({\n x: clampFiniteNumber(point?.x, 0),\n y: clampFiniteNumber(point?.y, 0),\n z: clampFiniteNumber(point?.z, 0)\n }));\n}\n\nfunction clampFiniteNumber(value: number | undefined, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n\nfunction clampUnitInterval(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nexport function isBrushNode(node: GeometryNode): node is BrushNode {\n return node.kind === \"brush\";\n}\n\nexport function isMeshNode(node: GeometryNode): node is MeshNode {\n return node.kind === \"mesh\";\n}\n\nexport function isGroupNode(node: GeometryNode): node is GroupNode {\n return node.kind === \"group\";\n}\n\nexport function isModelNode(node: GeometryNode): node is ModelNode {\n return node.kind === \"model\";\n}\n\nexport function isPrimitiveNode(node: GeometryNode): node is PrimitiveNode {\n return node.kind === \"primitive\";\n}\n\nexport function isInstancingNode(node: GeometryNode): node is InstancingNode {\n return node.kind === \"instancing\";\n}\n\nexport function isLightNode(node: GeometryNode): node is LightNode {\n return node.kind === \"light\";\n}\n\nexport function isInstancingSourceNode(node: GeometryNode): node is BrushNode | MeshNode | PrimitiveNode | ModelNode {\n return isBrushNode(node) || isMeshNode(node) || isPrimitiveNode(node) || isModelNode(node);\n}\n\nexport function resolveInstancingSourceNode(\n nodes: Iterable<GeometryNode>,\n nodeOrId: GeometryNode | NodeID,\n maxDepth = 32\n) {\n const nodesById = new Map(Array.from(nodes, (node) => [node.id, node] as const));\n let current = typeof nodeOrId === \"string\" ? nodesById.get(nodeOrId) : nodeOrId;\n let depth = 0;\n\n while (current && depth <= maxDepth) {\n if (isInstancingSourceNode(current)) {\n return current;\n }\n\n if (!isInstancingNode(current)) {\n return undefined;\n }\n\n current = nodesById.get(current.data.sourceNodeId);\n depth += 1;\n }\n\n return undefined;\n}\n\nfunction transformToMatrix(transform: Transform) {\n return new Matrix4().compose(\n new Vector3(transform.position.x, transform.position.y, transform.position.z),\n new Quaternion().setFromEuler(new Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\")),\n new Vector3(transform.scale.x, transform.scale.y, transform.scale.z)\n );\n}\n\nfunction matrixToTransform(matrix: Matrix4, pivot?: Vec3): Transform {\n matrix.decompose(tempPosition, tempQuaternion, tempScale);\n const rotation = new Euler().setFromQuaternion(tempQuaternion, \"XYZ\");\n\n return {\n pivot: pivot ? vec3(pivot.x, pivot.y, pivot.z) : undefined,\n position: vec3(tempPosition.x, tempPosition.y, tempPosition.z),\n rotation: vec3(rotation.x, rotation.y, rotation.z),\n scale: vec3(tempScale.x, tempScale.y, tempScale.z)\n };\n}\n","import type { Asset, MaterialRenderSide, PropPhysics, SceneSkyboxSettings, Transform, Vec3 } from \"@ggez/shared\";\nimport { resolveInstancingSourceNode, resolveSceneGraph, vec3 } from \"@ggez/shared\";\nimport {\n AmbientLight,\n BackSide,\n Box3,\n BoxGeometry,\n BufferGeometry,\n Color,\n DirectionalLight,\n DoubleSide,\n EquirectangularReflectionMapping,\n Euler,\n Fog,\n Float32BufferAttribute,\n FrontSide,\n Group,\n InstancedMesh,\n HemisphereLight,\n LOD,\n Matrix4,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n PointLight,\n Quaternion,\n SRGBColorSpace,\n Scene,\n SpotLight,\n Texture,\n TextureLoader,\n RepeatWrapping,\n Vector3\n} from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport { HDRLoader } from \"three/examples/jsm/loaders/HDRLoader.js\";\nimport { MTLLoader } from \"three/examples/jsm/loaders/MTLLoader.js\";\nimport { OBJLoader } from \"three/examples/jsm/loaders/OBJLoader.js\";\nimport {\n isRuntimeBundle,\n isRuntimeScene,\n parseRuntimeScene,\n type RuntimeScene\n} from \"@ggez/runtime-format\";\nimport {\n createWebHammerSceneObjectFactory,\n extractPhysics as extractNodePhysics,\n findPrimaryLight as findNodePrimaryLight\n} from \"./object-factory\";\nimport type {\n WebHammerEngineBundle,\n WebHammerEngineModelNode,\n WebHammerEngineGeometryNode,\n WebHammerEngineNode,\n WebHammerEngineScene,\n WebHammerExportGeometry,\n WebHammerExportGeometryLod,\n WebHammerExportModelLod,\n WebHammerExportMaterial\n} from \"./types\";\n\ntype TextureSlot = \"baseColorTexture\" | \"metallicRoughnessTexture\" | \"normalTexture\";\n\nexport type WebHammerAssetResolverContext =\n | {\n kind: \"model\";\n node: Extract<WebHammerEngineNode, { kind: \"model\" }>;\n asset?: Asset;\n path: string;\n format: \"gltf\" | \"obj\";\n }\n | {\n kind: \"texture\";\n material: WebHammerExportMaterial;\n path: string;\n slot: TextureSlot;\n }\n | {\n kind: \"skybox\";\n path: string;\n skybox: SceneSkyboxSettings;\n };\n\nexport type WebHammerSceneLoaderOptions = {\n applyToScene?: Scene;\n castShadow?: boolean;\n lod?: WebHammerSceneLodOptions;\n receiveShadow?: boolean;\n resolveAssetUrl?: (context: WebHammerAssetResolverContext) => Promise<string> | string;\n};\n\nexport type WebHammerSceneLodOptions = {\n lowDistance: number;\n midDistance: number;\n};\n\nexport type ThreeRuntimeSceneInstance = {\n dispose: () => void;\n entities: WebHammerEngineScene[\"entities\"];\n lights: Object3D[];\n nodesById: Map<string, Object3D>;\n physicsDescriptors: Array<{\n nodeId: string;\n object: Object3D;\n physics: PropPhysics;\n }>;\n root: Group;\n scene: WebHammerEngineScene;\n};\n\nexport type WebHammerLoadedScene = ThreeRuntimeSceneInstance & {\n nodes: ThreeRuntimeSceneInstance[\"nodesById\"];\n physicsNodes: ThreeRuntimeSceneInstance[\"physicsDescriptors\"];\n};\n\nexport type ThreeRuntimeAssetResolverContext = WebHammerAssetResolverContext;\nexport type ThreeRuntimeSceneInstanceOptions = WebHammerSceneLoaderOptions;\nexport type ThreeRuntimeSceneLodOptions = WebHammerSceneLodOptions;\n\nconst textureLoader = new TextureLoader();\nconst gltfLoader = new GLTFLoader();\nconst hdrLoader = new HDRLoader();\nconst mtlLoader = new MTLLoader();\n\nexport function isWebHammerEngineScene(value: unknown): value is WebHammerEngineScene {\n return isRuntimeScene(value);\n}\n\nexport function isWebHammerEngineBundle(value: unknown): value is WebHammerEngineBundle {\n return isRuntimeBundle(value);\n}\n\nexport function parseWebHammerEngineScene(text: string): WebHammerEngineScene {\n return parseRuntimeScene(text);\n}\n\nexport async function fetchWebHammerEngineScene(url: string, init?: RequestInit): Promise<WebHammerEngineScene> {\n const response = await fetch(url, init);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch engine scene: ${response.status} ${response.statusText}`);\n }\n\n return parseWebHammerEngineScene(await response.text());\n}\n\nexport async function createThreeRuntimeSceneInstance(\n input: RuntimeScene | string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<ThreeRuntimeSceneInstance> {\n const engineScene = typeof input === \"string\" ? parseRuntimeScene(input) : parseRuntimeScene(JSON.stringify(input));\n const root = new Group();\n const nodesById = new Map<string, Object3D>();\n const lights: Object3D[] = [];\n const physicsDescriptors: ThreeRuntimeSceneInstance[\"physicsDescriptors\"] = [];\n const runtimeNodesById = new Map(engineScene.nodes.map((node) => [node.id, node]));\n const sceneGraph = resolveSceneGraph(engineScene.nodes, engineScene.entities);\n const objectFactory = createWebHammerSceneObjectFactory(engineScene, options);\n const createdObjects = await Promise.all(\n engineScene.nodes.map(async (node) => [node.id, await objectFactory.createNodeObject(node)] as const)\n );\n const attachedNodeIds = new Set<string>();\n const attachStack = new Set<string>();\n\n root.name = \"Web Hammer Scene\";\n root.userData.webHammer = {\n metadata: engineScene.metadata,\n settings: engineScene.settings\n };\n\n if (options.applyToScene) {\n await applyWebHammerWorldSettings(options.applyToScene, engineScene, options);\n }\n\n const worldAmbient = createWorldAmbientLight(engineScene);\n\n if (worldAmbient) {\n root.add(worldAmbient);\n lights.push(worldAmbient);\n }\n\n createdObjects.forEach(([nodeId, object]) => {\n nodesById.set(nodeId, object);\n });\n\n const attachNode = (nodeId: string) => {\n if (attachedNodeIds.has(nodeId)) {\n return;\n }\n\n const node = runtimeNodesById.get(nodeId);\n const object = nodesById.get(nodeId);\n\n if (!node || !object) {\n return;\n }\n\n if (attachStack.has(nodeId)) {\n root.add(object);\n attachedNodeIds.add(nodeId);\n return;\n }\n\n attachStack.add(nodeId);\n\n const parentObject =\n node.parentId && node.parentId !== node.id\n ? nodesById.get(node.parentId)\n : undefined;\n\n if (parentObject && !attachStack.has(node.parentId!)) {\n attachNode(node.parentId!);\n parentObject.add(object);\n } else {\n root.add(object);\n }\n\n attachStack.delete(nodeId);\n attachedNodeIds.add(nodeId);\n };\n\n for (const node of engineScene.nodes) {\n attachNode(node.id);\n }\n\n const instancingObjects = await objectFactory.createInstancingObjects();\n\n instancingObjects.forEach((object) => {\n root.add(object);\n });\n\n for (const node of engineScene.nodes) {\n const object = nodesById.get(node.id);\n\n if (!object) {\n continue;\n }\n\n const light = findNodePrimaryLight(object);\n\n if (light) {\n lights.push(light);\n }\n\n const physics = extractNodePhysics(node);\n\n if (physics?.enabled) {\n physicsDescriptors.push({\n nodeId: node.id,\n object,\n physics\n });\n }\n }\n\n return {\n dispose() {\n disposeThreeRuntimeSceneInstance(root);\n },\n entities: engineScene.entities.map((entity) => ({\n ...entity,\n transform: sceneGraph.entityWorldTransforms.get(entity.id) ?? entity.transform\n })),\n lights,\n nodesById,\n physicsDescriptors,\n root,\n scene: engineScene\n };\n}\n\nexport async function loadWebHammerEngineScene(\n input: WebHammerEngineScene | string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<WebHammerLoadedScene> {\n const instance = await createThreeRuntimeSceneInstance(input, options);\n\n return {\n ...instance,\n nodes: instance.nodesById,\n physicsNodes: instance.physicsDescriptors\n };\n}\n\nexport async function loadWebHammerEngineSceneFromUrl(\n url: string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<WebHammerLoadedScene> {\n const scene = await fetchWebHammerEngineScene(url);\n return loadWebHammerEngineScene(scene, options);\n}\n\nexport async function loadThreeRuntimeSceneInstanceFromUrl(\n url: string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<ThreeRuntimeSceneInstance> {\n const scene = await fetchWebHammerEngineScene(url);\n return createThreeRuntimeSceneInstance(scene, options);\n}\n\ntype AppliedWorldSettingsState = {\n requestId: number;\n skyboxTexture?: Texture;\n};\n\nconst APPLIED_WORLD_SETTINGS_KEY = \"__webHammerWorldSettings\";\n\nexport async function applyWebHammerWorldSettings(\n target: Scene,\n engineScene: Pick<WebHammerEngineScene, \"settings\">,\n options: Pick<WebHammerSceneLoaderOptions, \"resolveAssetUrl\"> = {}\n) {\n const state = getAppliedWorldSettingsState(target);\n state.requestId += 1;\n disposeAppliedSkybox(target, state);\n\n const { fogColor, fogFar, fogNear } = engineScene.settings.world;\n target.fog = fogFar > fogNear ? new Fog(new Color(fogColor), fogNear, fogFar) : null;\n\n const skybox = engineScene.settings.world.skybox;\n\n if (!skybox.enabled || !skybox.source) {\n return;\n }\n\n const requestId = state.requestId;\n\n try {\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"skybox\",\n path: skybox.source,\n skybox\n })\n : skybox.source;\n const texture = await loadSkyboxTexture(resolvedPath, skybox);\n\n if (getAppliedWorldSettingsState(target).requestId !== requestId) {\n texture.dispose();\n return;\n }\n\n target.background = texture;\n target.backgroundBlurriness = skybox.blur;\n target.backgroundIntensity = skybox.intensity;\n target.environment = skybox.affectsLighting ? texture : null;\n target.environmentIntensity = skybox.affectsLighting ? skybox.lightingIntensity : 1;\n state.skyboxTexture = texture;\n } catch {\n if (getAppliedWorldSettingsState(target).requestId === requestId) {\n disposeAppliedSkybox(target, state);\n }\n }\n}\n\nexport function clearWebHammerWorldSettings(target: Scene) {\n const state = getAppliedWorldSettingsState(target);\n state.requestId += 1;\n disposeAppliedSkybox(target, state);\n target.fog = null;\n}\n\nexport const applyRuntimeWorldSettingsToThreeScene = applyWebHammerWorldSettings;\nexport const clearRuntimeWorldSettingsFromThreeScene = clearWebHammerWorldSettings;\n\nfunction createWorldAmbientLight(engineScene: WebHammerEngineScene) {\n const { ambientColor, ambientIntensity } = engineScene.settings.world;\n\n if (ambientIntensity <= 0) {\n return undefined;\n }\n\n const light = new AmbientLight(ambientColor, ambientIntensity);\n light.name = \"World Ambient\";\n light.userData.webHammer = {\n source: \"world-settings\"\n };\n\n return light;\n}\n\nfunction getAppliedWorldSettingsState(target: Scene): AppliedWorldSettingsState {\n const userData = target.userData as Record<string, AppliedWorldSettingsState | undefined>;\n const existing = userData[APPLIED_WORLD_SETTINGS_KEY];\n\n if (existing) {\n return existing;\n }\n\n const created: AppliedWorldSettingsState = {\n requestId: 0\n };\n userData[APPLIED_WORLD_SETTINGS_KEY] = created;\n return created;\n}\n\nfunction disposeAppliedSkybox(target: Scene, state: AppliedWorldSettingsState) {\n if (state.skyboxTexture) {\n if (target.background === state.skyboxTexture) {\n target.background = null;\n }\n\n if (target.environment === state.skyboxTexture) {\n target.environment = null;\n }\n\n state.skyboxTexture.dispose();\n state.skyboxTexture = undefined;\n }\n\n target.backgroundBlurriness = 0;\n target.backgroundIntensity = 1;\n target.environmentIntensity = 1;\n}\n\nfunction disposeThreeRuntimeSceneInstance(root: Group) {\n const geometries = new Set<BufferGeometry>();\n const materials = new Set<MeshStandardMaterial>();\n const textures = new Set<Texture>();\n\n root.traverse((object) => {\n if (!(object instanceof Mesh || object instanceof InstancedMesh)) {\n return;\n }\n\n if (object.geometry instanceof BufferGeometry) {\n geometries.add(object.geometry);\n }\n\n const objectMaterials = Array.isArray(object.material) ? object.material : [object.material];\n\n objectMaterials.forEach((material) => {\n if (!(material instanceof MeshStandardMaterial)) {\n return;\n }\n\n materials.add(material);\n\n if (material.map) {\n textures.add(material.map);\n }\n\n if (material.normalMap) {\n textures.add(material.normalMap);\n }\n\n if (material.metalnessMap) {\n textures.add(material.metalnessMap);\n }\n\n if (material.roughnessMap) {\n textures.add(material.roughnessMap);\n }\n });\n });\n\n root.removeFromParent();\n geometries.forEach((geometry) => {\n geometry.dispose();\n });\n materials.forEach((material) => {\n material.dispose();\n });\n textures.forEach((texture) => {\n texture.dispose();\n });\n}\n\nasync function loadSkyboxTexture(path: string, skybox: SceneSkyboxSettings) {\n const texture = skybox.format === \"hdr\"\n ? await hdrLoader.loadAsync(path)\n : await textureLoader.loadAsync(path);\n\n texture.mapping = EquirectangularReflectionMapping;\n\n if (skybox.format === \"image\") {\n texture.colorSpace = SRGBColorSpace;\n }\n\n return texture;\n}\n\nasync function createObjectForNode(\n node: WebHammerEngineNode,\n assetsById: Map<string, Asset>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const anchor = new Group();\n const content = new Group();\n const pivot = node.transform.pivot;\n\n anchor.name = node.name;\n applyTransform(anchor, node.transform);\n anchor.userData.webHammer = {\n data: node.data,\n hooks: node.hooks,\n id: node.id,\n kind: node.kind,\n metadata: node.metadata,\n tags: node.tags\n };\n\n if (pivot) {\n content.position.set(-pivot.x, -pivot.y, -pivot.z);\n }\n\n anchor.add(content);\n\n if (node.kind === \"light\") {\n const light = createThreeLight(node);\n\n if (light) {\n content.add(light);\n }\n\n return anchor;\n }\n\n if (node.kind === \"model\") {\n const modelObject = await createModelObject(node, assetsById.get(node.data.assetId), options);\n const lodObject = await createLodObjectForModelNode(node, modelObject, assetsById, options);\n content.add(lodObject ?? modelObject);\n return anchor;\n }\n\n if (node.kind === \"instancing\") {\n anchor.visible = false;\n return anchor;\n }\n\n if (node.kind === \"group\") {\n return anchor;\n }\n\n const lodObject = await createLodObjectForGeometryNode(node, materialCache, textureCache, options);\n\n if (lodObject) {\n content.add(lodObject);\n }\n\n return anchor;\n}\n\nasync function createInstancingObjects(\n engineScene: WebHammerEngineScene,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const batches = new Map<string, Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>>();\n\n engineScene.nodes.forEach((node) => {\n if (node.kind !== \"instancing\") {\n return;\n }\n\n const sourceNode = resolveInstancingSourceNode(engineScene.nodes, node.data.sourceNodeId);\n\n if (!sourceNode || !(sourceNode.kind === \"brush\" || sourceNode.kind === \"mesh\" || sourceNode.kind === \"primitive\")) {\n return;\n }\n\n const instances = batches.get(sourceNode.id);\n\n if (instances) {\n instances.push(node);\n return;\n }\n\n batches.set(sourceNode.id, [node]);\n });\n\n const objects: Object3D[] = [];\n\n for (const [sourceNodeId, instances] of batches) {\n const sourceNode = engineScene.nodes.find((node) => node.id === sourceNodeId);\n\n if (!sourceNode || !(sourceNode.kind === \"brush\" || sourceNode.kind === \"mesh\" || sourceNode.kind === \"primitive\")) {\n continue;\n }\n\n const object = await createInstancedObjectForGeometryNode(sourceNode, instances, sceneGraph, materialCache, textureCache, options);\n\n if (object) {\n objects.push(object);\n }\n }\n\n return objects;\n}\n\nasync function createInstancedObjectForGeometryNode(\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const baseGroup = await createInstancedGeometryObject(sourceNode.geometry, sourceNode, instances, sceneGraph, materialCache, textureCache, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !sourceNode.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${sourceNode.name}:InstancingLOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of sourceNode.lods) {\n const levelGroup = await createInstancedGeometryObject(\n level.geometry,\n sourceNode,\n instances,\n sceneGraph,\n materialCache,\n textureCache,\n options,\n level\n );\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n levelOrder: [\"high\", ...(sourceNode.lods ?? []).map((level) => level.level)],\n sourceNodeId: sourceNode.id\n };\n return lod;\n}\n\nasync function createInstancedGeometryObject(\n geometry: WebHammerExportGeometry,\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const pivot = sourceNode.transform.pivot ?? vec3(0, 0, 0);\n\n for (const primitive of geometry.primitives) {\n const primitiveGeometry = new BufferGeometry();\n primitiveGeometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n primitiveGeometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n primitiveGeometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n primitiveGeometry.setIndex(primitive.indices);\n primitiveGeometry.computeBoundingBox();\n primitiveGeometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, materialCache, textureCache, options);\n const mesh = new InstancedMesh(primitiveGeometry, material, instances.length);\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${sourceNode.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}:instanced`;\n mesh.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n sourceNodeId: sourceNode.id\n };\n\n instances.forEach((instance, index) => {\n const worldTransform = sceneGraph.nodeWorldTransforms.get(instance.id) ?? instance.transform;\n mesh.setMatrixAt(index, composeInstancedMatrix(worldTransform, pivot));\n });\n\n mesh.instanceMatrix.needsUpdate = true;\n group.add(mesh);\n }\n\n group.name = `${sourceNode.name}:instances`;\n group.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n sourceNodeId: sourceNode.id\n };\n return group;\n}\n\nasync function createLodObjectForGeometryNode(\n node: WebHammerEngineGeometryNode,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const baseGroup = await createGeometryObject(node.geometry, node, materialCache, textureCache, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of node.lods) {\n const levelGroup = await createGeometryObject(level.geometry, node, materialCache, textureCache, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createLodObjectForModelNode(\n node: WebHammerEngineModelNode,\n baseModel: Object3D,\n assetsById: Map<string, Asset>,\n options: WebHammerSceneLoaderOptions\n) {\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return undefined;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseModel, 0);\n\n for (const level of node.lods) {\n const levelModel = await createModelObject(node, assetsById.get(level.assetId), options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelModel, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createGeometryObject(\n geometry: WebHammerExportGeometry,\n node: Pick<WebHammerEngineNode, \"id\" | \"name\">,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const meshes: Mesh[] = [];\n\n for (const primitive of geometry.primitives) {\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n geometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n geometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n geometry.setIndex(primitive.indices);\n geometry.computeBoundingBox();\n geometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, materialCache, textureCache, options);\n const mesh = new Mesh(geometry, material);\n\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${node.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}`;\n mesh.userData.webHammer = {\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n nodeId: node.id\n };\n\n meshes.push(mesh);\n }\n\n meshes.forEach((mesh) => {\n group.add(mesh);\n });\n\n return group;\n}\n\nfunction resolveSceneLodOptions(lod?: WebHammerSceneLodOptions): WebHammerSceneLodOptions | undefined {\n if (!lod) {\n return undefined;\n }\n\n const midDistance = Math.max(0, lod.midDistance);\n const lowDistance = Math.max(midDistance + 0.01, lod.lowDistance);\n\n return {\n lowDistance,\n midDistance\n };\n}\n\nasync function createThreeMaterial(\n materialSpec: WebHammerExportMaterial,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const cached = materialCache.get(materialSpec.id);\n\n if (cached) {\n return cached;\n }\n\n const material = new MeshStandardMaterial({\n color: materialSpec.color,\n metalness: materialSpec.metallicFactor,\n roughness: materialSpec.roughnessFactor,\n side: resolveMaterialSide(materialSpec.side)\n });\n\n if (materialSpec.baseColorTexture) {\n const texture = await loadTexture(materialSpec.baseColorTexture, materialSpec, \"baseColorTexture\", textureCache, options);\n texture.colorSpace = SRGBColorSpace;\n material.map = texture;\n }\n\n if (materialSpec.normalTexture) {\n material.normalMap = await loadTexture(materialSpec.normalTexture, materialSpec, \"normalTexture\", textureCache, options);\n }\n\n if (materialSpec.metallicRoughnessTexture) {\n const ormTexture = await loadTexture(\n materialSpec.metallicRoughnessTexture,\n materialSpec,\n \"metallicRoughnessTexture\",\n textureCache,\n options\n );\n material.metalnessMap = ormTexture;\n material.roughnessMap = ormTexture;\n }\n\n material.name = materialSpec.name;\n material.needsUpdate = true;\n materialCache.set(materialSpec.id, material);\n\n return material;\n}\n\nasync function loadTexture(\n path: string,\n material: WebHammerExportMaterial,\n slot: TextureSlot,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material,\n path,\n slot\n })\n : path;\n const cacheKey = `${slot}:${resolvedPath}`;\n const cached = textureCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const pendingTexture = textureLoader.loadAsync(resolvedPath);\n const configuredTexture = pendingTexture.then((texture) => {\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n return texture;\n });\n textureCache.set(\n cacheKey,\n configuredTexture\n );\n return configuredTexture;\n}\n\nasync function createModelObject(\n node: Extract<WebHammerEngineNode, { kind: \"model\" }>,\n asset: Asset | undefined,\n options: WebHammerSceneLoaderOptions,\n lodLevel?: WebHammerExportModelLod\n) {\n const fallback = createMissingModelFallback(asset);\n const modelPath = asset?.path ?? node.data.path;\n\n if (!modelPath) {\n return fallback;\n }\n\n const format = resolveModelFormat(asset?.metadata.modelFormat, modelPath);\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n asset,\n format,\n kind: \"model\",\n node,\n path: modelPath\n })\n : modelPath;\n const texturePath = readAssetString(asset, \"texturePath\");\n const resolvedTexturePath =\n texturePath && options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material: {\n color: \"#ffffff\",\n id: `material:model-texture:${node.id}`,\n metallicFactor: 0,\n name: `${node.name} Model Texture`,\n roughnessFactor: 1\n },\n path: texturePath,\n slot: \"baseColorTexture\"\n })\n : texturePath;\n\n try {\n const object =\n format === \"obj\"\n ? await loadObjModel(asset, resolvedPath, resolvedTexturePath)\n : await loadGltfModel(asset, resolvedPath);\n\n object.name = `${node.name}:${lodLevel?.level ?? \"high\"}`;\n object.userData.webHammer = {\n ...(object.userData.webHammer ?? {}),\n lodLevel: lodLevel?.level ?? \"high\",\n nodeId: node.id\n };\n return object;\n } catch {\n fallback.name = `${node.name}:${lodLevel?.level ?? \"high\"}:fallback`;\n fallback.userData.webHammer = {\n ...(fallback.userData.webHammer ?? {}),\n lodLevel: lodLevel?.level ?? \"high\",\n nodeId: node.id\n };\n return fallback;\n }\n}\n\nasync function loadObjModel(asset: Asset | undefined, resolvedPath: string, resolvedTexturePath?: string) {\n const objLoader = new OBJLoader();\n const mtlText = readAssetString(asset, \"materialMtlText\");\n\n if (mtlText) {\n const materialCreator = mtlLoader.parse(patchMtlTextureReferences(mtlText, resolvedTexturePath), \"\");\n materialCreator.preload();\n objLoader.setMaterials(materialCreator);\n }\n\n const object = await objLoader.loadAsync(resolvedPath);\n\n if (!mtlText && resolvedTexturePath) {\n const texture = await textureLoader.loadAsync(resolvedTexturePath);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.colorSpace = SRGBColorSpace;\n\n object.traverse((child: Object3D) => {\n if (child instanceof Mesh) {\n child.material = new MeshStandardMaterial({\n map: texture,\n metalness: 0.12,\n roughness: 0.76\n });\n }\n });\n }\n\n centerObject(object, readAssetVec3(asset, \"nativeCenter\"));\n return object;\n}\n\nasync function loadGltfModel(asset: Asset | undefined, resolvedPath: string) {\n const gltf = await gltfLoader.loadAsync(resolvedPath);\n const object = gltf.scene;\n centerObject(object, readAssetVec3(asset, \"nativeCenter\"));\n object.userData.webHammer = {\n ...(object.userData.webHammer ?? {}),\n animations: gltf.animations\n };\n return object;\n}\n\nfunction centerObject(object: Object3D, center: Vec3 | undefined) {\n const resolvedCenter = center ?? computeObjectCenter(object);\n object.position.set(-resolvedCenter.x, -resolvedCenter.y, -resolvedCenter.z);\n}\n\nfunction computeObjectCenter(object: Object3D) {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n\n return {\n x: center.x,\n y: center.y,\n z: center.z\n };\n}\n\nfunction createMissingModelFallback(asset: Asset | undefined) {\n const previewColor = readAssetString(asset, \"previewColor\") ?? \"#7f8ea3\";\n const size = readAssetVec3(asset, \"nativeSize\") ?? { x: 1.4, y: 1.4, z: 1.4 };\n const geometry = new BoxGeometry(size.x, size.y, size.z);\n const material = new MeshStandardMaterial({\n color: previewColor,\n metalness: 0.08,\n roughness: 0.72\n });\n const mesh = new Mesh(geometry, material);\n\n mesh.name = \"Missing Model\";\n return mesh;\n}\n\nfunction createThreeLight(node: Extract<WebHammerEngineNode, { kind: \"light\" }>) {\n if (!node.data.enabled) {\n return undefined;\n }\n\n switch (node.data.type) {\n case \"ambient\": {\n return new AmbientLight(node.data.color, node.data.intensity);\n }\n case \"hemisphere\": {\n const light = new HemisphereLight(node.data.color, node.data.groundColor ?? \"#0f1721\", node.data.intensity);\n return light;\n }\n case \"point\": {\n const light = new PointLight(node.data.color, node.data.intensity, node.data.distance ?? 0, node.data.decay ?? 2);\n light.castShadow = node.data.castShadow;\n return light;\n }\n case \"directional\": {\n const group = new Group();\n const light = new DirectionalLight(node.data.color, node.data.intensity);\n const target = new Object3D();\n\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(light);\n group.add(target);\n light.target = target;\n return group;\n }\n case \"spot\": {\n const group = new Group();\n const light = new SpotLight(\n node.data.color,\n node.data.intensity,\n node.data.distance ?? 0,\n node.data.angle ?? Math.PI / 3,\n node.data.penumbra ?? 0,\n node.data.decay ?? 2\n );\n const target = new Object3D();\n\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(light);\n group.add(target);\n light.target = target;\n return group;\n }\n default:\n return undefined;\n }\n}\n\nfunction applyTransform(object: Object3D, transform: Transform) {\n object.position.set(transform.position.x, transform.position.y, transform.position.z);\n object.rotation.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\");\n object.scale.set(transform.scale.x, transform.scale.y, transform.scale.z);\n}\n\nfunction composeInstancedMatrix(transform: Transform, pivot: Vec3) {\n return new Matrix4()\n .compose(\n new Vector3(transform.position.x, transform.position.y, transform.position.z),\n new Quaternion().setFromEuler(new Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\")),\n new Vector3(transform.scale.x, transform.scale.y, transform.scale.z)\n )\n .multiply(new Matrix4().makeTranslation(-pivot.x, -pivot.y, -pivot.z));\n}\n\nfunction extractPhysics(node: WebHammerEngineNode) {\n if (node.kind === \"primitive\") {\n return node.data.physics;\n }\n\n if (node.kind === \"mesh\") {\n return node.data.physics;\n }\n\n return undefined;\n}\n\nfunction findPrimaryLight(object: Object3D) {\n let resolved: Object3D | undefined;\n\n object.traverse((child: Object3D) => {\n if (!resolved && \"isLight\" in child && child.isLight) {\n resolved = child;\n }\n });\n\n return resolved;\n}\n\nfunction resolveModelFormat(format: unknown, path: string): \"gltf\" | \"obj\" {\n if (typeof format === \"string\" && format.toLowerCase() === \"obj\") {\n return \"obj\";\n }\n\n return path.toLowerCase().endsWith(\".obj\") ? \"obj\" : \"gltf\";\n}\n\nfunction readAssetString(asset: Asset | undefined, key: string) {\n const value = asset?.metadata[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction readAssetVec3(asset: Asset | undefined, keyPrefix: \"nativeCenter\" | \"nativeSize\") {\n if (!asset) {\n return undefined;\n }\n\n const x = asset.metadata[`${keyPrefix}X`];\n const y = asset.metadata[`${keyPrefix}Y`];\n const z = asset.metadata[`${keyPrefix}Z`];\n\n if (typeof x !== \"number\" || typeof y !== \"number\" || typeof z !== \"number\") {\n return undefined;\n }\n\n return { x, y, z };\n}\n\nfunction resolveMaterialSide(side?: MaterialRenderSide) {\n switch (side) {\n case \"back\":\n return BackSide;\n case \"double\":\n return DoubleSide;\n default:\n return FrontSide;\n }\n}\n\nfunction patchMtlTextureReferences(mtlText: string, texturePath?: string) {\n if (!texturePath) {\n return mtlText;\n }\n\n const mapPattern = /^(map_Ka|map_Kd|map_d|map_Bump|bump)\\s+.+$/gm;\n const hasDiffuseMap = /^map_Kd\\s+.+$/m.test(mtlText);\n const normalized = mtlText.replace(mapPattern, (line) => {\n if (line.startsWith(\"map_Kd \")) {\n return `map_Kd ${texturePath}`;\n }\n\n return line;\n });\n\n return hasDiffuseMap ? normalized : `${normalized.trim()}\\nmap_Kd ${texturePath}\\n`;\n}\n","import type {\n Asset,\n BrushNode,\n Entity,\n GroupNode,\n InstancingNode,\n Layer,\n LightNode,\n MaterialRenderSide,\n MeshNode,\n ModelNode,\n PropPhysics,\n PrimitiveNode,\n SceneSettings\n} from \"@ggez/shared\";\n\nexport const RUNTIME_SCENE_FORMAT = \"web-hammer-engine\" as const;\nexport const CURRENT_RUNTIME_SCENE_VERSION = 6 as const;\nexport const MIN_RUNTIME_SCENE_VERSION = 4 as const;\nexport const CURRENT_RUNTIME_WORLD_INDEX_VERSION = 1 as const;\n\nexport type RuntimeMaterial = {\n baseColorTexture?: string;\n color: string;\n id: string;\n metallicFactor: number;\n metallicRoughnessTexture?: string;\n name: string;\n normalTexture?: string;\n roughnessFactor: number;\n side?: MaterialRenderSide;\n};\n\nexport type RuntimePrimitive = {\n indices: number[];\n material: RuntimeMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n};\n\nexport type RuntimeGeometry = {\n primitives: RuntimePrimitive[];\n};\n\nexport type RuntimeLodLevel = \"mid\" | \"low\";\n\nexport type RuntimeGeometryLod = {\n geometry: RuntimeGeometry;\n level: RuntimeLodLevel;\n};\n\nexport type RuntimeModelLod = {\n assetId: string;\n level: RuntimeLodLevel;\n};\n\nexport type RuntimeGeometryNode =\n | (BrushNode & { geometry: RuntimeGeometry; lods?: RuntimeGeometryLod[] })\n | (MeshNode & { geometry: RuntimeGeometry; lods?: RuntimeGeometryLod[] })\n | (PrimitiveNode & { geometry: RuntimeGeometry; lods?: RuntimeGeometryLod[] });\n\nexport type RuntimeModelNode = ModelNode & {\n lods?: RuntimeModelLod[];\n};\n\nexport type RuntimeInstancingNode = InstancingNode;\n\nexport type RuntimeNode = GroupNode | RuntimeGeometryNode | RuntimeModelNode | RuntimeInstancingNode | LightNode;\n\nexport type RuntimeSceneMetadata = {\n exportedAt: string;\n format: typeof RUNTIME_SCENE_FORMAT;\n version: number;\n};\n\nexport type RuntimeScene = {\n assets: Asset[];\n entities: Entity[];\n layers: Layer[];\n materials: RuntimeMaterial[];\n metadata: RuntimeSceneMetadata;\n nodes: RuntimeNode[];\n settings: SceneSettings;\n};\n\nexport type RuntimeBundleFile = {\n bytes: Uint8Array;\n mimeType: string;\n path: string;\n};\n\nexport type RuntimeBundle = {\n files: RuntimeBundleFile[];\n manifest: RuntimeScene;\n};\n\nexport type RuntimePhysicsDescriptor = {\n node: RuntimeNode;\n nodeId: string;\n physics: PropPhysics;\n};\n\nexport type RuntimeWorldChunk = {\n bounds: [number, number, number, number, number, number];\n bundleUrl?: string;\n id: string;\n loadDistance?: number;\n manifestUrl?: string;\n tags?: string[];\n unloadDistance?: number;\n};\n\nexport type RuntimeSharedAssetPack = {\n baseUrl: string;\n id: string;\n};\n\nexport type RuntimeWorldIndex = {\n chunks: RuntimeWorldChunk[];\n sharedAssets?: RuntimeSharedAssetPack[];\n version: number;\n};\n\nexport type WebHammerExportMaterial = RuntimeMaterial;\nexport type WebHammerExportPrimitive = RuntimePrimitive;\nexport type WebHammerExportGeometry = RuntimeGeometry;\nexport type WebHammerLodLevel = RuntimeLodLevel;\nexport type WebHammerExportGeometryLod = RuntimeGeometryLod;\nexport type WebHammerExportModelLod = RuntimeModelLod;\nexport type WebHammerEngineGeometryNode = RuntimeGeometryNode;\nexport type WebHammerEngineModelNode = RuntimeModelNode;\nexport type WebHammerEngineInstancingNode = RuntimeInstancingNode;\nexport type WebHammerEngineNode = RuntimeNode;\nexport type WebHammerEngineSceneMetadata = RuntimeSceneMetadata;\nexport type WebHammerEngineScene = RuntimeScene;\nexport type WebHammerEngineBundleFile = RuntimeBundleFile;\nexport type WebHammerEngineBundle = RuntimeBundle;\nexport type WebHammerRuntimePhysicsDescriptor = RuntimePhysicsDescriptor;\n","import {\n CURRENT_RUNTIME_SCENE_VERSION,\n CURRENT_RUNTIME_WORLD_INDEX_VERSION,\n MIN_RUNTIME_SCENE_VERSION,\n RUNTIME_SCENE_FORMAT,\n type RuntimeBundle,\n type RuntimeScene,\n type RuntimeWorldIndex,\n type WebHammerEngineBundle,\n type WebHammerEngineScene\n} from \"./types\";\n\nexport type RuntimeValidationResult<T> =\n | {\n errors: [];\n ok: true;\n value: T;\n }\n | {\n errors: string[];\n ok: false;\n };\n\nexport function isRuntimeScene(value: unknown): value is RuntimeScene {\n return validateRuntimeScene(value).ok;\n}\n\nexport function validateRuntimeScene(value: unknown): RuntimeValidationResult<RuntimeScene> {\n const errors: string[] = [];\n\n if (!value || typeof value !== \"object\") {\n return invalid(\"Runtime scene must be an object.\");\n }\n\n const candidate = value as Partial<RuntimeScene>;\n\n if (candidate.metadata?.format !== RUNTIME_SCENE_FORMAT) {\n errors.push(`Runtime scene metadata.format must be \"${RUNTIME_SCENE_FORMAT}\".`);\n }\n\n if (typeof candidate.metadata?.version !== \"number\") {\n errors.push(\"Runtime scene metadata.version must be a number.\");\n } else if (candidate.metadata.version < MIN_RUNTIME_SCENE_VERSION) {\n errors.push(`Runtime scene metadata.version must be >= ${MIN_RUNTIME_SCENE_VERSION}.`);\n }\n\n if (!Array.isArray(candidate.nodes)) {\n errors.push(\"Runtime scene nodes must be an array.\");\n }\n\n if (!Array.isArray(candidate.assets)) {\n errors.push(\"Runtime scene assets must be an array.\");\n }\n\n if (!Array.isArray(candidate.materials)) {\n errors.push(\"Runtime scene materials must be an array.\");\n }\n\n if (!Array.isArray(candidate.entities)) {\n errors.push(\"Runtime scene entities must be an array.\");\n }\n\n if (!Array.isArray(candidate.layers)) {\n errors.push(\"Runtime scene layers must be an array.\");\n }\n\n if (!candidate.settings || typeof candidate.settings !== \"object\") {\n errors.push(\"Runtime scene settings must be an object.\");\n }\n\n if (errors.length > 0) {\n return {\n errors,\n ok: false\n };\n }\n\n return {\n errors: [],\n ok: true,\n value: candidate as RuntimeScene\n };\n}\n\nexport function migrateRuntimeScene(scene: RuntimeScene): RuntimeScene {\n const migrated = structuredClone(scene);\n\n migrated.metadata = {\n ...migrated.metadata,\n format: RUNTIME_SCENE_FORMAT,\n version: CURRENT_RUNTIME_SCENE_VERSION\n };\n\n return migrated;\n}\n\nexport function parseRuntimeScene(text: string): RuntimeScene {\n const parsed = JSON.parse(text) as unknown;\n const validation = validateRuntimeScene(parsed);\n\n if (!validation.ok) {\n throw new Error(validation.errors.join(\" \"));\n }\n\n return migrateRuntimeScene(validation.value);\n}\n\nexport function isRuntimeBundle(value: unknown): value is RuntimeBundle {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<RuntimeBundle>;\n return Array.isArray(candidate.files) && isRuntimeScene(candidate.manifest);\n}\n\nexport function validateRuntimeBundle(value: unknown): RuntimeValidationResult<RuntimeBundle> {\n if (!value || typeof value !== \"object\") {\n return invalid(\"Runtime bundle must be an object.\");\n }\n\n const candidate = value as Partial<RuntimeBundle>;\n const errors: string[] = [];\n\n if (!Array.isArray(candidate.files)) {\n errors.push(\"Runtime bundle files must be an array.\");\n }\n\n const sceneValidation = validateRuntimeScene(candidate.manifest);\n\n if (!sceneValidation.ok) {\n errors.push(...sceneValidation.errors);\n }\n\n if (errors.length > 0) {\n return {\n errors,\n ok: false\n };\n }\n\n const manifest = migrateRuntimeScene((sceneValidation as Extract<typeof sceneValidation, { ok: true }>).value);\n\n return {\n errors: [],\n ok: true,\n value: {\n files: candidate.files!,\n manifest\n }\n };\n}\n\nexport function isRuntimeWorldIndex(value: unknown): value is RuntimeWorldIndex {\n return validateRuntimeWorldIndex(value).ok;\n}\n\nexport function validateRuntimeWorldIndex(value: unknown): RuntimeValidationResult<RuntimeWorldIndex> {\n if (!value || typeof value !== \"object\") {\n return invalid(\"Runtime world index must be an object.\");\n }\n\n const candidate = value as Partial<RuntimeWorldIndex>;\n const errors: string[] = [];\n\n if (typeof candidate.version !== \"number\") {\n errors.push(\"Runtime world index version must be a number.\");\n } else if (candidate.version > CURRENT_RUNTIME_WORLD_INDEX_VERSION) {\n errors.push(\n `Runtime world index version ${candidate.version} is newer than supported version ${CURRENT_RUNTIME_WORLD_INDEX_VERSION}.`\n );\n }\n\n if (!Array.isArray(candidate.chunks)) {\n errors.push(\"Runtime world index chunks must be an array.\");\n }\n\n if (errors.length > 0) {\n return {\n errors,\n ok: false\n };\n }\n\n return {\n errors: [],\n ok: true,\n value: candidate as RuntimeWorldIndex\n };\n}\n\nexport function parseRuntimeWorldIndex(text: string): RuntimeWorldIndex {\n const parsed = JSON.parse(text) as unknown;\n const validation = validateRuntimeWorldIndex(parsed);\n\n if (!validation.ok) {\n throw new Error(validation.errors.join(\" \"));\n }\n\n return validation.value;\n}\n\nexport function parseWebHammerEngineScene(text: string): WebHammerEngineScene {\n return parseRuntimeScene(text);\n}\n\nexport function isWebHammerEngineScene(value: unknown): value is WebHammerEngineScene {\n return isRuntimeScene(value);\n}\n\nexport function isWebHammerEngineBundle(value: unknown): value is WebHammerEngineBundle {\n return isRuntimeBundle(value);\n}\n\nfunction invalid(message: string): RuntimeValidationResult<never> {\n return {\n errors: [message],\n ok: false\n };\n}\n","import type { Asset, PropPhysics, Transform, Vec3 } from \"@ggez/shared\";\nimport { resolveInstancingSourceNode, resolveSceneGraph, vec3 } from \"@ggez/shared\";\nimport {\n AmbientLight,\n BackSide,\n Box3,\n BoxGeometry,\n BufferGeometry,\n DirectionalLight,\n DoubleSide,\n Euler,\n Float32BufferAttribute,\n FrontSide,\n Group,\n HemisphereLight,\n InstancedMesh,\n LOD,\n Matrix4,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n PointLight,\n Quaternion,\n RepeatWrapping,\n SRGBColorSpace,\n SpotLight,\n Texture,\n TextureLoader,\n Vector3\n} from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport { MTLLoader } from \"three/examples/jsm/loaders/MTLLoader.js\";\nimport { OBJLoader } from \"three/examples/jsm/loaders/OBJLoader.js\";\nimport type {\n WebHammerEngineGeometryNode,\n WebHammerEngineModelNode,\n WebHammerEngineNode,\n WebHammerEngineScene,\n WebHammerExportGeometry,\n WebHammerExportGeometryLod,\n WebHammerExportMaterial,\n WebHammerExportModelLod\n} from \"./types\";\nimport type { WebHammerSceneLoaderOptions, WebHammerSceneLodOptions } from \"./loader\";\n\ntype TextureSlot = \"baseColorTexture\" | \"metallicRoughnessTexture\" | \"normalTexture\";\n\ntype WebHammerSceneObjectFactoryOptions = Pick<\n WebHammerSceneLoaderOptions,\n \"castShadow\" | \"lod\" | \"receiveShadow\" | \"resolveAssetUrl\"\n>;\n\ntype CreateNodeObjectOverrides = {\n transform?: Transform;\n};\n\ntype ModelReference = {\n asset?: Asset;\n assetId?: string;\n center?: Vec3;\n fallbackName: string;\n format: \"gltf\" | \"obj\";\n modelPath?: string;\n nodeId: string;\n nodeName: string;\n texturePath?: string;\n};\n\ntype WebHammerSceneObjectFactoryResources = {\n assetsById: Map<string, Asset>;\n materialCache: Map<string, MeshStandardMaterial>;\n modelTemplateCache: Map<string, Promise<Object3D>>;\n textureCache: Map<string, Promise<Texture>>;\n};\n\nconst textureLoader = new TextureLoader();\nconst gltfLoader = new GLTFLoader();\nconst mtlLoader = new MTLLoader();\nconst modelTextureLoader = new TextureLoader();\nconst tempModelInstanceMatrix = new Matrix4();\nconst tempModelChildMatrix = new Matrix4();\nconst tempPivotMatrix = new Matrix4();\nconst tempInstancePosition = new Vector3();\nconst tempInstanceQuaternion = new Quaternion();\nconst tempInstanceScale = new Vector3();\n\nexport type WebHammerSceneObjectFactory = {\n createInstancingObjects: () => Promise<Object3D[]>;\n createNodeObject: (node: WebHammerEngineNode, overrides?: CreateNodeObjectOverrides) => Promise<Object3D>;\n};\n\nexport function createWebHammerSceneObjectFactory(\n engineScene: Pick<WebHammerEngineScene, \"assets\" | \"nodes\">,\n options: WebHammerSceneObjectFactoryOptions = {}\n): WebHammerSceneObjectFactory {\n const resources: WebHammerSceneObjectFactoryResources = {\n assetsById: new Map(engineScene.assets.map((asset) => [asset.id, asset])),\n materialCache: new Map(),\n modelTemplateCache: new Map(),\n textureCache: new Map()\n };\n\n return {\n createInstancingObjects: () => createInstancingObjects(engineScene, resources, options),\n createNodeObject: (node, overrides) => createObjectForNode(node, resources, options, overrides)\n };\n}\n\nexport const createThreeRuntimeObjectFactory = createWebHammerSceneObjectFactory;\n\nasync function createObjectForNode(\n node: WebHammerEngineNode,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n overrides?: CreateNodeObjectOverrides\n) {\n const anchor = new Group();\n const content = new Group();\n const transform = overrides?.transform ?? node.transform;\n const pivot = transform.pivot;\n\n anchor.name = node.name;\n applyTransform(anchor, transform);\n anchor.userData.webHammer = {\n data: node.data,\n hooks: node.hooks,\n id: node.id,\n kind: node.kind,\n metadata: node.metadata,\n tags: node.tags\n };\n\n if (pivot) {\n content.position.set(-pivot.x, -pivot.y, -pivot.z);\n }\n\n anchor.add(content);\n\n if (node.kind === \"light\") {\n const light = createThreeLight(node);\n\n if (light) {\n content.add(light);\n }\n\n return anchor;\n }\n\n if (node.kind === \"group\") {\n return anchor;\n }\n\n if (node.kind === \"instancing\") {\n anchor.visible = false;\n return anchor;\n }\n\n if (node.kind === \"model\") {\n const modelObject = await createModelObject(node, resources, options);\n const lodObject = await createLodObjectForModelNode(node, modelObject, resources, options);\n content.add(lodObject ?? modelObject);\n return anchor;\n }\n\n const lodObject = await createLodObjectForGeometryNode(node, resources, options);\n\n if (lodObject) {\n content.add(lodObject);\n }\n\n return anchor;\n}\n\nasync function createInstancingObjects(\n engineScene: Pick<WebHammerEngineScene, \"assets\" | \"nodes\">,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const sceneGraph = resolveSceneGraph(engineScene.nodes);\n const batches = new Map<string, Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>>();\n\n engineScene.nodes.forEach((node) => {\n if (node.kind !== \"instancing\") {\n return;\n }\n\n const sourceNode = resolveInstancingSourceNode(engineScene.nodes, node.data.sourceNodeId);\n\n if (!sourceNode) {\n return;\n }\n\n const instances = batches.get(sourceNode.id);\n\n if (instances) {\n instances.push(node);\n return;\n }\n\n batches.set(sourceNode.id, [node]);\n });\n\n const objects: Object3D[] = [];\n\n for (const [sourceNodeId, instances] of batches) {\n const sourceNode = resolveInstancingSourceNode(engineScene.nodes, sourceNodeId);\n\n if (!sourceNode) {\n continue;\n }\n\n const exportedSourceNode = engineScene.nodes.find((node) => node.id === sourceNode.id);\n\n if (!exportedSourceNode || exportedSourceNode.kind === \"group\" || exportedSourceNode.kind === \"instancing\" || exportedSourceNode.kind === \"light\") {\n continue;\n }\n\n const object =\n exportedSourceNode.kind === \"model\"\n ? await createInstancedObjectForModelNode(exportedSourceNode, instances, sceneGraph, resources, options)\n : await createInstancedObjectForGeometryNode(exportedSourceNode, instances, sceneGraph, resources, options);\n\n if (object) {\n objects.push(object);\n }\n }\n\n return objects;\n}\n\nasync function createInstancedObjectForGeometryNode(\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const baseGroup = await createInstancedGeometryObject(sourceNode.geometry, sourceNode, instances, sceneGraph, resources, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !sourceNode.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${sourceNode.name}:InstancingLOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of sourceNode.lods) {\n const levelGroup = await createInstancedGeometryObject(\n level.geometry,\n sourceNode,\n instances,\n sceneGraph,\n resources,\n options,\n level\n );\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n levelOrder: [\"high\", ...(sourceNode.lods ?? []).map((level) => level.level)],\n sourceNodeId: sourceNode.id\n };\n return lod;\n}\n\nasync function createInstancedGeometryObject(\n geometry: WebHammerExportGeometry,\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const pivot = sourceNode.transform.pivot ?? vec3(0, 0, 0);\n\n for (const primitive of geometry.primitives) {\n const primitiveGeometry = new BufferGeometry();\n primitiveGeometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n primitiveGeometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n primitiveGeometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n primitiveGeometry.setIndex(primitive.indices);\n primitiveGeometry.computeBoundingBox();\n primitiveGeometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, resources, options);\n const mesh = new InstancedMesh(primitiveGeometry, material, instances.length);\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${sourceNode.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}:instanced`;\n mesh.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n sourceNodeId: sourceNode.id\n };\n\n instances.forEach((instance, index) => {\n const worldTransform = sceneGraph.nodeWorldTransforms.get(instance.id) ?? instance.transform;\n mesh.setMatrixAt(index, composeGeometryInstanceMatrix(worldTransform, pivot));\n });\n\n mesh.instanceMatrix.needsUpdate = true;\n group.add(mesh);\n }\n\n group.name = `${sourceNode.name}:instances`;\n group.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n sourceNodeId: sourceNode.id\n };\n return group;\n}\n\nasync function createInstancedObjectForModelNode(\n sourceNode: WebHammerEngineModelNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const baseGroup = await createInstancedModelObject(sourceNode, instances, sceneGraph, resources, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !sourceNode.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${sourceNode.name}:InstancingLOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of sourceNode.lods) {\n const levelGroup = await createInstancedModelObject(sourceNode, instances, sceneGraph, resources, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n levelOrder: [\"high\", ...(sourceNode.lods ?? []).map((level) => level.level)],\n sourceNodeId: sourceNode.id\n };\n return lod;\n}\n\nasync function createInstancedModelObject(\n sourceNode: WebHammerEngineModelNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportModelLod\n) {\n const group = new Group();\n const template = await loadModelTemplate(resolveModelReference(sourceNode, resources.assetsById, lodLevel), options, resources);\n const templateInstanceNodeIds = instances.map((instance) => instance.id);\n let modelMeshIndex = 0;\n\n template.updateMatrixWorld(true);\n\n template.traverse((child) => {\n if (!(child instanceof Mesh) || !(child.geometry instanceof BufferGeometry)) {\n return;\n }\n\n const instancedMesh = new InstancedMesh(child.geometry, child.material, instances.length);\n instancedMesh.castShadow = options.castShadow ?? true;\n instancedMesh.receiveShadow = options.receiveShadow ?? true;\n instancedMesh.name = `${sourceNode.name}:${lodLevel?.level ?? \"high\"}:${child.name || modelMeshIndex}:instanced`;\n instancedMesh.userData.webHammer = {\n instanceNodeIds: templateInstanceNodeIds,\n lodLevel: lodLevel?.level ?? \"high\",\n modelMeshIndex,\n sourceNodeId: sourceNode.id\n };\n\n tempModelChildMatrix.copy(child.matrixWorld);\n\n instances.forEach((instance, index) => {\n const worldTransform = sceneGraph.nodeWorldTransforms.get(instance.id) ?? instance.transform;\n tempModelInstanceMatrix.copy(composeTransformMatrix(worldTransform)).multiply(tempModelChildMatrix);\n instancedMesh.setMatrixAt(index, tempModelInstanceMatrix);\n });\n\n instancedMesh.instanceMatrix.needsUpdate = true;\n group.add(instancedMesh);\n modelMeshIndex += 1;\n });\n\n group.name = `${sourceNode.name}:instances`;\n group.userData.webHammer = {\n instanceNodeIds: templateInstanceNodeIds,\n sourceNodeId: sourceNode.id\n };\n return group;\n}\n\nasync function createLodObjectForGeometryNode(\n node: WebHammerEngineGeometryNode,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const baseGroup = await createGeometryObject(node.geometry, node, resources, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of node.lods) {\n const levelGroup = await createGeometryObject(level.geometry, node, resources, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createLodObjectForModelNode(\n node: WebHammerEngineModelNode,\n baseModel: Object3D,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return undefined;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseModel, 0);\n\n for (const level of node.lods) {\n const levelModel = await createModelObject(node, resources, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelModel, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createGeometryObject(\n geometry: WebHammerExportGeometry,\n node: Pick<WebHammerEngineNode, \"id\" | \"name\">,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const meshes: Mesh[] = [];\n\n for (const primitive of geometry.primitives) {\n const primitiveGeometry = new BufferGeometry();\n primitiveGeometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n primitiveGeometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n primitiveGeometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n primitiveGeometry.setIndex(primitive.indices);\n primitiveGeometry.computeBoundingBox();\n primitiveGeometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, resources, options);\n const mesh = new Mesh(primitiveGeometry, material);\n\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${node.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}`;\n mesh.userData.webHammer = {\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n nodeId: node.id\n };\n\n meshes.push(mesh);\n }\n\n meshes.forEach((mesh) => {\n group.add(mesh);\n });\n\n return group;\n}\n\nasync function createThreeMaterial(\n materialSpec: WebHammerExportMaterial,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const cached = resources.materialCache.get(materialSpec.id);\n\n if (cached) {\n return cached;\n }\n\n const material = new MeshStandardMaterial({\n color: materialSpec.color,\n metalness: materialSpec.metallicFactor,\n roughness: materialSpec.roughnessFactor,\n side: resolveMaterialSide(materialSpec.side)\n });\n\n if (materialSpec.baseColorTexture) {\n const texture = await loadTexture(materialSpec.baseColorTexture, materialSpec, \"baseColorTexture\", resources, options);\n texture.colorSpace = SRGBColorSpace;\n material.map = texture;\n }\n\n if (materialSpec.normalTexture) {\n material.normalMap = await loadTexture(materialSpec.normalTexture, materialSpec, \"normalTexture\", resources, options);\n }\n\n if (materialSpec.metallicRoughnessTexture) {\n const ormTexture = await loadTexture(\n materialSpec.metallicRoughnessTexture,\n materialSpec,\n \"metallicRoughnessTexture\",\n resources,\n options\n );\n material.metalnessMap = ormTexture;\n material.roughnessMap = ormTexture;\n }\n\n material.name = materialSpec.name;\n material.needsUpdate = true;\n resources.materialCache.set(materialSpec.id, material);\n\n return material;\n}\n\nasync function loadTexture(\n path: string,\n material: WebHammerExportMaterial,\n slot: TextureSlot,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material,\n path,\n slot\n })\n : path;\n const cacheKey = `${slot}:${resolvedPath}`;\n const cached = resources.textureCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const pendingTexture = textureLoader.loadAsync(resolvedPath);\n const configuredTexture = pendingTexture.then((texture) => {\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n return texture;\n });\n resources.textureCache.set(cacheKey, configuredTexture);\n return configuredTexture;\n}\n\nasync function createModelObject(\n node: WebHammerEngineModelNode,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportModelLod\n) {\n const template = await loadModelTemplate(resolveModelReference(node, resources.assetsById, lodLevel), options, resources);\n const clone = template.clone(true);\n\n clone.name = `${node.name}:${lodLevel?.level ?? \"high\"}`;\n clone.userData.webHammer = {\n ...(clone.userData.webHammer ?? {}),\n lodLevel: lodLevel?.level ?? \"high\",\n nodeId: node.id\n };\n clone.traverse((child) => {\n if (child instanceof Mesh) {\n child.castShadow = options.castShadow ?? true;\n child.receiveShadow = options.receiveShadow ?? true;\n }\n });\n\n return clone;\n}\n\nfunction resolveModelReference(\n node: WebHammerEngineModelNode,\n assetsById: Map<string, Asset>,\n lodLevel?: WebHammerExportModelLod\n): ModelReference {\n const asset = lodLevel ? assetsById.get(lodLevel.assetId) : assetsById.get(node.data.assetId);\n const modelPath = asset?.path ?? node.data.path;\n\n return {\n asset,\n assetId: asset?.id ?? (lodLevel ? lodLevel.assetId : node.data.assetId),\n center: readAssetVec3(asset, \"nativeCenter\"),\n fallbackName: `${node.name}:${lodLevel?.level ?? \"high\"}:fallback`,\n format: resolveModelFormat(asset?.metadata.modelFormat, modelPath),\n modelPath,\n nodeId: node.id,\n nodeName: node.name,\n texturePath: readAssetString(asset, \"texturePath\")\n };\n}\n\nasync function loadModelTemplate(\n reference: ModelReference,\n options: WebHammerSceneObjectFactoryOptions,\n resources: WebHammerSceneObjectFactoryResources\n) {\n if (!reference.modelPath) {\n return createMissingModelFallback(reference.asset, reference.fallbackName);\n }\n\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n asset: reference.asset,\n format: reference.format,\n kind: \"model\",\n node: {\n data: {\n assetId: reference.assetId ?? \"\",\n path: reference.modelPath\n },\n id: reference.nodeId,\n kind: \"model\",\n name: reference.nodeName,\n transform: {\n position: vec3(0, 0, 0),\n rotation: vec3(0, 0, 0),\n scale: vec3(1, 1, 1)\n }\n },\n path: reference.modelPath\n })\n : reference.modelPath;\n const resolvedTexturePath =\n reference.texturePath && options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material: {\n color: \"#ffffff\",\n id: `material:model-texture:${reference.nodeId}`,\n metallicFactor: 0,\n name: `${reference.nodeName} Model Texture`,\n roughnessFactor: 1\n },\n path: reference.texturePath,\n slot: \"baseColorTexture\"\n })\n : reference.texturePath;\n const cacheKey = `${reference.format}:${resolvedPath}:${resolvedTexturePath ?? \"\"}:${readAssetString(reference.asset, \"materialMtlText\") ?? \"\"}`;\n const cached = resources.modelTemplateCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const pending = (async () => {\n try {\n const object =\n reference.format === \"obj\"\n ? await loadObjModel(reference.asset, resolvedPath, resolvedTexturePath)\n : await loadGltfModel(reference.asset, resolvedPath);\n centerObject(object, reference.center);\n return object;\n } catch {\n return createMissingModelFallback(reference.asset, reference.fallbackName);\n }\n })();\n\n resources.modelTemplateCache.set(cacheKey, pending);\n return pending;\n}\n\nasync function loadObjModel(asset: Asset | undefined, resolvedPath: string, resolvedTexturePath?: string) {\n const objLoader = new OBJLoader();\n const mtlText = readAssetString(asset, \"materialMtlText\");\n\n if (mtlText) {\n const materialCreator = mtlLoader.parse(patchMtlTextureReferences(mtlText, resolvedTexturePath), \"\");\n materialCreator.preload();\n objLoader.setMaterials(materialCreator);\n }\n\n const object = await objLoader.loadAsync(resolvedPath);\n\n if (!mtlText && resolvedTexturePath) {\n const texture = await loadModelTexture(resolvedTexturePath);\n\n object.traverse((child: Object3D) => {\n if (child instanceof Mesh) {\n child.material = new MeshStandardMaterial({\n map: texture,\n metalness: 0.12,\n roughness: 0.76\n });\n }\n });\n }\n\n return object;\n}\n\nasync function loadGltfModel(asset: Asset | undefined, resolvedPath: string) {\n const gltf = await gltfLoader.loadAsync(resolvedPath);\n const object = gltf.scene;\n object.userData.webHammer = {\n ...(object.userData.webHammer ?? {}),\n animations: gltf.animations,\n nativeCenter: readAssetVec3(asset, \"nativeCenter\")\n };\n return object;\n}\n\nasync function loadModelTexture(path: string) {\n const texture = await modelTextureLoader.loadAsync(path);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\nfunction centerObject(object: Object3D, center: Vec3 | undefined) {\n const resolvedCenter = center ?? computeObjectCenter(object);\n object.position.set(-resolvedCenter.x, -resolvedCenter.y, -resolvedCenter.z);\n}\n\nfunction computeObjectCenter(object: Object3D) {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n\n return {\n x: center.x,\n y: center.y,\n z: center.z\n };\n}\n\nfunction createMissingModelFallback(asset: Asset | undefined, name = \"Missing Model\") {\n const previewColor = readAssetString(asset, \"previewColor\") ?? \"#7f8ea3\";\n const size = readAssetVec3(asset, \"nativeSize\") ?? { x: 1.4, y: 1.4, z: 1.4 };\n const geometry = new BoxGeometry(size.x, size.y, size.z);\n const material = new MeshStandardMaterial({\n color: previewColor,\n metalness: 0.08,\n roughness: 0.72\n });\n const mesh = new Mesh(geometry, material);\n\n mesh.name = name;\n return mesh;\n}\n\nfunction createThreeLight(node: Extract<WebHammerEngineNode, { kind: \"light\" }>) {\n if (!node.data.enabled) {\n return undefined;\n }\n\n switch (node.data.type) {\n case \"ambient\": {\n return new AmbientLight(node.data.color, node.data.intensity);\n }\n case \"hemisphere\": {\n return new HemisphereLight(node.data.color, node.data.groundColor ?? \"#0f1721\", node.data.intensity);\n }\n case \"point\": {\n const light = new PointLight(node.data.color, node.data.intensity, node.data.distance ?? 0, node.data.decay ?? 2);\n light.castShadow = node.data.castShadow;\n return light;\n }\n case \"directional\": {\n const group = new Group();\n const light = new DirectionalLight(node.data.color, node.data.intensity);\n const target = new Object3D();\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(target);\n group.add(light);\n light.target = target;\n return group;\n }\n case \"spot\": {\n const group = new Group();\n const light = new SpotLight(\n node.data.color,\n node.data.intensity,\n node.data.distance,\n node.data.angle,\n node.data.penumbra,\n node.data.decay\n );\n const target = new Object3D();\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(target);\n group.add(light);\n light.target = target;\n return group;\n }\n default:\n return undefined;\n }\n}\n\nfunction applyTransform(object: Object3D, transform: Transform) {\n object.position.set(transform.position.x, transform.position.y, transform.position.z);\n object.rotation.set(transform.rotation.x, transform.rotation.y, transform.rotation.z);\n object.scale.set(transform.scale.x, transform.scale.y, transform.scale.z);\n}\n\nfunction composeGeometryInstanceMatrix(transform: Transform, pivot: Vec3) {\n return composeTransformMatrix(transform).multiply(\n tempPivotMatrix.makeTranslation(-pivot.x, -pivot.y, -pivot.z)\n );\n}\n\nfunction composeTransformMatrix(transform: Transform) {\n tempInstancePosition.set(transform.position.x, transform.position.y, transform.position.z);\n tempInstanceQuaternion.setFromEuler(new Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\"));\n tempInstanceScale.set(transform.scale.x, transform.scale.y, transform.scale.z);\n\n return new Matrix4().compose(tempInstancePosition, tempInstanceQuaternion, tempInstanceScale);\n}\n\nfunction resolveSceneLodOptions(lod?: WebHammerSceneLodOptions): WebHammerSceneLodOptions | undefined {\n if (!lod) {\n return undefined;\n }\n\n const midDistance = Math.max(0, lod.midDistance);\n const lowDistance = Math.max(midDistance + 0.01, lod.lowDistance);\n\n return {\n lowDistance,\n midDistance\n };\n}\n\nfunction resolveMaterialSide(side?: WebHammerExportMaterial[\"side\"]) {\n switch (side) {\n case \"back\":\n return BackSide;\n case \"double\":\n return DoubleSide;\n default:\n return FrontSide;\n }\n}\n\nfunction resolveModelFormat(format: unknown, path?: string): \"gltf\" | \"obj\" {\n if (typeof format === \"string\" && format.toLowerCase() === \"obj\") {\n return \"obj\";\n }\n\n return path?.toLowerCase().endsWith(\".obj\") ? \"obj\" : \"gltf\";\n}\n\nfunction readAssetString(asset: Asset | undefined, key: string) {\n const value = asset?.metadata[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction readAssetVec3(asset: Asset | undefined, keyPrefix: \"nativeCenter\" | \"nativeSize\") {\n const x = asset?.metadata[`${keyPrefix}X`];\n const y = asset?.metadata[`${keyPrefix}Y`];\n const z = asset?.metadata[`${keyPrefix}Z`];\n\n if (typeof x !== \"number\" || typeof y !== \"number\" || typeof z !== \"number\") {\n return undefined;\n }\n\n return { x, y, z };\n}\n\nfunction patchMtlTextureReferences(mtlText: string, texturePath?: string) {\n if (!texturePath) {\n return mtlText;\n }\n\n const mapPattern = /^(map_Ka|map_Kd|map_d|map_Bump|bump)\\s+.+$/gm;\n const hasDiffuseMap = /^map_Kd\\s+.+$/m.test(mtlText);\n const normalized = mtlText.replace(mapPattern, (line) => {\n if (line.startsWith(\"map_Kd \")) {\n return `map_Kd ${texturePath}`;\n }\n\n return line;\n });\n\n return hasDiffuseMap\n ? normalized\n : `${normalized.trim()}\\nmap_Kd ${texturePath}\\n`;\n}\n\nexport function extractPhysics(node: WebHammerEngineNode): PropPhysics | undefined {\n if (node.kind === \"primitive\") {\n return node.data.physics;\n }\n\n if (node.kind === \"mesh\") {\n return node.data.physics;\n }\n\n return undefined;\n}\n\nexport function findPrimaryLight(object: Object3D) {\n if (\"isLight\" in object && object.isLight) {\n return object;\n }\n\n return object.children.find((child) => \"isLight\" in child && child.isLight);\n}\n","import { unzipSync, zipSync } from \"fflate\";\nimport {\n parseRuntimeScene,\n type RuntimeBundle,\n type RuntimeBundleFile,\n type RuntimeScene,\n type RuntimeWorldChunk,\n type RuntimeWorldIndex,\n type WebHammerEngineBundle,\n type WebHammerEngineScene\n} from \"@ggez/runtime-format\";\n\nconst TEXTURE_FIELDS = [\"baseColorTexture\", \"metallicRoughnessTexture\", \"normalTexture\"] as const;\n\ntype TextureField = (typeof TEXTURE_FIELDS)[number];\n\nexport type ExternalizeRuntimeAssetsOptions = {\n assetDir?: string;\n copyExternalAssets?: boolean;\n};\n\nexport type PackRuntimeBundleOptions = {\n compressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;\n manifestPath?: string;\n};\n\nexport type BuildRuntimeWorldIndexOptions = {\n sharedAssets?: RuntimeWorldIndex[\"sharedAssets\"];\n version?: number;\n};\n\nexport async function externalizeRuntimeAssets(\n scene: RuntimeScene,\n options: ExternalizeRuntimeAssetsOptions = {}\n): Promise<RuntimeBundle> {\n const manifest = structuredClone(scene);\n const files: RuntimeBundleFile[] = [];\n const assetDir = trimSlashes(options.assetDir ?? \"assets\");\n const copyExternalAssets = options.copyExternalAssets ?? true;\n const pathBySource = new Map<string, string>();\n const usedPaths = new Set<string>();\n\n for (const material of manifest.materials) {\n for (const field of TEXTURE_FIELDS) {\n const source = material[field];\n\n if (!source) {\n continue;\n }\n\n const bundledPath = await materializeSource(source, {\n copyExternalAssets,\n files,\n pathBySource,\n preferredStem: `${assetDir}/textures/${slugify(material.id)}-${textureFieldSuffix(field)}`,\n usedPaths\n });\n\n if (bundledPath) {\n material[field] = bundledPath;\n }\n }\n }\n\n for (const asset of manifest.assets) {\n if (asset.type !== \"model\") {\n continue;\n }\n\n const bundledPath = await materializeSource(asset.path, {\n copyExternalAssets,\n files,\n pathBySource,\n preferredExtension: inferModelExtension(asset.path, asset.metadata.modelFormat),\n preferredStem: `${assetDir}/models/${slugify(asset.id)}`,\n usedPaths\n });\n\n if (bundledPath) {\n asset.path = bundledPath;\n }\n\n const texturePath = asset.metadata.texturePath;\n\n if (typeof texturePath === \"string\" && texturePath.length > 0) {\n const bundledTexturePath = await materializeSource(texturePath, {\n copyExternalAssets,\n files,\n pathBySource,\n preferredStem: `${assetDir}/model-textures/${slugify(asset.id)}`,\n usedPaths\n });\n\n if (bundledTexturePath) {\n asset.metadata.texturePath = bundledTexturePath;\n }\n }\n }\n\n const skyboxSource = manifest.settings.world.skybox.source;\n\n if (skyboxSource) {\n const bundledSkyboxPath = await materializeSource(skyboxSource, {\n copyExternalAssets,\n files,\n pathBySource,\n preferredExtension: manifest.settings.world.skybox.format === \"hdr\" ? \"hdr\" : inferExtensionFromPath(skyboxSource),\n preferredStem: `${assetDir}/skyboxes/${slugify(manifest.settings.world.skybox.name || \"skybox\")}`,\n usedPaths\n });\n\n if (bundledSkyboxPath) {\n manifest.settings.world.skybox.source = bundledSkyboxPath;\n }\n }\n\n return {\n files,\n manifest\n };\n}\n\nexport async function buildRuntimeBundle(\n scene: RuntimeScene,\n options: ExternalizeRuntimeAssetsOptions = {}\n): Promise<RuntimeBundle> {\n return externalizeRuntimeAssets(scene, options);\n}\n\nexport function normalizeRuntimeScene(scene: RuntimeScene | string): RuntimeScene {\n return typeof scene === \"string\" ? parseRuntimeScene(scene) : parseRuntimeScene(JSON.stringify(scene));\n}\n\nexport function packRuntimeBundle(bundle: RuntimeBundle, options: PackRuntimeBundleOptions = {}) {\n const manifestPath = options.manifestPath ?? \"scene.runtime.json\";\n const encoder = new TextEncoder();\n const entries: Record<string, Uint8Array> = {\n [manifestPath]: encoder.encode(JSON.stringify(bundle.manifest))\n };\n\n bundle.files.forEach((file) => {\n entries[file.path] = file.bytes;\n });\n\n return zipSync(entries, {\n level: options.compressionLevel ?? 6\n });\n}\n\nexport function unpackRuntimeBundle(\n bytes: Uint8Array,\n options: { manifestPath?: string } = {}\n): RuntimeBundle {\n const manifestPath = options.manifestPath ?? \"scene.runtime.json\";\n const archive = unzipSync(bytes);\n const manifestBytes = archive[manifestPath];\n\n if (!manifestBytes) {\n throw new Error(`Bundle is missing ${manifestPath}.`);\n }\n\n const manifest = parseRuntimeScene(new TextDecoder().decode(manifestBytes));\n const files = Object.entries(archive)\n .filter(([path]) => path !== manifestPath)\n .map(([path, fileBytes]) => ({\n bytes: fileBytes,\n mimeType: inferMimeTypeFromPath(path),\n path\n }));\n\n return {\n files,\n manifest\n };\n}\n\nexport function buildRuntimeWorldIndex(\n chunks: RuntimeWorldChunk[],\n options: BuildRuntimeWorldIndexOptions = {}\n): RuntimeWorldIndex {\n return {\n chunks,\n sharedAssets: options.sharedAssets,\n version: options.version ?? 1\n };\n}\n\nexport async function externalizeWebHammerEngineScene(\n scene: WebHammerEngineScene,\n options: ExternalizeRuntimeAssetsOptions = {}\n): Promise<WebHammerEngineBundle> {\n return externalizeRuntimeAssets(scene, options);\n}\n\nexport function createWebHammerEngineBundleZip(bundle: WebHammerEngineBundle, options: PackRuntimeBundleOptions = {}) {\n return packRuntimeBundle(bundle, options);\n}\n\nexport function parseWebHammerEngineBundleZip(\n bytes: Uint8Array,\n options: { manifestPath?: string } = {}\n): WebHammerEngineBundle {\n return unpackRuntimeBundle(bytes, options);\n}\n\nasync function materializeSource(\n source: string,\n context: {\n copyExternalAssets: boolean;\n files: RuntimeBundleFile[];\n pathBySource: Map<string, string>;\n preferredExtension?: string;\n preferredStem: string;\n usedPaths: Set<string>;\n }\n) {\n const existing = context.pathBySource.get(source);\n\n if (existing) {\n return existing;\n }\n\n if (isDataUrl(source)) {\n const parsed = parseDataUrl(source);\n const path = ensureUniquePath(\n `${context.preferredStem}.${inferExtension(parsed.mimeType, context.preferredExtension)}`,\n context.usedPaths\n );\n\n context.files.push({\n bytes: parsed.bytes,\n mimeType: parsed.mimeType,\n path\n });\n context.pathBySource.set(source, path);\n return path;\n }\n\n if (!context.copyExternalAssets) {\n return undefined;\n }\n\n const response = await fetch(source);\n\n if (!response.ok) {\n throw new Error(`Failed to bundle asset: ${source}`);\n }\n\n const blob = await response.blob();\n const bytes = new Uint8Array(await blob.arrayBuffer());\n const path = ensureUniquePath(\n `${context.preferredStem}.${inferExtension(blob.type, context.preferredExtension ?? inferExtensionFromPath(source))}`,\n context.usedPaths\n );\n\n context.files.push({\n bytes,\n mimeType: blob.type || \"application/octet-stream\",\n path\n });\n context.pathBySource.set(source, path);\n\n return path;\n}\n\nfunction parseDataUrl(source: string) {\n const match = /^data:([^;,]+)?(?:;charset=[^;,]+)?(;base64)?,(.*)$/i.exec(source);\n\n if (!match) {\n throw new Error(\"Invalid data URL.\");\n }\n\n const mimeType = match[1] || \"application/octet-stream\";\n const payload = match[3] || \"\";\n\n if (match[2]) {\n const binary = atob(payload);\n const bytes = new Uint8Array(binary.length);\n\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n\n return { bytes, mimeType };\n }\n\n return {\n bytes: new TextEncoder().encode(decodeURIComponent(payload)),\n mimeType\n };\n}\n\nfunction textureFieldSuffix(field: TextureField) {\n switch (field) {\n case \"baseColorTexture\":\n return \"color\";\n case \"metallicRoughnessTexture\":\n return \"orm\";\n default:\n return \"normal\";\n }\n}\n\nfunction inferModelExtension(path: string, modelFormat: unknown) {\n if (typeof modelFormat === \"string\" && modelFormat.length > 0) {\n return modelFormat.toLowerCase();\n }\n\n return inferExtensionFromPath(path) ?? \"bin\";\n}\n\nfunction inferExtension(mimeType: string | undefined, fallback?: string) {\n const normalized = mimeType?.toLowerCase();\n\n if (normalized === \"image/png\") {\n return \"png\";\n }\n\n if (normalized === \"image/jpeg\") {\n return \"jpg\";\n }\n\n if (normalized === \"image/svg+xml\") {\n return \"svg\";\n }\n\n if (normalized === \"image/vnd.radiance\") {\n return \"hdr\";\n }\n\n if (normalized === \"model/gltf+json\") {\n return \"gltf\";\n }\n\n if (normalized === \"model/gltf-binary\" || normalized === \"application/octet-stream\") {\n return fallback ?? \"bin\";\n }\n\n return fallback ?? \"bin\";\n}\n\nfunction inferExtensionFromPath(path: string) {\n const cleanPath = path.split(\"?\")[0]?.split(\"#\")[0] ?? path;\n const parts = cleanPath.split(\".\");\n return parts.length > 1 ? parts.at(-1)?.toLowerCase() : undefined;\n}\n\nfunction inferMimeTypeFromPath(path: string) {\n switch (inferExtensionFromPath(path)) {\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n case \"jpeg\":\n return \"image/jpeg\";\n case \"svg\":\n return \"image/svg+xml\";\n case \"hdr\":\n return \"image/vnd.radiance\";\n case \"glb\":\n return \"model/gltf-binary\";\n case \"gltf\":\n return \"model/gltf+json\";\n case \"obj\":\n return \"text/plain\";\n case \"mtl\":\n return \"text/plain\";\n case \"json\":\n return \"application/json\";\n default:\n return \"application/octet-stream\";\n }\n}\n\nfunction ensureUniquePath(path: string, usedPaths: Set<string>) {\n if (!usedPaths.has(path)) {\n usedPaths.add(path);\n return path;\n }\n\n const lastDot = path.lastIndexOf(\".\");\n const stem = lastDot >= 0 ? path.slice(0, lastDot) : path;\n const extension = lastDot >= 0 ? path.slice(lastDot) : \"\";\n let counter = 2;\n\n while (usedPaths.has(`${stem}-${counter}${extension}`)) {\n counter += 1;\n }\n\n const resolved = `${stem}-${counter}${extension}`;\n usedPaths.add(resolved);\n return resolved;\n}\n\nfunction isDataUrl(value: string) {\n return value.startsWith(\"data:\");\n}\n\nfunction slugify(value: string) {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n\n return normalized || \"asset\";\n}\n\nfunction trimSlashes(value: string) {\n return value.replace(/^\\/+|\\/+$/g, \"\");\n}\n","import earcut from \"earcut\";\nimport {\n addVec3,\n averageVec3,\n crossVec3,\n dotVec3,\n lengthVec3,\n normalizeVec3,\n scaleVec3,\n subVec3,\n vec3\n} from \"@ggez/shared\";\nimport type { Vec3 } from \"@ggez/shared\";\n\nexport function computePolygonNormal(vertices: Vec3[]): Vec3 {\n if (vertices.length < 3) {\n return vec3(0, 1, 0);\n }\n\n let normal = vec3(0, 0, 0);\n\n for (let index = 0; index < vertices.length; index += 1) {\n const current = vertices[index];\n const next = vertices[(index + 1) % vertices.length];\n\n normal = addVec3(\n normal,\n vec3(\n (current.y - next.y) * (current.z + next.z),\n (current.z - next.z) * (current.x + next.x),\n (current.x - next.x) * (current.y + next.y)\n )\n );\n }\n\n const normalized = normalizeVec3(normal);\n return lengthVec3(normalized) === 0 ? vec3(0, 1, 0) : normalized;\n}\n\nexport function projectPolygonToPlane(vertices: Vec3[], normal = computePolygonNormal(vertices)): Array<[number, number]> {\n const origin = averageVec3(vertices);\n const tangentReference = Math.abs(normal.y) < 0.99 ? vec3(0, 1, 0) : vec3(1, 0, 0);\n let tangent = normalizeVec3(crossVec3(tangentReference, normal));\n\n if (lengthVec3(tangent) === 0) {\n tangent = normalizeVec3(crossVec3(vec3(0, 0, 1), normal));\n }\n\n const bitangent = normalizeVec3(crossVec3(normal, tangent));\n\n return vertices.map((vertex) => {\n const offset = subVec3(vertex, origin);\n return [dotVec3(offset, tangent), dotVec3(offset, bitangent)];\n });\n}\n\nexport function polygonSignedArea(points: Array<[number, number]>): number {\n let area = 0;\n\n for (let index = 0; index < points.length; index += 1) {\n const [x1, y1] = points[index];\n const [x2, y2] = points[(index + 1) % points.length];\n area += x1 * y2 - x2 * y1;\n }\n\n return area * 0.5;\n}\n\nexport function sortVerticesOnPlane(vertices: Vec3[], normal: Vec3): Vec3[] {\n const center = averageVec3(vertices);\n const tangentReference = Math.abs(normal.y) < 0.99 ? vec3(0, 1, 0) : vec3(1, 0, 0);\n let tangent = normalizeVec3(crossVec3(tangentReference, normal));\n\n if (lengthVec3(tangent) === 0) {\n tangent = normalizeVec3(crossVec3(vec3(0, 0, 1), normal));\n }\n\n const bitangent = normalizeVec3(crossVec3(normal, tangent));\n const sorted = [...vertices].sort((left, right) => {\n const leftOffset = subVec3(left, center);\n const rightOffset = subVec3(right, center);\n const leftAngle = Math.atan2(dotVec3(leftOffset, bitangent), dotVec3(leftOffset, tangent));\n const rightAngle = Math.atan2(dotVec3(rightOffset, bitangent), dotVec3(rightOffset, tangent));\n\n return leftAngle - rightAngle;\n });\n\n if (sorted.length < 3) {\n return sorted;\n }\n\n const windingNormal = normalizeVec3(\n crossVec3(subVec3(sorted[1], sorted[0]), subVec3(sorted[2], sorted[0]))\n );\n\n return dotVec3(windingNormal, normal) < 0 ? sorted.reverse() : sorted;\n}\n\nexport function triangulatePolygon(points: Array<[number, number]>): number[] {\n const flattened = points.flatMap(([x, y]) => [x, y]);\n return earcut(flattened);\n}\n\nexport function triangulatePolygon3D(vertices: Vec3[], normal = computePolygonNormal(vertices)): number[] {\n if (vertices.length < 3) {\n return [];\n }\n\n const projected = projectPolygonToPlane(vertices, normal);\n\n if (Math.abs(polygonSignedArea(projected)) <= 0.000001) {\n return [];\n }\n\n return triangulatePolygon(projected);\n}\n\nexport function computeFaceCenter(vertices: Vec3[]): Vec3 {\n return averageVec3(vertices);\n}\n\nexport function scaleFaceFromCenter(vertices: Vec3[], scale: number): Vec3[] {\n const center = computeFaceCenter(vertices);\n return vertices.map((vertex) => addVec3(center, scaleVec3(subVec3(vertex, center), scale)));\n}\n","import {\n addVec3,\n crossVec3,\n dotVec3,\n normalizeVec3,\n scaleVec3,\n vec3\n} from \"@ggez/shared\";\nimport type { Brush, Face, Plane, Vec3 } from \"@ggez/shared\";\nimport { computeFaceCenter, sortVerticesOnPlane, triangulatePolygon3D } from \"../polygon/polygon-utils\";\n\nexport type ReconstructedBrushVertex = {\n id: string;\n position: Vec3;\n};\n\nexport type ReconstructedBrushFace = Face & {\n center: Vec3;\n normal: Vec3;\n triangleIndices: number[];\n vertices: ReconstructedBrushVertex[];\n};\n\nexport type BrushRebuildResult = {\n faces: ReconstructedBrushFace[];\n vertices: ReconstructedBrushVertex[];\n valid: boolean;\n errors: string[];\n};\n\nexport function reconstructBrushFaces(brush: Brush, epsilon = 0.0001): BrushRebuildResult {\n if (brush.planes.length < 4) {\n return {\n faces: [],\n vertices: [],\n valid: false,\n errors: [\"Brush reconstruction requires at least four planes.\"]\n };\n }\n\n const vertexRegistry = new Map<string, ReconstructedBrushVertex>();\n const faces: ReconstructedBrushFace[] = [];\n\n for (let planeIndex = 0; planeIndex < brush.planes.length; planeIndex += 1) {\n const plane = brush.planes[planeIndex];\n const faceVertices = collectFaceVertices(brush.planes, planeIndex, epsilon);\n\n if (faceVertices.length < 3) {\n continue;\n }\n\n const orderedVertices = sortVerticesOnPlane(faceVertices, normalizeVec3(plane.normal));\n const triangleIndices = triangulatePolygon3D(orderedVertices, plane.normal);\n\n if (triangleIndices.length < 3) {\n continue;\n }\n\n const vertices = orderedVertices.map((position) => registerBrushVertex(vertexRegistry, position, epsilon));\n const seedFace = brush.faces[planeIndex];\n\n faces.push({\n id: seedFace?.id ?? `face:brush:${planeIndex}`,\n plane,\n materialId: seedFace?.materialId,\n uvOffset: seedFace?.uvOffset,\n uvScale: seedFace?.uvScale,\n vertexIds: vertices.map((vertex) => vertex.id),\n vertices,\n center: computeFaceCenter(orderedVertices),\n normal: normalizeVec3(plane.normal),\n triangleIndices\n });\n }\n\n return {\n faces,\n vertices: Array.from(vertexRegistry.values()),\n valid: faces.length >= 4,\n errors: faces.length >= 4 ? [] : [\"Brush reconstruction did not produce a closed convex solid.\"]\n };\n}\n\nexport function classifyPointAgainstPlane(point: Vec3, plane: Plane, epsilon = 0.0001): \"inside\" | \"outside\" {\n const signedDistance = signedDistanceToPlane(point, plane);\n\n return signedDistance > epsilon ? \"outside\" : \"inside\";\n}\n\nexport function signedDistanceToPlane(point: Vec3, plane: Plane): number {\n return dotVec3(plane.normal, point) - plane.distance;\n}\n\nexport function intersectPlanes(\n first: Plane,\n second: Plane,\n third: Plane,\n epsilon = 0.000001\n): Vec3 | undefined {\n const denominator = dotVec3(first.normal, crossVec3(second.normal, third.normal));\n\n if (Math.abs(denominator) <= epsilon) {\n return undefined;\n }\n\n const firstTerm = scaleVec3(crossVec3(second.normal, third.normal), first.distance);\n const secondTerm = scaleVec3(crossVec3(third.normal, first.normal), second.distance);\n const thirdTerm = scaleVec3(crossVec3(first.normal, second.normal), third.distance);\n\n return scaleVec3(addVec3(addVec3(firstTerm, secondTerm), thirdTerm), 1 / denominator);\n}\n\nfunction collectFaceVertices(planes: Plane[], planeIndex: number, epsilon: number): Vec3[] {\n const plane = planes[planeIndex];\n const vertices = new Map<string, Vec3>();\n\n for (let firstIndex = 0; firstIndex < planes.length; firstIndex += 1) {\n if (firstIndex === planeIndex) {\n continue;\n }\n\n for (let secondIndex = firstIndex + 1; secondIndex < planes.length; secondIndex += 1) {\n if (secondIndex === planeIndex) {\n continue;\n }\n\n const intersection = intersectPlanes(plane, planes[firstIndex], planes[secondIndex], epsilon);\n\n if (!intersection) {\n continue;\n }\n\n const liesOnPlane = Math.abs(signedDistanceToPlane(intersection, plane)) <= epsilon * 4;\n const insideAllPlanes = planes.every(\n (candidatePlane) => classifyPointAgainstPlane(intersection, candidatePlane, epsilon * 4) === \"inside\"\n );\n\n if (!liesOnPlane || !insideAllPlanes) {\n continue;\n }\n\n vertices.set(makeVertexKey(intersection, epsilon), intersection);\n }\n }\n\n return Array.from(vertices.values());\n}\n\nfunction registerBrushVertex(\n registry: Map<string, ReconstructedBrushVertex>,\n position: Vec3,\n epsilon: number\n): ReconstructedBrushVertex {\n const key = makeVertexKey(position, epsilon);\n const existing = registry.get(key);\n\n if (existing) {\n return existing;\n }\n\n const vertex = {\n id: `vertex:brush:${registry.size}`,\n position: vec3(position.x, position.y, position.z)\n };\n\n registry.set(key, vertex);\n return vertex;\n}\n\nfunction makeVertexKey(position: Vec3, epsilon: number): string {\n return [\n Math.round(position.x / epsilon),\n Math.round(position.y / epsilon),\n Math.round(position.z / epsilon)\n ].join(\":\");\n}\n","import {\n computePolygonNormal,\n triangulatePolygon,\n triangulatePolygon3D\n} from \"../polygon/polygon-utils\";\nimport type {\n EditableMesh,\n EditableMeshFace,\n EditableMeshHalfEdge,\n EditableMeshVertex,\n FaceID,\n HalfEdgeID,\n MaterialID,\n Vec3,\n Vec2,\n VertexID\n} from \"@ggez/shared\";\nimport { almostEqual, vec3 } from \"@ggez/shared\";\n\nexport type EditableMeshPolygon = {\n id?: FaceID;\n materialId?: MaterialID;\n positions: Vec3[];\n uvScale?: Vec2;\n uvs?: Vec2[];\n vertexIds?: VertexID[];\n};\n\nexport type EditableMeshValidation = {\n valid: boolean;\n errors: string[];\n};\n\nexport type TriangulatedMeshFace = {\n faceId: FaceID;\n vertexIds: VertexID[];\n normal: Vec3;\n indices: number[];\n};\n\nexport type TriangulatedEditableMesh = EditableMeshValidation & {\n faces: TriangulatedMeshFace[];\n indices: number[];\n positions: number[];\n};\n\ntype EditableMeshIndex = {\n faceById: Map<FaceID, EditableMeshFace>;\n faceVertexIds: Map<FaceID, VertexID[]>;\n faces: EditableMesh[\"faces\"];\n halfEdgeById: Map<HalfEdgeID, EditableMeshHalfEdge>;\n halfEdges: EditableMesh[\"halfEdges\"];\n vertexById: Map<VertexID, EditableMeshVertex>;\n vertices: EditableMesh[\"vertices\"];\n};\n\nconst editableMeshIndexCache = new WeakMap<EditableMesh, EditableMeshIndex>();\n\nexport function createEditableMeshFromPolygons(\n polygons: EditableMeshPolygon[],\n epsilon = 0.0001\n): EditableMesh {\n const vertices: EditableMeshVertex[] = [];\n const halfEdges: EditableMeshHalfEdge[] = [];\n const faces: EditableMeshFace[] = [];\n const vertexRegistry = new Map<string, EditableMeshVertex>();\n const directedEdges = new Map<string, HalfEdgeID>();\n const halfEdgesById = new Map<HalfEdgeID, EditableMeshHalfEdge>();\n\n polygons.forEach((polygon, polygonIndex) => {\n const orderedPositions = normalizePolygonLoop(polygon.positions);\n const orderedVertexIds =\n polygon.vertexIds && polygon.vertexIds.length >= orderedPositions.length\n ? polygon.vertexIds.slice(0, orderedPositions.length)\n : undefined;\n\n if (orderedPositions.length < 3) {\n return;\n }\n\n // Preserve caller-provided winding. Topology ops already emit ordered loops,\n // and re-sorting around the face center can corrupt concave or intentionally\n // stitched polygons after cuts/bevels.\n const orderedVertices = orderedPositions;\n const faceId = polygon.id ?? `face:mesh:${polygonIndex}`;\n const faceHalfEdges: EditableMeshHalfEdge[] = [];\n\n orderedVertices.forEach((position, edgeIndex) => {\n const currentVertex = registerMeshVertex(\n vertexRegistry,\n vertices,\n position,\n epsilon,\n orderedVertexIds?.[edgeIndex]\n );\n const nextVertex = registerMeshVertex(\n vertexRegistry,\n vertices,\n orderedVertices[(edgeIndex + 1) % orderedVertices.length],\n epsilon,\n orderedVertexIds?.[(edgeIndex + 1) % orderedVertices.length]\n );\n const halfEdge: EditableMeshHalfEdge = {\n id: `half-edge:${faceId}:${edgeIndex}`,\n vertex: currentVertex.id,\n face: faceId\n };\n\n const reverseKey = `${nextVertex.id}:${currentVertex.id}`;\n const reverseHalfEdgeId = directedEdges.get(reverseKey);\n\n if (reverseHalfEdgeId) {\n halfEdge.twin = reverseHalfEdgeId;\n const reverseHalfEdge = halfEdgesById.get(reverseHalfEdgeId);\n\n if (reverseHalfEdge) {\n reverseHalfEdge.twin = halfEdge.id;\n }\n }\n\n directedEdges.set(`${currentVertex.id}:${nextVertex.id}`, halfEdge.id);\n faceHalfEdges.push(halfEdge);\n halfEdges.push(halfEdge);\n halfEdgesById.set(halfEdge.id, halfEdge);\n });\n\n faceHalfEdges.forEach((halfEdge, edgeIndex) => {\n halfEdge.next = faceHalfEdges[(edgeIndex + 1) % faceHalfEdges.length].id;\n });\n\n faces.push({\n id: faceId,\n halfEdge: faceHalfEdges[0].id,\n materialId: polygon.materialId,\n uvScale: polygon.uvScale,\n uvs: polygon.uvs?.slice(0, orderedVertices.length)\n });\n });\n\n return {\n vertices,\n halfEdges,\n faces\n };\n}\n\nexport function getFaceVertexIds(mesh: EditableMesh, faceId: FaceID): VertexID[] {\n const index = getEditableMeshIndex(mesh);\n const cachedIds = index.faceVertexIds.get(faceId);\n\n if (cachedIds) {\n return cachedIds;\n }\n\n const face = index.faceById.get(faceId);\n\n if (!face) {\n return [];\n }\n\n const ids: VertexID[] = [];\n let currentEdgeId: HalfEdgeID | undefined = face.halfEdge;\n let guard = 0;\n\n while (currentEdgeId && guard < mesh.halfEdges.length + 1) {\n const halfEdge = index.halfEdgeById.get(currentEdgeId);\n\n if (!halfEdge) {\n return [];\n }\n\n ids.push(halfEdge.vertex);\n currentEdgeId = halfEdge.next;\n guard += 1;\n\n if (currentEdgeId === face.halfEdge) {\n break;\n }\n }\n\n index.faceVertexIds.set(faceId, ids);\n return ids;\n}\n\nexport function getFaceVertices(mesh: EditableMesh, faceId: FaceID): EditableMeshVertex[] {\n const index = getEditableMeshIndex(mesh);\n\n return getFaceVertexIds(mesh, faceId)\n .map((vertexId) => index.vertexById.get(vertexId))\n .filter((vertex): vertex is EditableMeshVertex => Boolean(vertex));\n}\n\nexport function validateEditableMesh(mesh: EditableMesh): EditableMeshValidation {\n const errors: string[] = [];\n const verticesById = new Set(mesh.vertices.map((vertex) => vertex.id));\n const halfEdgesById = new Map(mesh.halfEdges.map((halfEdge) => [halfEdge.id, halfEdge]));\n\n mesh.faces.forEach((face) => {\n if (!halfEdgesById.has(face.halfEdge)) {\n errors.push(`Face ${face.id} references missing half-edge ${face.halfEdge}.`);\n return;\n }\n\n const faceVertexIds = getFaceVertexIds(mesh, face.id);\n\n if (faceVertexIds.length < 3) {\n errors.push(`Face ${face.id} does not resolve to a closed polygon loop.`);\n }\n });\n\n mesh.halfEdges.forEach((halfEdge) => {\n if (!verticesById.has(halfEdge.vertex)) {\n errors.push(`Half-edge ${halfEdge.id} references missing vertex ${halfEdge.vertex}.`);\n }\n\n if (halfEdge.next && !halfEdgesById.has(halfEdge.next)) {\n errors.push(`Half-edge ${halfEdge.id} references missing next edge ${halfEdge.next}.`);\n }\n\n if (halfEdge.twin) {\n const twin = halfEdgesById.get(halfEdge.twin);\n\n if (!twin) {\n errors.push(`Half-edge ${halfEdge.id} references missing twin ${halfEdge.twin}.`);\n } else if (twin.twin !== halfEdge.id) {\n errors.push(`Half-edge ${halfEdge.id} and ${halfEdge.twin} do not reciprocate their twin links.`);\n }\n }\n });\n\n return {\n valid: errors.length === 0,\n errors\n };\n}\n\nexport function triangulateMeshFace(mesh: EditableMesh, faceId: FaceID): TriangulatedMeshFace | undefined {\n const faceVertices = getFaceVertices(mesh, faceId);\n\n if (faceVertices.length < 3) {\n return undefined;\n }\n\n const normal = computePolygonNormal(faceVertices.map((vertex) => vertex.position));\n const indices = triangulatePolygon3D(\n faceVertices.map((vertex) => vertex.position),\n normal\n );\n\n if (indices.length < 3) {\n return undefined;\n }\n\n return {\n faceId,\n vertexIds: faceVertices.map((vertex) => vertex.id),\n normal,\n indices\n };\n}\n\nexport function triangulateEditableMesh(mesh: EditableMesh): TriangulatedEditableMesh {\n const validation = validateEditableMesh(mesh);\n const vertexIndexById = new Map(mesh.vertices.map((vertex, index) => [vertex.id, index]));\n const positions = mesh.vertices.flatMap((vertex) => [vertex.position.x, vertex.position.y, vertex.position.z]);\n const faces = mesh.faces\n .map((face) => triangulateMeshFace(mesh, face.id))\n .filter((face): face is TriangulatedMeshFace => Boolean(face));\n const indices = faces.flatMap((face) =>\n face.indices.map((localIndex) => vertexIndexById.get(face.vertexIds[localIndex]) ?? 0)\n );\n\n return {\n valid: validation.valid && faces.length > 0 && indices.length > 0,\n errors: validation.errors,\n faces,\n indices,\n positions\n };\n}\n\nfunction registerMeshVertex(\n registry: Map<string, EditableMeshVertex>,\n vertices: EditableMeshVertex[],\n position: Vec3,\n epsilon: number,\n preferredId?: VertexID\n): EditableMeshVertex {\n const key = preferredId ? `id:${preferredId}` : makeVertexKey(position, epsilon);\n const existing = registry.get(key);\n\n if (existing) {\n return existing;\n }\n\n const vertex = {\n id: preferredId ?? `vertex:mesh:${vertices.length}`,\n position: vec3(position.x, position.y, position.z)\n };\n\n registry.set(key, vertex);\n vertices.push(vertex);\n return vertex;\n}\n\nfunction normalizePolygonLoop(positions: Vec3[]): Vec3[] {\n if (positions.length >= 2) {\n const first = positions[0];\n const last = positions[positions.length - 1];\n\n if (\n almostEqual(first.x, last.x) &&\n almostEqual(first.y, last.y) &&\n almostEqual(first.z, last.z)\n ) {\n return positions.slice(0, -1);\n }\n }\n\n return positions;\n}\n\nfunction makeVertexKey(position: Vec3, epsilon: number): string {\n return [\n Math.round(position.x / epsilon),\n Math.round(position.y / epsilon),\n Math.round(position.z / epsilon)\n ].join(\":\");\n}\n\nfunction getEditableMeshIndex(mesh: EditableMesh): EditableMeshIndex {\n const cached = editableMeshIndexCache.get(mesh);\n\n if (cached && cached.faces === mesh.faces && cached.halfEdges === mesh.halfEdges && cached.vertices === mesh.vertices) {\n return cached;\n }\n\n const nextIndex: EditableMeshIndex = {\n faceById: new Map(mesh.faces.map((face) => [face.id, face] as const)),\n faceVertexIds: new Map(),\n faces: mesh.faces,\n halfEdgeById: new Map(mesh.halfEdges.map((halfEdge) => [halfEdge.id, halfEdge] as const)),\n halfEdges: mesh.halfEdges,\n vertexById: new Map(mesh.vertices.map((vertex) => [vertex.id, vertex] as const)),\n vertices: mesh.vertices\n };\n\n editableMeshIndexCache.set(mesh, nextIndex);\n return nextIndex;\n}\n","import { getFaceVertices, reconstructBrushFaces, triangulateMeshFace } from \"@ggez/geometry-kernel\";\nimport type { SceneDocumentSnapshot } from \"@ggez/editor-core\";\nimport {\n createBlockoutTextureDataUri,\n crossVec3,\n dotVec3,\n isBrushNode,\n isGroupNode,\n isInstancingNode,\n isMeshNode,\n isModelNode,\n isPrimitiveNode,\n normalizeVec3,\n resolveInstancingSourceNode,\n subVec3,\n vec3,\n type Asset,\n type Material,\n type MaterialID,\n type Vec2,\n type Vec3\n} from \"@ggez/shared\";\nimport {\n CURRENT_RUNTIME_SCENE_VERSION,\n parseRuntimeScene,\n type RuntimeBundle,\n type RuntimeGeometry,\n type RuntimeGeometryLod,\n type RuntimeMaterial,\n type RuntimeModelLod,\n type RuntimeScene\n} from \"@ggez/runtime-format\";\nimport { MeshBVH } from \"three-mesh-bvh\";\nimport {\n Box3,\n BoxGeometry,\n BufferGeometry,\n ConeGeometry,\n Float32BufferAttribute,\n Group,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n RepeatWrapping,\n Scene,\n SphereGeometry,\n SRGBColorSpace,\n TextureLoader,\n Vector3,\n CylinderGeometry\n} from \"three\";\nimport { GLTFExporter } from \"three/examples/jsm/exporters/GLTFExporter.js\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport { MTLLoader } from \"three/examples/jsm/loaders/MTLLoader.js\";\nimport { OBJLoader } from \"three/examples/jsm/loaders/OBJLoader.js\";\nimport { externalizeRuntimeAssets, type ExternalizeRuntimeAssetsOptions, normalizeRuntimeScene } from \"./bundle\";\n\nconst gltfLoader = new GLTFLoader();\nconst gltfExporter = new GLTFExporter();\nconst mtlLoader = new MTLLoader();\nconst modelTextureLoader = new TextureLoader();\n\nexport async function buildRuntimeScene(input: SceneDocumentSnapshot | RuntimeScene | string): Promise<RuntimeScene> {\n if (typeof input === \"string\") {\n return parseRuntimeScene(input);\n }\n\n if (isSceneDocumentSnapshotLike(input)) {\n return buildRuntimeSceneFromSnapshot(input);\n }\n\n return normalizeRuntimeScene(input);\n}\n\nexport async function buildRuntimeBundleFromSnapshot(\n snapshot: SceneDocumentSnapshot,\n options: ExternalizeRuntimeAssetsOptions = {}\n): Promise<RuntimeBundle> {\n return externalizeRuntimeAssets(await buildRuntimeSceneFromSnapshot(snapshot), options);\n}\n\nexport async function serializeRuntimeScene(snapshot: SceneDocumentSnapshot): Promise<string> {\n return JSON.stringify(await buildRuntimeSceneFromSnapshot(snapshot));\n}\n\nexport async function buildRuntimeSceneFromSnapshot(snapshot: SceneDocumentSnapshot): Promise<RuntimeScene> {\n const assetsById = new Map(snapshot.assets.map((asset) => [asset.id, asset]));\n const materialsById = new Map(snapshot.materials.map((material) => [material.id, material]));\n const exportedMaterials = await Promise.all(snapshot.materials.map((material) => resolveRuntimeMaterial(material)));\n const shouldBakeLods = snapshot.settings.world.lod.enabled;\n const exportedAt = new Date().toISOString();\n const exportedSettings = shouldBakeLods\n ? {\n ...snapshot.settings,\n world: {\n ...snapshot.settings.world,\n lod: {\n ...snapshot.settings.world.lod,\n bakedAt: exportedAt\n }\n }\n }\n : snapshot.settings;\n const generatedAssets: Asset[] = [];\n const exportedNodes: RuntimeScene[\"nodes\"] = [];\n\n for (const node of snapshot.nodes) {\n if (isGroupNode(node)) {\n exportedNodes.push({\n data: node.data,\n hooks: node.hooks,\n id: node.id,\n kind: \"group\",\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: node.transform\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"group\" }>);\n continue;\n }\n\n if (isBrushNode(node)) {\n const geometry = await buildExportGeometry(node, materialsById);\n exportedNodes.push({\n data: node.data,\n geometry,\n hooks: node.hooks,\n id: node.id,\n kind: \"brush\",\n lods: shouldBakeLods ? await buildGeometryLods(geometry, snapshot.settings.world.lod) : undefined,\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: node.transform\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"brush\" }>);\n continue;\n }\n\n if (isMeshNode(node)) {\n const geometry = await buildExportGeometry(node, materialsById);\n exportedNodes.push({\n data: node.data,\n geometry,\n hooks: node.hooks,\n id: node.id,\n kind: \"mesh\",\n lods: shouldBakeLods ? await buildGeometryLods(geometry, snapshot.settings.world.lod) : undefined,\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: node.transform\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"mesh\" }>);\n continue;\n }\n\n if (isPrimitiveNode(node)) {\n const geometry = await buildExportGeometry(node, materialsById);\n exportedNodes.push({\n data: node.data,\n geometry,\n hooks: node.hooks,\n id: node.id,\n kind: \"primitive\",\n lods: shouldBakeLods ? await buildGeometryLods(geometry, snapshot.settings.world.lod) : undefined,\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: node.transform\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"primitive\" }>);\n continue;\n }\n\n if (isModelNode(node)) {\n const modelLodBake = shouldBakeLods\n ? await buildModelLods(node.name, assetsById.get(node.data.assetId), node.id, snapshot.settings.world.lod)\n : undefined;\n\n generatedAssets.push(...(modelLodBake?.assets ?? []));\n exportedNodes.push({\n data: node.data,\n hooks: node.hooks,\n id: node.id,\n kind: \"model\",\n lods: modelLodBake?.lods,\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: node.transform\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"model\" }>);\n continue;\n }\n\n if (isInstancingNode(node)) {\n const sourceNode = resolveInstancingSourceNode(snapshot.nodes, node);\n\n if (!sourceNode || !(isBrushNode(sourceNode) || isMeshNode(sourceNode) || isPrimitiveNode(sourceNode) || isModelNode(sourceNode))) {\n continue;\n }\n\n exportedNodes.push({\n data: {\n sourceNodeId: sourceNode.id\n },\n hooks: node.hooks,\n id: node.id,\n kind: \"instancing\",\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: sanitizeInstanceTransform(node.transform)\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"instancing\" }>);\n continue;\n }\n\n exportedNodes.push({\n data: node.data,\n id: node.id,\n kind: \"light\",\n metadata: node.metadata,\n name: node.name,\n parentId: node.parentId,\n tags: node.tags,\n transform: node.transform\n } satisfies Extract<RuntimeScene[\"nodes\"][number], { kind: \"light\" }>);\n }\n\n return {\n assets: [...snapshot.assets, ...generatedAssets],\n entities: snapshot.entities,\n layers: snapshot.layers,\n materials: exportedMaterials,\n metadata: {\n exportedAt,\n format: \"web-hammer-engine\",\n version: CURRENT_RUNTIME_SCENE_VERSION\n },\n nodes: exportedNodes,\n settings: exportedSettings\n } satisfies RuntimeScene;\n}\n\nfunction isSceneDocumentSnapshotLike(value: unknown): value is SceneDocumentSnapshot {\n return Boolean(\n value &&\n typeof value === \"object\" &&\n Array.isArray((value as Partial<SceneDocumentSnapshot>).nodes) &&\n Array.isArray((value as Partial<SceneDocumentSnapshot>).materials) &&\n Array.isArray((value as Partial<SceneDocumentSnapshot>).textures)\n );\n}\n\nasync function buildExportGeometry(\n node: Extract<SceneDocumentSnapshot[\"nodes\"][number], { kind: \"brush\" | \"mesh\" | \"primitive\" }>,\n materialsById: Map<MaterialID, Material>\n) {\n const fallbackMaterial = await resolveRuntimeMaterial({\n color: node.kind === \"brush\" ? \"#f69036\" : node.kind === \"primitive\" && node.data.role === \"prop\" ? \"#7f8ea3\" : \"#6ed5c0\",\n id: `material:fallback:${node.id}`,\n metalness: node.kind === \"brush\" ? 0 : node.kind === \"primitive\" && node.data.role === \"prop\" ? 0.12 : 0.05,\n name: `${node.name} Default`,\n roughness: node.kind === \"brush\" ? 0.95 : node.kind === \"primitive\" && node.data.role === \"prop\" ? 0.64 : 0.82\n });\n const primitiveByMaterial = new Map<string, RuntimeGeometry[\"primitives\"][number]>();\n\n const appendFace = async (params: {\n faceMaterialId?: string;\n normal: Vec3;\n triangleIndices: number[];\n uvOffset?: Vec2;\n uvScale?: Vec2;\n uvs?: Vec2[];\n vertices: Vec3[];\n }) => {\n const material = params.faceMaterialId ? await resolveRuntimeMaterial(materialsById.get(params.faceMaterialId)) : fallbackMaterial;\n const primitive = primitiveByMaterial.get(material.id) ?? {\n indices: [],\n material,\n normals: [],\n positions: [],\n uvs: []\n };\n const vertexOffset = primitive.positions.length / 3;\n const uvs = params.uvs && params.uvs.length === params.vertices.length\n ? params.uvs.flatMap((uv) => [uv.x, uv.y])\n : projectPlanarUvs(params.vertices, params.normal, params.uvScale, params.uvOffset);\n\n params.vertices.forEach((vertex) => {\n primitive.positions.push(vertex.x, vertex.y, vertex.z);\n primitive.normals.push(params.normal.x, params.normal.y, params.normal.z);\n });\n primitive.uvs.push(...uvs);\n params.triangleIndices.forEach((index) => {\n primitive.indices.push(vertexOffset + index);\n });\n primitiveByMaterial.set(material.id, primitive);\n };\n\n if (isBrushNode(node)) {\n const rebuilt = reconstructBrushFaces(node.data);\n\n if (!rebuilt.valid) {\n return { primitives: [] };\n }\n\n for (const face of rebuilt.faces) {\n await appendFace({\n faceMaterialId: face.materialId,\n normal: face.normal,\n triangleIndices: face.triangleIndices,\n uvOffset: face.uvOffset,\n uvScale: face.uvScale,\n vertices: face.vertices.map((vertex) => vertex.position)\n });\n }\n }\n\n if (isMeshNode(node)) {\n for (const face of node.data.faces) {\n const triangulated = triangulateMeshFace(node.data, face.id);\n\n if (!triangulated) {\n continue;\n }\n\n await appendFace({\n faceMaterialId: face.materialId,\n normal: triangulated.normal,\n triangleIndices: triangulated.indices,\n uvOffset: face.uvOffset,\n uvScale: face.uvScale,\n uvs: face.uvs,\n vertices: getFaceVertices(node.data, face.id).map((vertex) => vertex.position)\n });\n }\n }\n\n if (isPrimitiveNode(node)) {\n const material = node.data.materialId ? await resolveRuntimeMaterial(materialsById.get(node.data.materialId)) : fallbackMaterial;\n const primitive = buildPrimitiveGeometry(node.data.shape, node.data.size, node.data.radialSegments ?? 24);\n\n if (primitive) {\n primitiveByMaterial.set(material.id, {\n indices: primitive.indices,\n material,\n normals: primitive.normals,\n positions: primitive.positions,\n uvs: primitive.uvs\n });\n }\n }\n\n return {\n primitives: Array.from(primitiveByMaterial.values())\n };\n}\n\nasync function buildGeometryLods(\n geometry: RuntimeGeometry,\n settings: SceneDocumentSnapshot[\"settings\"][\"world\"][\"lod\"]\n): Promise<RuntimeGeometryLod[] | undefined> {\n if (!geometry.primitives.length) {\n return undefined;\n }\n\n const midGeometry = simplifyExportGeometry(geometry, settings.midDetailRatio);\n const lowGeometry = simplifyExportGeometry(geometry, settings.lowDetailRatio);\n const lods: RuntimeGeometryLod[] = [];\n\n if (midGeometry) {\n lods.push({\n geometry: midGeometry,\n level: \"mid\"\n });\n }\n\n if (lowGeometry) {\n lods.push({\n geometry: lowGeometry,\n level: \"low\"\n });\n }\n\n return lods.length ? lods : undefined;\n}\n\nasync function buildModelLods(\n name: string,\n asset: Asset | undefined,\n nodeId: string,\n settings: SceneDocumentSnapshot[\"settings\"][\"world\"][\"lod\"]\n): Promise<{ assets: Asset[]; lods?: RuntimeModelLod[] }> {\n if (!asset?.path) {\n return { assets: [], lods: undefined };\n }\n\n const source = await loadModelSceneForLodBake(asset);\n const bakedLevels: Array<{ asset: Asset; level: RuntimeModelLod[\"level\"] }> = [];\n\n for (const [level, ratio] of [\n [\"mid\", settings.midDetailRatio],\n [\"low\", settings.lowDetailRatio]\n ] as const) {\n const simplified = simplifyModelSceneForRatio(source, ratio);\n\n if (!simplified) {\n continue;\n }\n\n const bytes = await exportModelSceneAsGlb(simplified);\n bakedLevels.push({\n asset: createGeneratedModelLodAsset(asset, name, nodeId, level, bytes),\n level\n });\n }\n\n return {\n assets: bakedLevels.map((entry) => entry.asset),\n lods: bakedLevels.length\n ? bakedLevels.map((entry) => ({\n assetId: entry.asset.id,\n level: entry.level\n }))\n : undefined\n };\n}\n\nasync function loadModelSceneForLodBake(asset: Asset) {\n const format = resolveModelAssetFormat(asset);\n\n if (format === \"obj\") {\n const objLoader = new OBJLoader();\n const texturePath = readModelAssetString(asset, \"texturePath\");\n const resolvedTexturePath = typeof texturePath === \"string\" && texturePath.length > 0 ? texturePath : undefined;\n const mtlText = readModelAssetString(asset, \"materialMtlText\");\n\n if (mtlText) {\n const materialCreator = mtlLoader.parse(patchMtlTextureReferences(mtlText, resolvedTexturePath), \"\");\n materialCreator.preload();\n objLoader.setMaterials(materialCreator);\n } else {\n objLoader.setMaterials(undefined as never);\n }\n\n const object = await objLoader.loadAsync(asset.path);\n\n if (!mtlText && resolvedTexturePath) {\n const texture = await modelTextureLoader.loadAsync(resolvedTexturePath);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.colorSpace = SRGBColorSpace;\n\n object.traverse((child: Object3D) => {\n if (child instanceof Mesh) {\n child.material = new MeshStandardMaterial({\n map: texture,\n metalness: 0.12,\n roughness: 0.76\n });\n }\n });\n }\n\n return object;\n }\n\n return (await gltfLoader.loadAsync(asset.path)).scene;\n}\n\nfunction simplifyModelSceneForRatio(source: Object3D, ratio: number) {\n if (ratio >= 0.98) {\n return undefined;\n }\n\n const simplifiedRoot = source.clone(true);\n expandGroupedModelMeshesForLodBake(simplifiedRoot);\n let simplifiedMeshCount = 0;\n\n simplifiedRoot.traverse((child: Object3D) => {\n if (!(child instanceof Mesh)) {\n return;\n }\n\n if (\"isSkinnedMesh\" in child && child.isSkinnedMesh) {\n return;\n }\n\n const simplifiedGeometry = simplifyModelGeometry(child.geometry, ratio);\n\n if (!simplifiedGeometry) {\n return;\n }\n\n child.geometry = simplifiedGeometry;\n simplifiedMeshCount += 1;\n });\n\n return simplifiedMeshCount > 0 ? simplifiedRoot : undefined;\n}\n\nfunction expandGroupedModelMeshesForLodBake(root: Object3D) {\n const replacements: Array<{ container: Group; mesh: Mesh; parent: Object3D }> = [];\n\n root.traverse((child: Object3D) => {\n if (!(child instanceof Mesh) || !Array.isArray(child.material) || child.geometry.groups.length <= 1 || !child.parent) {\n return;\n }\n\n const container = new Group();\n container.name = child.name ? `${child.name}:lod-groups` : \"lod-groups\";\n container.position.copy(child.position);\n container.quaternion.copy(child.quaternion);\n container.scale.copy(child.scale);\n container.visible = child.visible;\n container.renderOrder = child.renderOrder;\n container.userData = structuredClone(child.userData ?? {});\n\n child.geometry.groups.forEach((group: { count: number; materialIndex: number; start: number }, groupIndex: number) => {\n const material = child.material[group.materialIndex] ?? child.material[0];\n\n if (!material) {\n return;\n }\n\n const partGeometry = extractGeometryGroup(child.geometry, group.start, group.count);\n const partMesh = new Mesh(partGeometry, material);\n partMesh.name = child.name ? `${child.name}:group:${groupIndex}` : `group:${groupIndex}`;\n partMesh.castShadow = child.castShadow;\n partMesh.receiveShadow = child.receiveShadow;\n partMesh.userData = structuredClone(child.userData ?? {});\n container.add(partMesh);\n });\n\n replacements.push({\n container,\n mesh: child,\n parent: child.parent\n });\n });\n\n replacements.forEach(({ container, mesh, parent }) => {\n parent.add(container);\n parent.remove(mesh);\n });\n}\n\nfunction extractGeometryGroup(geometry: BufferGeometry, start: number, count: number) {\n const groupGeometry = new BufferGeometry();\n const index = geometry.getIndex();\n const attributes = geometry.attributes;\n\n Object.entries(attributes).forEach(([name, attribute]) => {\n groupGeometry.setAttribute(name, attribute);\n });\n\n if (index) {\n groupGeometry.setIndex(Array.from(index.array as ArrayLike<number>).slice(start, start + count));\n } else {\n groupGeometry.setIndex(Array.from({ length: count }, (_, offset) => start + offset));\n }\n\n groupGeometry.computeBoundingBox();\n groupGeometry.computeBoundingSphere();\n return groupGeometry;\n}\n\nfunction simplifyModelGeometry(geometry: BufferGeometry, ratio: number) {\n const positionAttribute = geometry.getAttribute(\"position\");\n const vertexCount = positionAttribute?.count ?? 0;\n\n if (!positionAttribute || vertexCount < 12 || ratio >= 0.98) {\n return undefined;\n }\n\n const workingGeometry = geometry.getAttribute(\"normal\") ? geometry : geometry.clone();\n\n if (!workingGeometry.getAttribute(\"normal\")) {\n workingGeometry.computeVertexNormals();\n }\n\n workingGeometry.computeBoundingBox();\n const bounds = workingGeometry.boundingBox?.clone();\n\n if (!bounds) {\n if (workingGeometry !== geometry) {\n workingGeometry.dispose();\n }\n return undefined;\n }\n\n const normalAttribute = workingGeometry.getAttribute(\"normal\");\n const uvAttribute = workingGeometry.getAttribute(\"uv\");\n const index = workingGeometry.getIndex();\n const simplified = simplifyPrimitiveWithVertexClustering(\n {\n indices: index ? Array.from(index.array as ArrayLike<number>) : Array.from({ length: vertexCount }, (_, value) => value),\n material: {\n color: \"#ffffff\",\n id: \"material:model-simplify\",\n metallicFactor: 0,\n name: \"Model Simplify\",\n roughnessFactor: 1\n },\n normals: Array.from(normalAttribute.array as ArrayLike<number>),\n positions: Array.from(positionAttribute.array as ArrayLike<number>),\n uvs: uvAttribute ? Array.from(uvAttribute.array as ArrayLike<number>) : []\n },\n ratio,\n bounds\n );\n\n if (workingGeometry !== geometry) {\n workingGeometry.dispose();\n }\n\n if (!simplified) {\n return undefined;\n }\n\n const simplifiedGeometry = createBufferGeometryFromPrimitive(simplified);\n simplifiedGeometry.computeBoundingBox();\n simplifiedGeometry.computeBoundingSphere();\n return simplifiedGeometry;\n}\n\nasync function exportModelSceneAsGlb(object: Object3D) {\n try {\n return await exportGlbBytesFromObject(object);\n } catch {\n return await exportGlbBytesFromObject(stripTextureReferencesFromObject(object.clone(true)));\n }\n}\n\nasync function exportGlbBytesFromObject(object: Object3D) {\n const scene = new Scene();\n scene.add(object);\n const exported = await gltfExporter.parseAsync(scene, {\n binary: true,\n includeCustomExtensions: false\n });\n\n if (!(exported instanceof ArrayBuffer)) {\n throw new Error(\"Expected GLB binary output for baked model LOD.\");\n }\n\n return new Uint8Array(exported);\n}\n\nfunction stripTextureReferencesFromObject(object: Object3D) {\n object.traverse((child: Object3D) => {\n if (!(child instanceof Mesh)) {\n return;\n }\n\n const strip = (material: MeshStandardMaterial) => {\n const clone = material.clone();\n clone.alphaMap = null;\n clone.aoMap = null;\n clone.bumpMap = null;\n clone.displacementMap = null;\n clone.emissiveMap = null;\n clone.lightMap = null;\n clone.map = null;\n clone.metalnessMap = null;\n clone.normalMap = null;\n clone.roughnessMap = null;\n return clone;\n };\n\n if (Array.isArray(child.material)) {\n child.material = child.material.map((material: any) =>\n material instanceof MeshStandardMaterial\n ? strip(material)\n : new MeshStandardMaterial({\n color: \"color\" in material ? material.color : \"#7f8ea3\",\n metalness: \"metalness\" in material && typeof material.metalness === \"number\" ? material.metalness : 0.1,\n roughness: \"roughness\" in material && typeof material.roughness === \"number\" ? material.roughness : 0.8\n })\n );\n return;\n }\n\n const fallbackMaterial = child.material as any;\n\n child.material = child.material instanceof MeshStandardMaterial\n ? strip(child.material)\n : new MeshStandardMaterial({\n color: \"color\" in fallbackMaterial ? fallbackMaterial.color : \"#7f8ea3\",\n metalness: \"metalness\" in fallbackMaterial && typeof fallbackMaterial.metalness === \"number\" ? fallbackMaterial.metalness : 0.1,\n roughness: \"roughness\" in fallbackMaterial && typeof fallbackMaterial.roughness === \"number\" ? fallbackMaterial.roughness : 0.8\n });\n });\n\n return object;\n}\n\nfunction createGeneratedModelLodAsset(\n asset: Asset,\n name: string,\n nodeId: string,\n level: RuntimeModelLod[\"level\"],\n bytes: Uint8Array\n): Asset {\n return {\n id: `asset:model-lod:${slugify(`${name}-${nodeId}`)}:${level}`,\n metadata: {\n ...asset.metadata,\n lodGenerated: true,\n lodLevel: level,\n lodSourceAssetId: asset.id,\n materialMtlText: \"\",\n modelFormat: \"glb\",\n texturePath: \"\"\n },\n path: createBinaryDataUrl(bytes, \"model/gltf-binary\"),\n type: \"model\"\n };\n}\n\nfunction createBinaryDataUrl(bytes: Uint8Array, mimeType: string) {\n let binary = \"\";\n const chunkSize = 0x8000;\n\n for (let index = 0; index < bytes.length; index += chunkSize) {\n binary += String.fromCharCode(...bytes.subarray(index, index + chunkSize));\n }\n\n return `data:${mimeType};base64,${btoa(binary)}`;\n}\n\nfunction sanitizeInstanceTransform(transform: SceneDocumentSnapshot[\"nodes\"][number][\"transform\"]) {\n return {\n position: structuredClone(transform.position),\n rotation: structuredClone(transform.rotation),\n scale: structuredClone(transform.scale)\n };\n}\n\nfunction resolveModelAssetFormat(asset: Asset) {\n const format = readModelAssetString(asset, \"modelFormat\")?.toLowerCase();\n return format === \"obj\" || asset.path.toLowerCase().endsWith(\".obj\") ? \"obj\" : \"gltf\";\n}\n\nfunction readModelAssetString(asset: Asset | undefined, key: string) {\n const value = asset?.metadata[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction patchMtlTextureReferences(mtlText: string, texturePath?: string) {\n if (!texturePath) {\n return mtlText;\n }\n\n const mapPattern = /^(map_Ka|map_Kd|map_d|map_Bump|bump)\\s+.+$/gm;\n const hasDiffuseMap = /^map_Kd\\s+.+$/m.test(mtlText);\n const normalized = mtlText.replace(mapPattern, (line) => {\n if (line.startsWith(\"map_Kd \")) {\n return `map_Kd ${texturePath}`;\n }\n\n return line;\n });\n\n return hasDiffuseMap ? normalized : `${normalized.trim()}\\nmap_Kd ${texturePath}\\n`;\n}\n\nfunction slugify(value: string) {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n\n return normalized || \"model\";\n}\n\nfunction simplifyExportGeometry(geometry: RuntimeGeometry, ratio: number): RuntimeGeometry | undefined {\n const primitives = geometry.primitives\n .map((primitive) => simplifyExportPrimitive(primitive, ratio))\n .filter((primitive): primitive is RuntimeGeometry[\"primitives\"][number] => primitive !== undefined);\n\n return primitives.length ? { primitives } : undefined;\n}\n\nfunction simplifyExportPrimitive(\n primitive: RuntimeGeometry[\"primitives\"][number],\n ratio: number\n): RuntimeGeometry[\"primitives\"][number] | undefined {\n const vertexCount = Math.floor(primitive.positions.length / 3);\n const triangleCount = Math.floor(primitive.indices.length / 3);\n\n if (vertexCount < 12 || triangleCount < 8 || ratio >= 0.98) {\n return undefined;\n }\n\n const geometry = createBufferGeometryFromPrimitive(primitive);\n const boundsTree = new MeshBVH(geometry, { maxLeafSize: 12, setBoundingBox: true });\n const bounds = boundsTree.getBoundingBox(new Box3());\n const simplified = simplifyPrimitiveWithVertexClustering(primitive, ratio, bounds);\n\n geometry.dispose();\n\n if (!simplified) {\n return undefined;\n }\n\n return simplified;\n}\n\nfunction createBufferGeometryFromPrimitive(primitive: RuntimeGeometry[\"primitives\"][number]) {\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n geometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length) {\n geometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n geometry.setIndex(primitive.indices);\n return geometry;\n}\n\nfunction simplifyPrimitiveWithVertexClustering(\n primitive: RuntimeGeometry[\"primitives\"][number],\n ratio: number,\n bounds: Box3\n): RuntimeGeometry[\"primitives\"][number] | undefined {\n const targetVertexCount = Math.max(8, Math.floor((primitive.positions.length / 3) * Math.max(0.04, ratio)));\n const size = bounds.getSize(new Vector3());\n let resolution = Math.max(1, Math.round(Math.cbrt(targetVertexCount)));\n let best: RuntimeGeometry[\"primitives\"][number] | undefined;\n\n for (let attempt = 0; attempt < 5; attempt += 1) {\n const simplified = clusterPrimitiveVertices(primitive, bounds, size, Math.max(1, resolution - attempt));\n\n if (!simplified) {\n continue;\n }\n\n best = simplified;\n\n if ((simplified.positions.length / 3) <= targetVertexCount) {\n break;\n }\n }\n\n if (!best) {\n return undefined;\n }\n\n if (best.positions.length >= primitive.positions.length || best.indices.length >= primitive.indices.length) {\n return undefined;\n }\n\n return best;\n}\n\nfunction clusterPrimitiveVertices(\n primitive: RuntimeGeometry[\"primitives\"][number],\n bounds: Box3,\n size: Vector3,\n resolution: number\n): RuntimeGeometry[\"primitives\"][number] | undefined {\n const min = bounds.min;\n const cellSizeX = Math.max(size.x / resolution, 0.0001);\n const cellSizeY = Math.max(size.y / resolution, 0.0001);\n const cellSizeZ = Math.max(size.z / resolution, 0.0001);\n const vertexCount = primitive.positions.length / 3;\n const clusters = new Map<string, {\n count: number;\n normalX: number;\n normalY: number;\n normalZ: number;\n positionX: number;\n positionY: number;\n positionZ: number;\n uvX: number;\n uvY: number;\n }>();\n const clusterKeyByVertex = new Array<string>(vertexCount);\n\n for (let vertexIndex = 0; vertexIndex < vertexCount; vertexIndex += 1) {\n const positionOffset = vertexIndex * 3;\n const uvOffset = vertexIndex * 2;\n const x = primitive.positions[positionOffset];\n const y = primitive.positions[positionOffset + 1];\n const z = primitive.positions[positionOffset + 2];\n const normalX = primitive.normals[positionOffset];\n const normalY = primitive.normals[positionOffset + 1];\n const normalZ = primitive.normals[positionOffset + 2];\n const cellX = Math.floor((x - min.x) / cellSizeX);\n const cellY = Math.floor((y - min.y) / cellSizeY);\n const cellZ = Math.floor((z - min.z) / cellSizeZ);\n const clusterKey = `${cellX}:${cellY}:${cellZ}:${resolveNormalBucket(normalX, normalY, normalZ)}`;\n const cluster = clusters.get(clusterKey) ?? {\n count: 0,\n normalX: 0,\n normalY: 0,\n normalZ: 0,\n positionX: 0,\n positionY: 0,\n positionZ: 0,\n uvX: 0,\n uvY: 0\n };\n\n cluster.count += 1;\n cluster.positionX += x;\n cluster.positionY += y;\n cluster.positionZ += z;\n cluster.normalX += normalX;\n cluster.normalY += normalY;\n cluster.normalZ += normalZ;\n cluster.uvX += primitive.uvs[uvOffset] ?? 0;\n cluster.uvY += primitive.uvs[uvOffset + 1] ?? 0;\n clusters.set(clusterKey, cluster);\n clusterKeyByVertex[vertexIndex] = clusterKey;\n }\n\n const remappedIndices: number[] = [];\n const positions: number[] = [];\n const normals: number[] = [];\n const uvs: number[] = [];\n const clusterIndexByKey = new Map<string, number>();\n\n const ensureClusterIndex = (clusterKey: string) => {\n const existing = clusterIndexByKey.get(clusterKey);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const cluster = clusters.get(clusterKey);\n\n if (!cluster || cluster.count === 0) {\n return undefined;\n }\n\n const averagedNormal = normalizeVec3(vec3(cluster.normalX, cluster.normalY, cluster.normalZ));\n const index = positions.length / 3;\n\n positions.push(cluster.positionX / cluster.count, cluster.positionY / cluster.count, cluster.positionZ / cluster.count);\n normals.push(averagedNormal.x, averagedNormal.y, averagedNormal.z);\n uvs.push(cluster.uvX / cluster.count, cluster.uvY / cluster.count);\n clusterIndexByKey.set(clusterKey, index);\n return index;\n };\n\n for (let index = 0; index < primitive.indices.length; index += 3) {\n const a = ensureClusterIndex(clusterKeyByVertex[primitive.indices[index]]);\n const b = ensureClusterIndex(clusterKeyByVertex[primitive.indices[index + 1]]);\n const c = ensureClusterIndex(clusterKeyByVertex[primitive.indices[index + 2]]);\n\n if (a === undefined || b === undefined || c === undefined) {\n continue;\n }\n\n if (a === b || b === c || a === c) {\n continue;\n }\n\n if (triangleArea(positions, a, b, c) <= 0.000001) {\n continue;\n }\n\n remappedIndices.push(a, b, c);\n }\n\n if (remappedIndices.length < 12 || positions.length >= primitive.positions.length) {\n return undefined;\n }\n\n return {\n indices: remappedIndices,\n material: primitive.material,\n normals,\n positions,\n uvs\n };\n}\n\nfunction resolveNormalBucket(x: number, y: number, z: number) {\n const ax = Math.abs(x);\n const ay = Math.abs(y);\n const az = Math.abs(z);\n\n if (ax >= ay && ax >= az) {\n return x >= 0 ? \"xp\" : \"xn\";\n }\n\n if (ay >= ax && ay >= az) {\n return y >= 0 ? \"yp\" : \"yn\";\n }\n\n return z >= 0 ? \"zp\" : \"zn\";\n}\n\nfunction triangleArea(positions: number[], a: number, b: number, c: number) {\n const ax = positions[a * 3];\n const ay = positions[a * 3 + 1];\n const az = positions[a * 3 + 2];\n const bx = positions[b * 3];\n const by = positions[b * 3 + 1];\n const bz = positions[b * 3 + 2];\n const cx = positions[c * 3];\n const cy = positions[c * 3 + 1];\n const cz = positions[c * 3 + 2];\n const ab = vec3(bx - ax, by - ay, bz - az);\n const ac = vec3(cx - ax, cy - ay, cz - az);\n const cross = crossVec3(ab, ac);\n\n return Math.sqrt(cross.x * cross.x + cross.y * cross.y + cross.z * cross.z) * 0.5;\n}\n\nfunction buildPrimitiveGeometry(shape: \"cone\" | \"cube\" | \"cylinder\" | \"sphere\", size: Vec3, radialSegments: number) {\n const geometry =\n shape === \"cube\"\n ? new BoxGeometry(Math.abs(size.x), Math.abs(size.y), Math.abs(size.z))\n : shape === \"sphere\"\n ? new SphereGeometry(Math.max(Math.abs(size.x), Math.abs(size.z)) * 0.5, radialSegments, Math.max(8, Math.floor(radialSegments * 0.75)))\n : shape === \"cylinder\"\n ? new CylinderGeometry(Math.max(Math.abs(size.x), Math.abs(size.z)) * 0.5, Math.max(Math.abs(size.x), Math.abs(size.z)) * 0.5, Math.abs(size.y), radialSegments)\n : new ConeGeometry(Math.max(Math.abs(size.x), Math.abs(size.z)) * 0.5, Math.abs(size.y), radialSegments);\n const positionAttribute = geometry.getAttribute(\"position\");\n const normalAttribute = geometry.getAttribute(\"normal\");\n const uvAttribute = geometry.getAttribute(\"uv\");\n const index = geometry.getIndex();\n\n const primitive = {\n indices: index ? Array.from(index.array as ArrayLike<number>) : Array.from({ length: positionAttribute.count }, (_, value) => value),\n normals: Array.from(normalAttribute.array as ArrayLike<number>),\n positions: Array.from(positionAttribute.array as ArrayLike<number>),\n uvs: uvAttribute ? Array.from(uvAttribute.array as ArrayLike<number>) : []\n };\n\n geometry.dispose();\n return primitive;\n}\n\nasync function resolveRuntimeMaterial(material?: Material): Promise<RuntimeMaterial> {\n const resolved = material ?? {\n color: \"#ffffff\",\n id: \"material:fallback:default\",\n metalness: 0.05,\n name: \"Default Material\",\n roughness: 0.8\n };\n\n return {\n baseColorTexture: await resolveEmbeddedTextureUri(resolved.colorTexture ?? resolveGeneratedBlockoutTexture(resolved)),\n color: resolved.color,\n id: resolved.id,\n metallicFactor: resolved.metalness ?? 0,\n metallicRoughnessTexture: await createMetallicRoughnessTextureDataUri(\n resolved.metalnessTexture,\n resolved.roughnessTexture,\n resolved.metalness ?? 0,\n resolved.roughness ?? 0.8\n ),\n name: resolved.name,\n normalTexture: await resolveEmbeddedTextureUri(resolved.normalTexture),\n roughnessFactor: resolved.roughness ?? 0.8,\n side: resolved.side\n };\n}\n\nfunction resolveGeneratedBlockoutTexture(material: Material) {\n return material.category === \"blockout\"\n ? createBlockoutTextureDataUri(material.color, material.edgeColor ?? \"#2f3540\", material.edgeThickness ?? 0.035)\n : undefined;\n}\n\nfunction projectPlanarUvs(vertices: Vec3[], normal: Vec3, uvScale?: Vec2, uvOffset?: Vec2) {\n const basis = createFacePlaneBasis(normal);\n const origin = vertices[0] ?? vec3(0, 0, 0);\n const scaleX = Math.abs(uvScale?.x ?? 1) <= 0.0001 ? 1 : uvScale?.x ?? 1;\n const scaleY = Math.abs(uvScale?.y ?? 1) <= 0.0001 ? 1 : uvScale?.y ?? 1;\n const offsetX = uvOffset?.x ?? 0;\n const offsetY = uvOffset?.y ?? 0;\n\n return vertices.flatMap((vertex) => {\n const offset = subVec3(vertex, origin);\n return [dotVec3(offset, basis.u) * scaleX + offsetX, dotVec3(offset, basis.v) * scaleY + offsetY];\n });\n}\n\nfunction createFacePlaneBasis(normal: Vec3) {\n const normalizedNormal = normalizeVec3(normal);\n const reference = Math.abs(normalizedNormal.y) < 0.99 ? vec3(0, 1, 0) : vec3(1, 0, 0);\n const u = normalizeVec3(crossVec3(reference, normalizedNormal));\n const v = normalizeVec3(crossVec3(normalizedNormal, u));\n\n return { u, v };\n}\n\nasync function resolveEmbeddedTextureUri(source?: string) {\n if (!source) {\n return undefined;\n }\n\n if (source.startsWith(\"data:\")) {\n return source;\n }\n\n const response = await fetch(source);\n const blob = await response.blob();\n const buffer = await blob.arrayBuffer();\n return `data:${blob.type || \"application/octet-stream\"};base64,${toBase64(new Uint8Array(buffer))}`;\n}\n\nasync function createMetallicRoughnessTextureDataUri(\n metalnessSource: string | undefined,\n roughnessSource: string | undefined,\n metalnessFactor: number,\n roughnessFactor: number\n) {\n if (!metalnessSource && !roughnessSource) {\n return undefined;\n }\n\n if (typeof OffscreenCanvas === \"undefined\" || typeof createImageBitmap === \"undefined\") {\n return undefined;\n }\n\n const [metalness, roughness] = await Promise.all([\n loadImagePixels(metalnessSource),\n loadImagePixels(roughnessSource)\n ]);\n const width = Math.max(metalness?.width ?? 1, roughness?.width ?? 1);\n const height = Math.max(metalness?.height ?? 1, roughness?.height ?? 1);\n const canvas = new OffscreenCanvas(width, height);\n const context = canvas.getContext(\"2d\");\n\n if (!context) {\n return undefined;\n }\n\n const imageData = context.createImageData(width, height);\n const metalDefault = Math.round(clamp01(metalnessFactor) * 255);\n const roughDefault = Math.round(clamp01(roughnessFactor) * 255);\n\n for (let index = 0; index < imageData.data.length; index += 4) {\n imageData.data[index] = 0;\n imageData.data[index + 1] = roughness?.pixels[index] ?? roughDefault;\n imageData.data[index + 2] = metalness?.pixels[index] ?? metalDefault;\n imageData.data[index + 3] = 255;\n }\n\n context.putImageData(imageData, 0, 0);\n const blob = await canvas.convertToBlob({ type: \"image/png\" });\n const buffer = await blob.arrayBuffer();\n return `data:image/png;base64,${toBase64(new Uint8Array(buffer))}`;\n}\n\nasync function loadImagePixels(source?: string) {\n if (!source || typeof OffscreenCanvas === \"undefined\" || typeof createImageBitmap === \"undefined\") {\n return undefined;\n }\n\n const response = await fetch(source);\n const blob = await response.blob();\n const bitmap = await createImageBitmap(blob);\n const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);\n const context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\n if (!context) {\n bitmap.close();\n return undefined;\n }\n\n context.drawImage(bitmap, 0, 0);\n bitmap.close();\n const imageData = context.getImageData(0, 0, bitmap.width, bitmap.height);\n\n return {\n height: imageData.height,\n pixels: imageData.data,\n width: imageData.width\n };\n}\n\nfunction clamp01(value: number) {\n return Math.max(0, Math.min(1, value));\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n bytes.forEach((byte) => {\n binary += String.fromCharCode(byte);\n });\n return btoa(binary);\n}\n","import {\n createWebHammerEngineBundleZip as packWebHammerEngineBundle,\n externalizeWebHammerEngineScene as externalizeWebHammerEngineSceneAssets,\n parseWebHammerEngineBundleZip as unpackWebHammerEngineBundle\n} from \"@ggez/runtime-build\";\nimport type { RuntimeBundle, WebHammerEngineBundle } from \"@ggez/runtime-format\";\n\nexport {\n buildRuntimeBundle,\n buildRuntimeScene,\n buildRuntimeWorldIndex,\n externalizeRuntimeAssets,\n packRuntimeBundle,\n unpackRuntimeBundle\n} from \"@ggez/runtime-build\";\n\nexport function createThreeAssetResolver(bundle: RuntimeBundle) {\n const urlByPath = new Map<string, string>();\n\n return {\n dispose() {\n urlByPath.forEach((url) => {\n URL.revokeObjectURL(url);\n });\n urlByPath.clear();\n },\n resolve(path: string) {\n const existing = urlByPath.get(path);\n\n if (existing) {\n return existing;\n }\n\n const file = bundle.files.find((entry) => entry.path === path);\n\n if (!file) {\n return path;\n }\n\n const bytes = new Uint8Array(file.bytes.byteLength);\n bytes.set(file.bytes);\n const url = URL.createObjectURL(new Blob([bytes.buffer], { type: file.mimeType }));\n urlByPath.set(path, url);\n return url;\n }\n };\n}\n\nexport function createWebHammerBundleAssetResolver(bundle: WebHammerEngineBundle) {\n return createThreeAssetResolver(bundle);\n}\n\nexport function createWebHammerEngineBundleZip(bundle: WebHammerEngineBundle, options?: Parameters<typeof packWebHammerEngineBundle>[1]) {\n return packWebHammerEngineBundle(bundle, options);\n}\n\nexport function parseWebHammerEngineBundleZip(bundleBytes: Uint8Array, options?: Parameters<typeof unpackWebHammerEngineBundle>[1]) {\n return unpackWebHammerEngineBundle(bundleBytes, options);\n}\n\nexport function externalizeWebHammerEngineScene(\n scene: WebHammerEngineBundle[\"manifest\"],\n options?: Parameters<typeof externalizeWebHammerEngineSceneAssets>[1]\n) {\n return externalizeWebHammerEngineSceneAssets(scene, options);\n}\n"],"mappings":";AAkBA,SAAS,OAAO,SAAS,YAAY,eAAe;AAM7C,SAAS,6BAA6B,OAAe,YAAY,WAAW,gBAAgB,OAAe;AAChH,QAAM,OAAO;AACb,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,aAAa,CAAC,CAAC;AACvE,QAAM,aAAa,QAAQ;AAC3B,QAAM,YAAY,aAAa;AAC/B,QAAM,SAAS;AACf,QAAM,YAAY,aAAa,WAAW,WAAW,IAAI;AACzD,QAAM,aAAa,aAAa,WAAW,OAAO,IAAI;AACtD,QAAM,cAAc,aAAa,WAAW,OAAO,IAAI;AACvD,QAAM,MAAM;AAAA,qDACuC,IAAI,aAAa,IAAI,kBAAkB,IAAI,IAAI,IAAI;AAAA,qBACnF,IAAI,aAAa,IAAI,SAAS,MAAM,WAAW,KAAK;AAAA,iBACxD,QAAQ,CAAC,QAAQ,QAAQ,CAAC,YAAY,OAAO,KAAK,aAAa,OAAO,KAAK,SAAS,SAAS,CAAC,yBAAyB,UAAU,mBAAmB,KAAK;AAAA,iBACzJ,UAAU,QAAQ,UAAU,YAAY,OAAO,aAAa,CAAC,aAAa,OAAO,aAAa,CAAC,SAAS,SAAS,CAAC,yBAAyB,SAAS;AAAA,iBACpJ,SAAS,QAAQ,SAAS,YAAY,OAAO,YAAY,CAAC,aAAa,OAAO,YAAY,CAAC,SAAS,SAAS,CAAC,yBAAyB,WAAW;AAAA,mBAChJ,UAAU,IAAI,OAAO,IAAI,MAAM,OAAO,UAAU,aAAa,SAAS;AAAA,mBACtE,OAAO,IAAI,IAAI,UAAU,MAAM,OAAO,UAAU,aAAa,SAAS;AAAA;AAAA,IAErF,KAAK;AAEP,SAAO,oCAAoC,mBAAmB,GAAG,CAAC;AACpE;AAEO,SAAS,KAAK,GAAW,GAAW,GAAiB;AAC1D,SAAO,EAAE,GAAG,GAAG,EAAE;AACnB;AAEA,SAAS,aAAa,MAAc,OAAe,GAAW;AAC5D,QAAM,iBAAiB,aAAa,IAAI;AACxC,QAAM,kBAAkB,aAAa,KAAK;AAC1C,QAAM,YAAY,OAAO,SAAS,eAAe,MAAM,CAAC,GAAG,EAAE;AAC7D,QAAM,aAAa,OAAO,SAAS,gBAAgB,MAAM,CAAC,GAAG,EAAE;AAC/D,QAAM,WAAW,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU;AACzC,UAAM,cAAe,aAAa,QAAS;AAC3C,UAAM,eAAgB,cAAc,QAAS;AAC7C,WAAO,KAAK,MAAM,eAAe,eAAe,eAAe,CAAC,EAC7D,SAAS,EAAE,EACX,SAAS,GAAG,GAAG;AAAA,EACpB,CAAC;AAED,SAAO,IAAI,SAAS,KAAK,EAAE,CAAC;AAC9B;AAEA,SAAS,aAAa,OAAe;AACnC,MAAI,kBAAkB,KAAK,KAAK,GAAG;AACjC,WAAO;AAAA,EACT;AAEA,MAAI,kBAAkB,KAAK,KAAK,GAAG;AACjC,WAAO,IAAI,MACR,MAAM,CAAC,EACP,MAAM,EAAE,EACR,IAAI,CAAC,YAAY,GAAG,OAAO,GAAG,OAAO,EAAE,EACvC,KAAK,EAAE,CAAC;AAAA,EACb;AAEA,SAAO;AACT;AAMO,SAAS,QAAQ,MAAY,OAAmB;AACrD,SAAO,KAAK,KAAK,IAAI,MAAM,GAAG,KAAK,IAAI,MAAM,GAAG,KAAK,IAAI,MAAM,CAAC;AAClE;AAEO,SAAS,QAAQ,MAAY,OAAmB;AACrD,SAAO,KAAK,KAAK,IAAI,MAAM,GAAG,KAAK,IAAI,MAAM,GAAG,KAAK,IAAI,MAAM,CAAC;AAClE;AAEO,SAAS,UAAU,QAAc,QAAsB;AAC5D,SAAO,KAAK,OAAO,IAAI,QAAQ,OAAO,IAAI,QAAQ,OAAO,IAAI,MAAM;AACrE;AAEO,SAAS,QAAQ,MAAY,OAAqB;AACvD,SAAO,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;AAC9D;AAEO,SAAS,UAAU,MAAY,OAAmB;AACvD,SAAO;AAAA,IACL,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;AAAA,IAClC,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;AAAA,IAClC,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM;AAAA,EACpC;AACF;AAEO,SAAS,WAAW,QAAsB;AAC/C,SAAO,KAAK,KAAK,QAAQ,QAAQ,MAAM,CAAC;AAC1C;AAEO,SAAS,cAAc,QAAc,UAAU,MAAgB;AACpE,QAAM,SAAS,WAAW,MAAM;AAEhC,MAAI,UAAU,SAAS;AACrB,WAAO,KAAK,GAAG,GAAG,CAAC;AAAA,EACrB;AAEA,SAAO,UAAU,QAAQ,IAAI,MAAM;AACrC;AAEO,SAAS,YAAY,SAAuB;AACjD,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,KAAK,GAAG,GAAG,CAAC;AAAA,EACrB;AAEA,QAAM,QAAQ,QAAQ,OAAO,CAAC,KAAK,WAAW,QAAQ,KAAK,MAAM,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;AAEjF,SAAO,UAAU,OAAO,IAAI,QAAQ,MAAM;AAC5C;AAuCA,IAAM,eAAe,IAAI,QAAQ;AACjC,IAAM,iBAAiB,IAAI,WAAW;AACtC,IAAM,YAAY,IAAI,QAAQ;AAEvB,SAAS,kBAAkB,QAAmB,OAA6B;AAChF,QAAM,SAAS,kBAAkB,MAAM,EAAE,SAAS,kBAAkB,KAAK,CAAC;AAC1E,SAAO,kBAAkB,QAAQ,MAAM,KAAK;AAC9C;AAWO,SAAS,kBACd,OACA,WAAoE,CAAC,GAC/C;AACtB,QAAM,WAAW,MAAM,KAAK,KAAK;AACjC,QAAM,aAAa,MAAM,KAAK,QAAQ;AACtC,QAAM,YAAY,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AACjE,QAAM,sBAAsB,oBAAI,IAAuB;AACvD,QAAM,wBAAwB,oBAAI,IAA6B;AAC/D,QAAM,yBAAyB,oBAAI,IAAsB;AACzD,QAAM,2BAA2B,oBAAI,IAA4B;AACjE,QAAM,cAAwB,CAAC;AAC/B,QAAM,gBAAgC,CAAC;AACvC,QAAM,YAAY,oBAAI,IAAY;AAElC,QAAM,kBAAkB,CAAC,UAAkB,YAAoB;AAC7D,UAAM,WAAW,uBAAuB,IAAI,QAAQ;AAEpD,QAAI,UAAU;AACZ,eAAS,KAAK,OAAO;AACrB;AAAA,IACF;AAEA,2BAAuB,IAAI,UAAU,CAAC,OAAO,CAAC;AAAA,EAChD;AAEA,QAAM,oBAAoB,CAAC,UAAkB,YAA0B;AACrE,UAAM,WAAW,yBAAyB,IAAI,QAAQ;AAEtD,QAAI,UAAU;AACZ,eAAS,KAAK,OAAO;AACrB;AAAA,IACF;AAEA,6BAAyB,IAAI,UAAU,CAAC,OAAO,CAAC;AAAA,EAClD;AAEA,QAAM,uBAAuB,CAAC,SAAyE;AACrG,UAAM,SAAS,oBAAoB,IAAI,KAAK,EAAE;AAE9C,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,QAAI,UAAU,IAAI,KAAK,EAAE,GAAG;AAC1B,YAAM,WAAW,gBAAgB,KAAK,SAAS;AAC/C,0BAAoB,IAAI,KAAK,IAAI,QAAQ;AACzC,aAAO;AAAA,IACT;AAEA,cAAU,IAAI,KAAK,EAAE;AAErB,UAAM,SACJ,KAAK,YAAY,KAAK,aAAa,KAAK,KACpC,UAAU,IAAI,KAAK,QAAQ,IAC3B;AACN,UAAM,WAAW,SACb,kBAAkB,qBAAqB,MAAM,GAAG,KAAK,SAAS,IAC9D,gBAAgB,KAAK,SAAS;AAElC,wBAAoB,IAAI,KAAK,IAAI,QAAQ;AACzC,cAAU,OAAO,KAAK,EAAE;AACxB,WAAO;AAAA,EACT;AAEA,WAAS,QAAQ,CAAC,SAAS;AACzB,yBAAqB,IAAI;AAEzB,UAAM,iBAAiB;AAAA,MACrB,KAAK,YACL,KAAK,aAAa,KAAK,MACvB,UAAU,IAAI,KAAK,QAAQ;AAAA,IAC7B;AAEA,QAAI,gBAAgB;AAClB,sBAAgB,KAAK,UAAW,KAAK,EAAE;AACvC;AAAA,IACF;AAEA,gBAAY,KAAK,KAAK,EAAE;AAAA,EAC1B,CAAC;AAED,aAAW,QAAQ,CAAC,WAAW;AAC7B,UAAM,SACJ,OAAO,YAAY,UAAU,IAAI,OAAO,QAAQ,IAC5C,UAAU,IAAI,OAAO,QAAQ,IAC7B;AAEN,0BAAsB;AAAA,MACpB,OAAO;AAAA,MACP,SAAS,kBAAkB,qBAAqB,MAAM,GAAG,OAAO,SAAS,IAAI,gBAAgB,OAAO,SAAS;AAAA,IAC/G;AAEA,QAAI,QAAQ;AACV,wBAAkB,OAAO,IAAI,OAAO,EAAE;AACtC;AAAA,IACF;AAEA,kBAAc,KAAK,OAAO,EAAE;AAAA,EAC9B,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAoJO,SAAS,YAAY,MAAuC;AACjE,SAAO,KAAK,SAAS;AACvB;AAEO,SAAS,WAAW,MAAsC;AAC/D,SAAO,KAAK,SAAS;AACvB;AAEO,SAAS,YAAY,MAAuC;AACjE,SAAO,KAAK,SAAS;AACvB;AAEO,SAAS,YAAY,MAAuC;AACjE,SAAO,KAAK,SAAS;AACvB;AAEO,SAAS,gBAAgB,MAA2C;AACzE,SAAO,KAAK,SAAS;AACvB;AAEO,SAAS,iBAAiB,MAA4C;AAC3E,SAAO,KAAK,SAAS;AACvB;AAMO,SAAS,uBAAuB,MAA8E;AACnH,SAAO,YAAY,IAAI,KAAK,WAAW,IAAI,KAAK,gBAAgB,IAAI,KAAK,YAAY,IAAI;AAC3F;AAEO,SAAS,4BACd,OACA,UACA,WAAW,IACX;AACA,QAAM,YAAY,IAAI,IAAI,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAU,CAAC;AAC/E,MAAI,UAAU,OAAO,aAAa,WAAW,UAAU,IAAI,QAAQ,IAAI;AACvE,MAAI,QAAQ;AAEZ,SAAO,WAAW,SAAS,UAAU;AACnC,QAAI,uBAAuB,OAAO,GAAG;AACnC,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,iBAAiB,OAAO,GAAG;AAC9B,aAAO;AAAA,IACT;AAEA,cAAU,UAAU,IAAI,QAAQ,KAAK,YAAY;AACjD,aAAS;AAAA,EACX;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,WAAsB;AAC/C,SAAO,IAAI,QAAQ,EAAE;AAAA,IACnB,IAAI,QAAQ,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,CAAC;AAAA,IAC5E,IAAI,WAAW,EAAE,aAAa,IAAI,MAAM,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,KAAK,CAAC;AAAA,IAChH,IAAI,QAAQ,UAAU,MAAM,GAAG,UAAU,MAAM,GAAG,UAAU,MAAM,CAAC;AAAA,EACrE;AACF;AAEA,SAAS,kBAAkB,QAAiB,OAAyB;AACnE,SAAO,UAAU,cAAc,gBAAgB,SAAS;AACxD,QAAM,WAAW,IAAI,MAAM,EAAE,kBAAkB,gBAAgB,KAAK;AAEpE,SAAO;AAAA,IACL,OAAO,QAAQ,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI;AAAA,IACjD,UAAU,KAAK,aAAa,GAAG,aAAa,GAAG,aAAa,CAAC;AAAA,IAC7D,UAAU,KAAK,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAAA,IACjD,OAAO,KAAK,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAAA,EACnD;AACF;;;ACxgBA;AAAA,EACE,gBAAAA;AAAA,EACA,YAAAC;AAAA,EACA,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,EACA,oBAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA,SAAAC;AAAA,EACA;AAAA,EACA,0BAAAC;AAAA,EACA,aAAAC;AAAA,EACA,SAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,mBAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC;AAAA,EACA,QAAAC;AAAA,EACA,wBAAAC;AAAA,EACA,YAAAC;AAAA,EACA,cAAAC;AAAA,EACA,cAAAC;AAAA,EACA,kBAAAC;AAAA,EAEA,aAAAC;AAAA,EAEA,iBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,WAAAC;AAAA,OACK;AACP,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,aAAAC,kBAAiB;;;ACrBnB,IAAM,uBAAuB;AAC7B,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;;;ACKlC,SAAS,eAAe,OAAuC;AACpE,SAAO,qBAAqB,KAAK,EAAE;AACrC;AAEO,SAAS,qBAAqB,OAAuD;AAC1F,QAAM,SAAmB,CAAC;AAE1B,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO,QAAQ,kCAAkC;AAAA,EACnD;AAEA,QAAM,YAAY;AAElB,MAAI,UAAU,UAAU,WAAW,sBAAsB;AACvD,WAAO,KAAK,0CAA0C,oBAAoB,IAAI;AAAA,EAChF;AAEA,MAAI,OAAO,UAAU,UAAU,YAAY,UAAU;AACnD,WAAO,KAAK,kDAAkD;AAAA,EAChE,WAAW,UAAU,SAAS,UAAU,2BAA2B;AACjE,WAAO,KAAK,6CAA6C,yBAAyB,GAAG;AAAA,EACvF;AAEA,MAAI,CAAC,MAAM,QAAQ,UAAU,KAAK,GAAG;AACnC,WAAO,KAAK,uCAAuC;AAAA,EACrD;AAEA,MAAI,CAAC,MAAM,QAAQ,UAAU,MAAM,GAAG;AACpC,WAAO,KAAK,wCAAwC;AAAA,EACtD;AAEA,MAAI,CAAC,MAAM,QAAQ,UAAU,SAAS,GAAG;AACvC,WAAO,KAAK,2CAA2C;AAAA,EACzD;AAEA,MAAI,CAAC,MAAM,QAAQ,UAAU,QAAQ,GAAG;AACtC,WAAO,KAAK,0CAA0C;AAAA,EACxD;AAEA,MAAI,CAAC,MAAM,QAAQ,UAAU,MAAM,GAAG;AACpC,WAAO,KAAK,wCAAwC;AAAA,EACtD;AAEA,MAAI,CAAC,UAAU,YAAY,OAAO,UAAU,aAAa,UAAU;AACjE,WAAO,KAAK,2CAA2C;AAAA,EACzD;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO;AAAA,MACL;AAAA,MACA,IAAI;AAAA,IACN;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ,CAAC;AAAA,IACT,IAAI;AAAA,IACJ,OAAO;AAAA,EACT;AACF;AAEO,SAAS,oBAAoB,OAAmC;AACrE,QAAM,WAAW,gBAAgB,KAAK;AAEtC,WAAS,WAAW;AAAA,IAClB,GAAG,SAAS;AAAA,IACZ,QAAQ;AAAA,IACR,SAAS;AAAA,EACX;AAEA,SAAO;AACT;AAEO,SAAS,kBAAkB,MAA4B;AAC5D,QAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAM,aAAa,qBAAqB,MAAM;AAE9C,MAAI,CAAC,WAAW,IAAI;AAClB,UAAM,IAAI,MAAM,WAAW,OAAO,KAAK,GAAG,CAAC;AAAA,EAC7C;AAEA,SAAO,oBAAoB,WAAW,KAAK;AAC7C;AAEO,SAAS,gBAAgB,OAAwC;AACtE,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,YAAY;AAClB,SAAO,MAAM,QAAQ,UAAU,KAAK,KAAK,eAAe,UAAU,QAAQ;AAC5E;AAoGA,SAAS,QAAQ,SAAiD;AAChE,SAAO;AAAA,IACL,QAAQ,CAAC,OAAO;AAAA,IAChB,IAAI;AAAA,EACN;AACF;;;ACzNA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA,WAAAC;AAAA,OACK;AACP,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AA2C1B,IAAM,gBAAgB,IAAI,cAAc;AACxC,IAAM,aAAa,IAAI,WAAW;AAClC,IAAM,YAAY,IAAI,UAAU;AAChC,IAAM,qBAAqB,IAAI,cAAc;AAC7C,IAAM,0BAA0B,IAAIF,SAAQ;AAC5C,IAAM,uBAAuB,IAAIA,SAAQ;AACzC,IAAM,kBAAkB,IAAIA,SAAQ;AACpC,IAAM,uBAAuB,IAAIE,SAAQ;AACzC,IAAM,yBAAyB,IAAID,YAAW;AAC9C,IAAM,oBAAoB,IAAIC,SAAQ;AAO/B,SAAS,kCACd,aACA,UAA8C,CAAC,GAClB;AAC7B,QAAM,YAAkD;AAAA,IACtD,YAAY,IAAI,IAAI,YAAY,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAAA,IACxE,eAAe,oBAAI,IAAI;AAAA,IACvB,oBAAoB,oBAAI,IAAI;AAAA,IAC5B,cAAc,oBAAI,IAAI;AAAA,EACxB;AAEA,SAAO;AAAA,IACL,yBAAyB,MAAM,wBAAwB,aAAa,WAAW,OAAO;AAAA,IACtF,kBAAkB,CAAC,MAAM,cAAc,oBAAoB,MAAM,WAAW,SAAS,SAAS;AAAA,EAChG;AACF;AAEO,IAAM,kCAAkC;AAE/C,eAAe,oBACb,MACA,WACA,SACA,WACA;AACA,QAAM,SAAS,IAAI,MAAM;AACzB,QAAM,UAAU,IAAI,MAAM;AAC1B,QAAM,YAAY,WAAW,aAAa,KAAK;AAC/C,QAAM,QAAQ,UAAU;AAExB,SAAO,OAAO,KAAK;AACnB,iBAAe,QAAQ,SAAS;AAChC,SAAO,SAAS,YAAY;AAAA,IAC1B,MAAM,KAAK;AAAA,IACX,OAAO,KAAK;AAAA,IACZ,IAAI,KAAK;AAAA,IACT,MAAM,KAAK;AAAA,IACX,UAAU,KAAK;AAAA,IACf,MAAM,KAAK;AAAA,EACb;AAEA,MAAI,OAAO;AACT,YAAQ,SAAS,IAAI,CAAC,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC;AAAA,EACnD;AAEA,SAAO,IAAI,OAAO;AAElB,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,QAAQ,iBAAiB,IAAI;AAEnC,QAAI,OAAO;AACT,cAAQ,IAAI,KAAK;AAAA,IACnB;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,SAAS,SAAS;AACzB,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,SAAS,cAAc;AAC9B,WAAO,UAAU;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,SAAS,SAAS;AACzB,UAAM,cAAc,MAAM,kBAAkB,MAAM,WAAW,OAAO;AACpE,UAAMC,aAAY,MAAM,4BAA4B,MAAM,aAAa,WAAW,OAAO;AACzF,YAAQ,IAAIA,cAAa,WAAW;AACpC,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,+BAA+B,MAAM,WAAW,OAAO;AAE/E,MAAI,WAAW;AACb,YAAQ,IAAI,SAAS;AAAA,EACvB;AAEA,SAAO;AACT;AAEA,eAAe,wBACb,aACA,WACA,SACA;AACA,QAAM,aAAa,kBAAkB,YAAY,KAAK;AACtD,QAAM,UAAU,oBAAI,IAAyE;AAE7F,cAAY,MAAM,QAAQ,CAAC,SAAS;AAClC,QAAI,KAAK,SAAS,cAAc;AAC9B;AAAA,IACF;AAEA,UAAM,aAAa,4BAA4B,YAAY,OAAO,KAAK,KAAK,YAAY;AAExF,QAAI,CAAC,YAAY;AACf;AAAA,IACF;AAEA,UAAM,YAAY,QAAQ,IAAI,WAAW,EAAE;AAE3C,QAAI,WAAW;AACb,gBAAU,KAAK,IAAI;AACnB;AAAA,IACF;AAEA,YAAQ,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC;AAAA,EACnC,CAAC;AAED,QAAM,UAAsB,CAAC;AAE7B,aAAW,CAAC,cAAc,SAAS,KAAK,SAAS;AAC/C,UAAM,aAAa,4BAA4B,YAAY,OAAO,YAAY;AAE9E,QAAI,CAAC,YAAY;AACf;AAAA,IACF;AAEA,UAAM,qBAAqB,YAAY,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,WAAW,EAAE;AAErF,QAAI,CAAC,sBAAsB,mBAAmB,SAAS,WAAW,mBAAmB,SAAS,gBAAgB,mBAAmB,SAAS,SAAS;AACjJ;AAAA,IACF;AAEA,UAAM,SACJ,mBAAmB,SAAS,UACxB,MAAM,kCAAkC,oBAAoB,WAAW,YAAY,WAAW,OAAO,IACrG,MAAM,qCAAqC,oBAAoB,WAAW,YAAY,WAAW,OAAO;AAE9G,QAAI,QAAQ;AACV,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAe,qCACb,YACA,WACA,YACA,WACA,SACA;AACA,QAAM,YAAY,MAAM,8BAA8B,WAAW,UAAU,YAAY,WAAW,YAAY,WAAW,OAAO;AAChI,QAAM,aAAa,uBAAuB,QAAQ,GAAG;AAErD,MAAI,CAAC,cAAc,CAAC,WAAW,MAAM,QAAQ;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,IAAI;AACpB,MAAI,OAAO,GAAG,WAAW,IAAI;AAC7B,MAAI,aAAa;AACjB,MAAI,SAAS,WAAW,CAAC;AAEzB,aAAW,SAAS,WAAW,MAAM;AACnC,UAAM,aAAa,MAAM;AAAA,MACvB,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,WAAW,MAAM,UAAU,QAAQ,WAAW,cAAc,WAAW;AAC7E,QAAI,SAAS,YAAY,QAAQ;AAAA,EACnC;AAEA,MAAI,SAAS,YAAY;AAAA,IACvB,iBAAiB,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,IACxD,YAAY,CAAC,QAAQ,IAAI,WAAW,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IAC3E,cAAc,WAAW;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,eAAe,8BACb,UACA,YACA,WACA,YACA,WACA,SACA,UACA;AACA,QAAM,QAAQ,IAAI,MAAM;AACxB,QAAM,QAAQ,WAAW,UAAU,SAAS,KAAK,GAAG,GAAG,CAAC;AAExD,aAAW,aAAa,SAAS,YAAY;AAC3C,UAAM,oBAAoB,IAAI,eAAe;AAC7C,sBAAkB,aAAa,YAAY,IAAI,uBAAuB,UAAU,WAAW,CAAC,CAAC;AAC7F,sBAAkB,aAAa,UAAU,IAAI,uBAAuB,UAAU,SAAS,CAAC,CAAC;AAEzF,QAAI,UAAU,IAAI,SAAS,GAAG;AAC5B,wBAAkB,aAAa,MAAM,IAAI,uBAAuB,UAAU,KAAK,CAAC,CAAC;AAAA,IACnF;AAEA,sBAAkB,SAAS,UAAU,OAAO;AAC5C,sBAAkB,mBAAmB;AACrC,sBAAkB,sBAAsB;AAExC,UAAM,WAAW,MAAM,oBAAoB,UAAU,UAAU,WAAW,OAAO;AACjF,UAAM,OAAO,IAAI,cAAc,mBAAmB,UAAU,UAAU,MAAM;AAC5E,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,OAAO,GAAG,WAAW,IAAI,IAAI,UAAU,SAAS,MAAM,IAAI,UAAU,SAAS,IAAI;AACtF,SAAK,SAAS,YAAY;AAAA,MACxB,iBAAiB,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,MACxD,UAAU,UAAU,SAAS;AAAA,MAC7B,YAAY,UAAU,SAAS;AAAA,MAC/B,cAAc,WAAW;AAAA,IAC3B;AAEA,cAAU,QAAQ,CAAC,UAAU,UAAU;AACrC,YAAM,iBAAiB,WAAW,oBAAoB,IAAI,SAAS,EAAE,KAAK,SAAS;AACnF,WAAK,YAAY,OAAO,8BAA8B,gBAAgB,KAAK,CAAC;AAAA,IAC9E,CAAC;AAED,SAAK,eAAe,cAAc;AAClC,UAAM,IAAI,IAAI;AAAA,EAChB;AAEA,QAAM,OAAO,GAAG,WAAW,IAAI;AAC/B,QAAM,SAAS,YAAY;AAAA,IACzB,iBAAiB,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,IACxD,cAAc,WAAW;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,eAAe,kCACb,YACA,WACA,YACA,WACA,SACA;AACA,QAAM,YAAY,MAAM,2BAA2B,YAAY,WAAW,YAAY,WAAW,OAAO;AACxG,QAAM,aAAa,uBAAuB,QAAQ,GAAG;AAErD,MAAI,CAAC,cAAc,CAAC,WAAW,MAAM,QAAQ;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,IAAI;AACpB,MAAI,OAAO,GAAG,WAAW,IAAI;AAC7B,MAAI,aAAa;AACjB,MAAI,SAAS,WAAW,CAAC;AAEzB,aAAW,SAAS,WAAW,MAAM;AACnC,UAAM,aAAa,MAAM,2BAA2B,YAAY,WAAW,YAAY,WAAW,SAAS,KAAK;AAChH,UAAM,WAAW,MAAM,UAAU,QAAQ,WAAW,cAAc,WAAW;AAC7E,QAAI,SAAS,YAAY,QAAQ;AAAA,EACnC;AAEA,MAAI,SAAS,YAAY;AAAA,IACvB,iBAAiB,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,IACxD,YAAY,CAAC,QAAQ,IAAI,WAAW,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IAC3E,cAAc,WAAW;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,eAAe,2BACb,YACA,WACA,YACA,WACA,SACA,UACA;AACA,QAAM,QAAQ,IAAI,MAAM;AACxB,QAAM,WAAW,MAAM,kBAAkB,sBAAsB,YAAY,UAAU,YAAY,QAAQ,GAAG,SAAS,SAAS;AAC9H,QAAM,0BAA0B,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AACvE,MAAI,iBAAiB;AAErB,WAAS,kBAAkB,IAAI;AAE/B,WAAS,SAAS,CAAC,UAAU;AAC3B,QAAI,EAAE,iBAAiB,SAAS,EAAE,MAAM,oBAAoB,iBAAiB;AAC3E;AAAA,IACF;AAEA,UAAM,gBAAgB,IAAI,cAAc,MAAM,UAAU,MAAM,UAAU,UAAU,MAAM;AACxF,kBAAc,aAAa,QAAQ,cAAc;AACjD,kBAAc,gBAAgB,QAAQ,iBAAiB;AACvD,kBAAc,OAAO,GAAG,WAAW,IAAI,IAAI,UAAU,SAAS,MAAM,IAAI,MAAM,QAAQ,cAAc;AACpG,kBAAc,SAAS,YAAY;AAAA,MACjC,iBAAiB;AAAA,MACjB,UAAU,UAAU,SAAS;AAAA,MAC7B;AAAA,MACA,cAAc,WAAW;AAAA,IAC3B;AAEA,yBAAqB,KAAK,MAAM,WAAW;AAE3C,cAAU,QAAQ,CAAC,UAAU,UAAU;AACrC,YAAM,iBAAiB,WAAW,oBAAoB,IAAI,SAAS,EAAE,KAAK,SAAS;AACnF,8BAAwB,KAAK,uBAAuB,cAAc,CAAC,EAAE,SAAS,oBAAoB;AAClG,oBAAc,YAAY,OAAO,uBAAuB;AAAA,IAC1D,CAAC;AAED,kBAAc,eAAe,cAAc;AAC3C,UAAM,IAAI,aAAa;AACvB,sBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,OAAO,GAAG,WAAW,IAAI;AAC/B,QAAM,SAAS,YAAY;AAAA,IACzB,iBAAiB;AAAA,IACjB,cAAc,WAAW;AAAA,EAC3B;AACA,SAAO;AACT;AAEA,eAAe,+BACb,MACA,WACA,SACA;AACA,QAAM,YAAY,MAAM,qBAAqB,KAAK,UAAU,MAAM,WAAW,OAAO;AACpF,QAAM,aAAa,uBAAuB,QAAQ,GAAG;AAErD,MAAI,CAAC,cAAc,CAAC,KAAK,MAAM,QAAQ;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,IAAI;AACpB,MAAI,OAAO,GAAG,KAAK,IAAI;AACvB,MAAI,aAAa;AACjB,MAAI,SAAS,WAAW,CAAC;AAEzB,aAAW,SAAS,KAAK,MAAM;AAC7B,UAAM,aAAa,MAAM,qBAAqB,MAAM,UAAU,MAAM,WAAW,SAAS,KAAK;AAC7F,UAAM,WAAW,MAAM,UAAU,QAAQ,WAAW,cAAc,WAAW;AAC7E,QAAI,SAAS,YAAY,QAAQ;AAAA,EACnC;AAEA,MAAI,SAAS,YAAY;AAAA,IACvB,YAAY,CAAC,QAAQ,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IACrE,QAAQ,KAAK;AAAA,EACf;AACA,SAAO;AACT;AAEA,eAAe,4BACb,MACA,WACA,WACA,SACA;AACA,QAAM,aAAa,uBAAuB,QAAQ,GAAG;AAErD,MAAI,CAAC,cAAc,CAAC,KAAK,MAAM,QAAQ;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,IAAI;AACpB,MAAI,OAAO,GAAG,KAAK,IAAI;AACvB,MAAI,aAAa;AACjB,MAAI,SAAS,WAAW,CAAC;AAEzB,aAAW,SAAS,KAAK,MAAM;AAC7B,UAAM,aAAa,MAAM,kBAAkB,MAAM,WAAW,SAAS,KAAK;AAC1E,UAAM,WAAW,MAAM,UAAU,QAAQ,WAAW,cAAc,WAAW;AAC7E,QAAI,SAAS,YAAY,QAAQ;AAAA,EACnC;AAEA,MAAI,SAAS,YAAY;AAAA,IACvB,YAAY,CAAC,QAAQ,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC;AAAA,IACrE,QAAQ,KAAK;AAAA,EACf;AACA,SAAO;AACT;AAEA,eAAe,qBACb,UACA,MACA,WACA,SACA,UACA;AACA,QAAM,QAAQ,IAAI,MAAM;AACxB,QAAM,SAAiB,CAAC;AAExB,aAAW,aAAa,SAAS,YAAY;AAC3C,UAAM,oBAAoB,IAAI,eAAe;AAC7C,sBAAkB,aAAa,YAAY,IAAI,uBAAuB,UAAU,WAAW,CAAC,CAAC;AAC7F,sBAAkB,aAAa,UAAU,IAAI,uBAAuB,UAAU,SAAS,CAAC,CAAC;AAEzF,QAAI,UAAU,IAAI,SAAS,GAAG;AAC5B,wBAAkB,aAAa,MAAM,IAAI,uBAAuB,UAAU,KAAK,CAAC,CAAC;AAAA,IACnF;AAEA,sBAAkB,SAAS,UAAU,OAAO;AAC5C,sBAAkB,mBAAmB;AACrC,sBAAkB,sBAAsB;AAExC,UAAM,WAAW,MAAM,oBAAoB,UAAU,UAAU,WAAW,OAAO;AACjF,UAAM,OAAO,IAAI,KAAK,mBAAmB,QAAQ;AAEjD,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,OAAO,GAAG,KAAK,IAAI,IAAI,UAAU,SAAS,MAAM,IAAI,UAAU,SAAS,IAAI;AAChF,SAAK,SAAS,YAAY;AAAA,MACxB,UAAU,UAAU,SAAS;AAAA,MAC7B,YAAY,UAAU,SAAS;AAAA,MAC/B,QAAQ,KAAK;AAAA,IACf;AAEA,WAAO,KAAK,IAAI;AAAA,EAClB;AAEA,SAAO,QAAQ,CAAC,SAAS;AACvB,UAAM,IAAI,IAAI;AAAA,EAChB,CAAC;AAED,SAAO;AACT;AAEA,eAAe,oBACb,cACA,WACA,SACA;AACA,QAAM,SAAS,UAAU,cAAc,IAAI,aAAa,EAAE;AAE1D,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,IAAI,qBAAqB;AAAA,IACxC,OAAO,aAAa;AAAA,IACpB,WAAW,aAAa;AAAA,IACxB,WAAW,aAAa;AAAA,IACxB,MAAM,oBAAoB,aAAa,IAAI;AAAA,EAC7C,CAAC;AAED,MAAI,aAAa,kBAAkB;AACjC,UAAM,UAAU,MAAM,YAAY,aAAa,kBAAkB,cAAc,oBAAoB,WAAW,OAAO;AACrH,YAAQ,aAAa;AACrB,aAAS,MAAM;AAAA,EACjB;AAEA,MAAI,aAAa,eAAe;AAC9B,aAAS,YAAY,MAAM,YAAY,aAAa,eAAe,cAAc,iBAAiB,WAAW,OAAO;AAAA,EACtH;AAEA,MAAI,aAAa,0BAA0B;AACzC,UAAM,aAAa,MAAM;AAAA,MACvB,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,aAAS,eAAe;AACxB,aAAS,eAAe;AAAA,EAC1B;AAEA,WAAS,OAAO,aAAa;AAC7B,WAAS,cAAc;AACvB,YAAU,cAAc,IAAI,aAAa,IAAI,QAAQ;AAErD,SAAO;AACT;AAEA,eAAe,YACb,MACA,UACA,MACA,WACA,SACA;AACA,QAAM,eAAe,QAAQ,kBACzB,MAAM,QAAQ,gBAAgB;AAAA,IAC5B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC,IACD;AACJ,QAAM,WAAW,GAAG,IAAI,IAAI,YAAY;AACxC,QAAM,SAAS,UAAU,aAAa,IAAI,QAAQ;AAElD,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,cAAc,UAAU,YAAY;AAC3D,QAAM,oBAAoB,eAAe,KAAK,CAAC,YAAY;AACzD,YAAQ,QAAQ;AAChB,YAAQ,QAAQ;AAChB,WAAO;AAAA,EACT,CAAC;AACD,YAAU,aAAa,IAAI,UAAU,iBAAiB;AACtD,SAAO;AACT;AAEA,eAAe,kBACb,MACA,WACA,SACA,UACA;AACA,QAAM,WAAW,MAAM,kBAAkB,sBAAsB,MAAM,UAAU,YAAY,QAAQ,GAAG,SAAS,SAAS;AACxH,QAAM,QAAQ,SAAS,MAAM,IAAI;AAEjC,QAAM,OAAO,GAAG,KAAK,IAAI,IAAI,UAAU,SAAS,MAAM;AACtD,QAAM,SAAS,YAAY;AAAA,IACzB,GAAI,MAAM,SAAS,aAAa,CAAC;AAAA,IACjC,UAAU,UAAU,SAAS;AAAA,IAC7B,QAAQ,KAAK;AAAA,EACf;AACA,QAAM,SAAS,CAAC,UAAU;AACxB,QAAI,iBAAiB,MAAM;AACzB,YAAM,aAAa,QAAQ,cAAc;AACzC,YAAM,gBAAgB,QAAQ,iBAAiB;AAAA,IACjD;AAAA,EACF,CAAC;AAED,SAAO;AACT;AAEA,SAAS,sBACP,MACA,YACA,UACgB;AAChB,QAAM,QAAQ,WAAW,WAAW,IAAI,SAAS,OAAO,IAAI,WAAW,IAAI,KAAK,KAAK,OAAO;AAC5F,QAAM,YAAY,OAAO,QAAQ,KAAK,KAAK;AAE3C,SAAO;AAAA,IACL;AAAA,IACA,SAAS,OAAO,OAAO,WAAW,SAAS,UAAU,KAAK,KAAK;AAAA,IAC/D,QAAQ,cAAc,OAAO,cAAc;AAAA,IAC3C,cAAc,GAAG,KAAK,IAAI,IAAI,UAAU,SAAS,MAAM;AAAA,IACvD,QAAQ,mBAAmB,OAAO,SAAS,aAAa,SAAS;AAAA,IACjE;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,aAAa,gBAAgB,OAAO,aAAa;AAAA,EACnD;AACF;AAEA,eAAe,kBACb,WACA,SACA,WACA;AACA,MAAI,CAAC,UAAU,WAAW;AACxB,WAAO,2BAA2B,UAAU,OAAO,UAAU,YAAY;AAAA,EAC3E;AAEA,QAAM,eAAe,QAAQ,kBACzB,MAAM,QAAQ,gBAAgB;AAAA,IAC5B,OAAO,UAAU;AAAA,IACjB,QAAQ,UAAU;AAAA,IAClB,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,MAAM;AAAA,QACJ,SAAS,UAAU,WAAW;AAAA,QAC9B,MAAM,UAAU;AAAA,MAClB;AAAA,MACA,IAAI,UAAU;AAAA,MACd,MAAM;AAAA,MACN,MAAM,UAAU;AAAA,MAChB,WAAW;AAAA,QACT,UAAU,KAAK,GAAG,GAAG,CAAC;AAAA,QACtB,UAAU,KAAK,GAAG,GAAG,CAAC;AAAA,QACtB,OAAO,KAAK,GAAG,GAAG,CAAC;AAAA,MACrB;AAAA,IACF;AAAA,IACA,MAAM,UAAU;AAAA,EAClB,CAAC,IACD,UAAU;AACd,QAAM,sBACJ,UAAU,eAAe,QAAQ,kBAC7B,MAAM,QAAQ,gBAAgB;AAAA,IAC5B,MAAM;AAAA,IACN,UAAU;AAAA,MACR,OAAO;AAAA,MACP,IAAI,0BAA0B,UAAU,MAAM;AAAA,MAC9C,gBAAgB;AAAA,MAChB,MAAM,GAAG,UAAU,QAAQ;AAAA,MAC3B,iBAAiB;AAAA,IACnB;AAAA,IACA,MAAM,UAAU;AAAA,IAChB,MAAM;AAAA,EACR,CAAC,IACD,UAAU;AAChB,QAAM,WAAW,GAAG,UAAU,MAAM,IAAI,YAAY,IAAI,uBAAuB,EAAE,IAAI,gBAAgB,UAAU,OAAO,iBAAiB,KAAK,EAAE;AAC9I,QAAM,SAAS,UAAU,mBAAmB,IAAI,QAAQ;AAExD,MAAI,QAAQ;AACV,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,YAAY;AAC3B,QAAI;AACF,YAAM,SACJ,UAAU,WAAW,QACjB,MAAM,aAAa,UAAU,OAAO,cAAc,mBAAmB,IACrE,MAAM,cAAc,UAAU,OAAO,YAAY;AACvD,mBAAa,QAAQ,UAAU,MAAM;AACrC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,2BAA2B,UAAU,OAAO,UAAU,YAAY;AAAA,IAC3E;AAAA,EACF,GAAG;AAEH,YAAU,mBAAmB,IAAI,UAAU,OAAO;AAClD,SAAO;AACT;AAEA,eAAe,aAAa,OAA0B,cAAsB,qBAA8B;AACxG,QAAM,YAAY,IAAI,UAAU;AAChC,QAAM,UAAU,gBAAgB,OAAO,iBAAiB;AAExD,MAAI,SAAS;AACX,UAAM,kBAAkB,UAAU,MAAM,0BAA0B,SAAS,mBAAmB,GAAG,EAAE;AACnG,oBAAgB,QAAQ;AACxB,cAAU,aAAa,eAAe;AAAA,EACxC;AAEA,QAAM,SAAS,MAAM,UAAU,UAAU,YAAY;AAErD,MAAI,CAAC,WAAW,qBAAqB;AACnC,UAAM,UAAU,MAAM,iBAAiB,mBAAmB;AAE1D,WAAO,SAAS,CAAC,UAAoB;AACnC,UAAI,iBAAiB,MAAM;AACzB,cAAM,WAAW,IAAI,qBAAqB;AAAA,UACxC,KAAK;AAAA,UACL,WAAW;AAAA,UACX,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,eAAe,cAAc,OAA0B,cAAsB;AAC3E,QAAM,OAAO,MAAM,WAAW,UAAU,YAAY;AACpD,QAAM,SAAS,KAAK;AACpB,SAAO,SAAS,YAAY;AAAA,IAC1B,GAAI,OAAO,SAAS,aAAa,CAAC;AAAA,IAClC,YAAY,KAAK;AAAA,IACjB,cAAc,cAAc,OAAO,cAAc;AAAA,EACnD;AACA,SAAO;AACT;AAEA,eAAe,iBAAiB,MAAc;AAC5C,QAAM,UAAU,MAAM,mBAAmB,UAAU,IAAI;AACvD,UAAQ,QAAQ;AAChB,UAAQ,QAAQ;AAChB,UAAQ,aAAa;AACrB,SAAO;AACT;AAEA,SAAS,aAAa,QAAkB,QAA0B;AAChE,QAAM,iBAAiB,UAAU,oBAAoB,MAAM;AAC3D,SAAO,SAAS,IAAI,CAAC,eAAe,GAAG,CAAC,eAAe,GAAG,CAAC,eAAe,CAAC;AAC7E;AAEA,SAAS,oBAAoB,QAAkB;AAC7C,QAAM,MAAM,IAAI,KAAK,EAAE,cAAc,MAAM;AAC3C,QAAM,SAAS,IAAI,UAAU,IAAID,SAAQ,CAAC;AAE1C,SAAO;AAAA,IACL,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,IACV,GAAG,OAAO;AAAA,EACZ;AACF;AAEA,SAAS,2BAA2B,OAA0B,OAAO,iBAAiB;AACpF,QAAM,eAAe,gBAAgB,OAAO,cAAc,KAAK;AAC/D,QAAM,OAAO,cAAc,OAAO,YAAY,KAAK,EAAE,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI;AAC5E,QAAM,WAAW,IAAI,YAAY,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AACvD,QAAM,WAAW,IAAI,qBAAqB;AAAA,IACxC,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AACD,QAAM,OAAO,IAAI,KAAK,UAAU,QAAQ;AAExC,OAAK,OAAO;AACZ,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAuD;AAC/E,MAAI,CAAC,KAAK,KAAK,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,UAAQ,KAAK,KAAK,MAAM;AAAA,IACtB,KAAK,WAAW;AACd,aAAO,IAAI,aAAa,KAAK,KAAK,OAAO,KAAK,KAAK,SAAS;AAAA,IAC9D;AAAA,IACA,KAAK,cAAc;AACjB,aAAO,IAAI,gBAAgB,KAAK,KAAK,OAAO,KAAK,KAAK,eAAe,WAAW,KAAK,KAAK,SAAS;AAAA,IACrG;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,QAAQ,IAAI,WAAW,KAAK,KAAK,OAAO,KAAK,KAAK,WAAW,KAAK,KAAK,YAAY,GAAG,KAAK,KAAK,SAAS,CAAC;AAChH,YAAM,aAAa,KAAK,KAAK;AAC7B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,eAAe;AAClB,YAAM,QAAQ,IAAI,MAAM;AACxB,YAAM,QAAQ,IAAI,iBAAiB,KAAK,KAAK,OAAO,KAAK,KAAK,SAAS;AACvE,YAAM,SAAS,IAAI,SAAS;AAC5B,YAAM,aAAa,KAAK,KAAK;AAC7B,aAAO,SAAS,IAAI,GAAG,GAAG,EAAE;AAC5B,YAAM,IAAI,MAAM;AAChB,YAAM,IAAI,KAAK;AACf,YAAM,SAAS;AACf,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,QAAQ,IAAI,MAAM;AACxB,YAAM,QAAQ,IAAI;AAAA,QAChB,KAAK,KAAK;AAAA,QACV,KAAK,KAAK;AAAA,QACV,KAAK,KAAK;AAAA,QACV,KAAK,KAAK;AAAA,QACV,KAAK,KAAK;AAAA,QACV,KAAK,KAAK;AAAA,MACZ;AACA,YAAM,SAAS,IAAI,SAAS;AAC5B,YAAM,aAAa,KAAK,KAAK;AAC7B,aAAO,SAAS,IAAI,GAAG,GAAG,EAAE;AAC5B,YAAM,IAAI,MAAM;AAChB,YAAM,IAAI,KAAK;AACf,YAAM,SAAS;AACf,aAAO;AAAA,IACT;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,eAAe,QAAkB,WAAsB;AAC9D,SAAO,SAAS,IAAI,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,CAAC;AACpF,SAAO,SAAS,IAAI,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,CAAC;AACpF,SAAO,MAAM,IAAI,UAAU,MAAM,GAAG,UAAU,MAAM,GAAG,UAAU,MAAM,CAAC;AAC1E;AAEA,SAAS,8BAA8B,WAAsB,OAAa;AACxE,SAAO,uBAAuB,SAAS,EAAE;AAAA,IACvC,gBAAgB,gBAAgB,CAAC,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC;AAAA,EAC9D;AACF;AAEA,SAAS,uBAAuB,WAAsB;AACpD,uBAAqB,IAAI,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,CAAC;AACzF,yBAAuB,aAAa,IAAIH,OAAM,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,UAAU,SAAS,GAAG,KAAK,CAAC;AACtH,oBAAkB,IAAI,UAAU,MAAM,GAAG,UAAU,MAAM,GAAG,UAAU,MAAM,CAAC;AAE7E,SAAO,IAAIC,SAAQ,EAAE,QAAQ,sBAAsB,wBAAwB,iBAAiB;AAC9F;AAEA,SAAS,uBAAuB,KAAsE;AACpG,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,KAAK,IAAI,GAAG,IAAI,WAAW;AAC/C,QAAM,cAAc,KAAK,IAAI,cAAc,MAAM,IAAI,WAAW;AAEhE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,MAAwC;AACnE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,mBAAmB,QAAiB,MAA+B;AAC1E,MAAI,OAAO,WAAW,YAAY,OAAO,YAAY,MAAM,OAAO;AAChE,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,YAAY,EAAE,SAAS,MAAM,IAAI,QAAQ;AACxD;AAEA,SAAS,gBAAgB,OAA0B,KAAa;AAC9D,QAAM,QAAQ,OAAO,SAAS,GAAG;AACjC,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEA,SAAS,cAAc,OAA0B,WAA0C;AACzF,QAAM,IAAI,OAAO,SAAS,GAAG,SAAS,GAAG;AACzC,QAAM,IAAI,OAAO,SAAS,GAAG,SAAS,GAAG;AACzC,QAAM,IAAI,OAAO,SAAS,GAAG,SAAS,GAAG;AAEzC,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AAC3E,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,GAAG,GAAG,EAAE;AACnB;AAEA,SAAS,0BAA0B,SAAiB,aAAsB;AACxE,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,aAAa;AACnB,QAAM,gBAAgB,iBAAiB,KAAK,OAAO;AACnD,QAAM,aAAa,QAAQ,QAAQ,YAAY,CAAC,SAAS;AACvD,QAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,aAAO,UAAU,WAAW;AAAA,IAC9B;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,gBACH,aACA,GAAG,WAAW,KAAK,CAAC;AAAA,SAAY,WAAW;AAAA;AACjD;AAEO,SAAS,eAAe,MAAoD;AACjF,MAAI,KAAK,SAAS,aAAa;AAC7B,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,MAAI,KAAK,SAAS,QAAQ;AACxB,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO;AACT;AAEO,SAAS,iBAAiB,QAAkB;AACjD,MAAI,aAAa,UAAU,OAAO,SAAS;AACzC,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,SAAS,KAAK,CAAC,UAAU,aAAa,SAAS,MAAM,OAAO;AAC5E;;;AH7zBA,IAAMI,iBAAgB,IAAIC,eAAc;AACxC,IAAMC,cAAa,IAAIC,YAAW;AAClC,IAAM,YAAY,IAAI,UAAU;AAChC,IAAMC,aAAY,IAAIC,WAAU;AAEzB,SAAS,uBAAuB,OAA+C;AACpF,SAAO,eAAe,KAAK;AAC7B;AAEO,SAAS,wBAAwB,OAAgD;AACtF,SAAO,gBAAgB,KAAK;AAC9B;AAEO,SAAS,0BAA0B,MAAoC;AAC5E,SAAO,kBAAkB,IAAI;AAC/B;AAEA,eAAsB,0BAA0B,KAAa,MAAmD;AAC9G,QAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AAEtC,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EAC3F;AAEA,SAAO,0BAA0B,MAAM,SAAS,KAAK,CAAC;AACxD;AAEA,eAAsB,gCACpB,OACA,UAAuC,CAAC,GACJ;AACpC,QAAM,cAAc,OAAO,UAAU,WAAW,kBAAkB,KAAK,IAAI,kBAAkB,KAAK,UAAU,KAAK,CAAC;AAClH,QAAM,OAAO,IAAIC,OAAM;AACvB,QAAM,YAAY,oBAAI,IAAsB;AAC5C,QAAM,SAAqB,CAAC;AAC5B,QAAM,qBAAsE,CAAC;AAC7E,QAAM,mBAAmB,IAAI,IAAI,YAAY,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AACjF,QAAM,aAAa,kBAAkB,YAAY,OAAO,YAAY,QAAQ;AAC5E,QAAM,gBAAgB,kCAAkC,aAAa,OAAO;AAC5E,QAAM,iBAAiB,MAAM,QAAQ;AAAA,IACnC,YAAY,MAAM,IAAI,OAAO,SAAS,CAAC,KAAK,IAAI,MAAM,cAAc,iBAAiB,IAAI,CAAC,CAAU;AAAA,EACtG;AACA,QAAM,kBAAkB,oBAAI,IAAY;AACxC,QAAM,cAAc,oBAAI,IAAY;AAEpC,OAAK,OAAO;AACZ,OAAK,SAAS,YAAY;AAAA,IACxB,UAAU,YAAY;AAAA,IACtB,UAAU,YAAY;AAAA,EACxB;AAEA,MAAI,QAAQ,cAAc;AACxB,UAAM,4BAA4B,QAAQ,cAAc,aAAa,OAAO;AAAA,EAC9E;AAEA,QAAM,eAAe,wBAAwB,WAAW;AAExD,MAAI,cAAc;AAChB,SAAK,IAAI,YAAY;AACrB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAEA,iBAAe,QAAQ,CAAC,CAAC,QAAQ,MAAM,MAAM;AAC3C,cAAU,IAAI,QAAQ,MAAM;AAAA,EAC9B,CAAC;AAED,QAAM,aAAa,CAAC,WAAmB;AACrC,QAAI,gBAAgB,IAAI,MAAM,GAAG;AAC/B;AAAA,IACF;AAEA,UAAM,OAAO,iBAAiB,IAAI,MAAM;AACxC,UAAM,SAAS,UAAU,IAAI,MAAM;AAEnC,QAAI,CAAC,QAAQ,CAAC,QAAQ;AACpB;AAAA,IACF;AAEA,QAAI,YAAY,IAAI,MAAM,GAAG;AAC3B,WAAK,IAAI,MAAM;AACf,sBAAgB,IAAI,MAAM;AAC1B;AAAA,IACF;AAEA,gBAAY,IAAI,MAAM;AAEtB,UAAM,eACJ,KAAK,YAAY,KAAK,aAAa,KAAK,KACpC,UAAU,IAAI,KAAK,QAAQ,IAC3B;AAEN,QAAI,gBAAgB,CAAC,YAAY,IAAI,KAAK,QAAS,GAAG;AACpD,iBAAW,KAAK,QAAS;AACzB,mBAAa,IAAI,MAAM;AAAA,IACzB,OAAO;AACL,WAAK,IAAI,MAAM;AAAA,IACjB;AAEA,gBAAY,OAAO,MAAM;AACzB,oBAAgB,IAAI,MAAM;AAAA,EAC5B;AAEA,aAAW,QAAQ,YAAY,OAAO;AACpC,eAAW,KAAK,EAAE;AAAA,EACpB;AAEA,QAAM,oBAAoB,MAAM,cAAc,wBAAwB;AAEtE,oBAAkB,QAAQ,CAAC,WAAW;AACpC,SAAK,IAAI,MAAM;AAAA,EACjB,CAAC;AAED,aAAW,QAAQ,YAAY,OAAO;AACpC,UAAM,SAAS,UAAU,IAAI,KAAK,EAAE;AAEpC,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,UAAM,QAAQ,iBAAqB,MAAM;AAEzC,QAAI,OAAO;AACT,aAAO,KAAK,KAAK;AAAA,IACnB;AAEA,UAAM,UAAU,eAAmB,IAAI;AAEvC,QAAI,SAAS,SAAS;AACpB,yBAAmB,KAAK;AAAA,QACtB,QAAQ,KAAK;AAAA,QACb;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU;AACR,uCAAiC,IAAI;AAAA,IACvC;AAAA,IACA,UAAU,YAAY,SAAS,IAAI,CAAC,YAAY;AAAA,MAC9C,GAAG;AAAA,MACH,WAAW,WAAW,sBAAsB,IAAI,OAAO,EAAE,KAAK,OAAO;AAAA,IACvE,EAAE;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT;AACF;AAEA,eAAsB,yBACpB,OACA,UAAuC,CAAC,GACT;AAC/B,QAAM,WAAW,MAAM,gCAAgC,OAAO,OAAO;AAErE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,SAAS;AAAA,IAChB,cAAc,SAAS;AAAA,EACzB;AACF;AAEA,eAAsB,gCACpB,KACA,UAAuC,CAAC,GACT;AAC/B,QAAM,QAAQ,MAAM,0BAA0B,GAAG;AACjD,SAAO,yBAAyB,OAAO,OAAO;AAChD;AAEA,eAAsB,qCACpB,KACA,UAAuC,CAAC,GACJ;AACpC,QAAM,QAAQ,MAAM,0BAA0B,GAAG;AACjD,SAAO,gCAAgC,OAAO,OAAO;AACvD;AAOA,IAAM,6BAA6B;AAEnC,eAAsB,4BACpB,QACA,aACA,UAAgE,CAAC,GACjE;AACA,QAAM,QAAQ,6BAA6B,MAAM;AACjD,QAAM,aAAa;AACnB,uBAAqB,QAAQ,KAAK;AAElC,QAAM,EAAE,UAAU,QAAQ,QAAQ,IAAI,YAAY,SAAS;AAC3D,SAAO,MAAM,SAAS,UAAU,IAAI,IAAI,IAAI,MAAM,QAAQ,GAAG,SAAS,MAAM,IAAI;AAEhF,QAAM,SAAS,YAAY,SAAS,MAAM;AAE1C,MAAI,CAAC,OAAO,WAAW,CAAC,OAAO,QAAQ;AACrC;AAAA,EACF;AAEA,QAAM,YAAY,MAAM;AAExB,MAAI;AACF,UAAM,eAAe,QAAQ,kBACzB,MAAM,QAAQ,gBAAgB;AAAA,MAC5B,MAAM;AAAA,MACN,MAAM,OAAO;AAAA,MACb;AAAA,IACF,CAAC,IACD,OAAO;AACX,UAAM,UAAU,MAAM,kBAAkB,cAAc,MAAM;AAE5D,QAAI,6BAA6B,MAAM,EAAE,cAAc,WAAW;AAChE,cAAQ,QAAQ;AAChB;AAAA,IACF;AAEA,WAAO,aAAa;AACpB,WAAO,uBAAuB,OAAO;AACrC,WAAO,sBAAsB,OAAO;AACpC,WAAO,cAAc,OAAO,kBAAkB,UAAU;AACxD,WAAO,uBAAuB,OAAO,kBAAkB,OAAO,oBAAoB;AAClF,UAAM,gBAAgB;AAAA,EACxB,QAAQ;AACN,QAAI,6BAA6B,MAAM,EAAE,cAAc,WAAW;AAChE,2BAAqB,QAAQ,KAAK;AAAA,IACpC;AAAA,EACF;AACF;AAEO,SAAS,4BAA4B,QAAe;AACzD,QAAM,QAAQ,6BAA6B,MAAM;AACjD,QAAM,aAAa;AACnB,uBAAqB,QAAQ,KAAK;AAClC,SAAO,MAAM;AACf;AAEO,IAAM,wCAAwC;AAC9C,IAAM,0CAA0C;AAEvD,SAAS,wBAAwB,aAAmC;AAClE,QAAM,EAAE,cAAc,iBAAiB,IAAI,YAAY,SAAS;AAEhE,MAAI,oBAAoB,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,IAAIC,cAAa,cAAc,gBAAgB;AAC7D,QAAM,OAAO;AACb,QAAM,SAAS,YAAY;AAAA,IACzB,QAAQ;AAAA,EACV;AAEA,SAAO;AACT;AAEA,SAAS,6BAA6B,QAA0C;AAC9E,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,SAAS,0BAA0B;AAEpD,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,UAAqC;AAAA,IACzC,WAAW;AAAA,EACb;AACA,WAAS,0BAA0B,IAAI;AACvC,SAAO;AACT;AAEA,SAAS,qBAAqB,QAAe,OAAkC;AAC7E,MAAI,MAAM,eAAe;AACvB,QAAI,OAAO,eAAe,MAAM,eAAe;AAC7C,aAAO,aAAa;AAAA,IACtB;AAEA,QAAI,OAAO,gBAAgB,MAAM,eAAe;AAC9C,aAAO,cAAc;AAAA,IACvB;AAEA,UAAM,cAAc,QAAQ;AAC5B,UAAM,gBAAgB;AAAA,EACxB;AAEA,SAAO,uBAAuB;AAC9B,SAAO,sBAAsB;AAC7B,SAAO,uBAAuB;AAChC;AAEA,SAAS,iCAAiC,MAAa;AACrD,QAAM,aAAa,oBAAI,IAAoB;AAC3C,QAAM,YAAY,oBAAI,IAA0B;AAChD,QAAM,WAAW,oBAAI,IAAa;AAElC,OAAK,SAAS,CAAC,WAAW;AACxB,QAAI,EAAE,kBAAkBC,SAAQ,kBAAkBC,iBAAgB;AAChE;AAAA,IACF;AAEA,QAAI,OAAO,oBAAoBC,iBAAgB;AAC7C,iBAAW,IAAI,OAAO,QAAQ;AAAA,IAChC;AAEA,UAAM,kBAAkB,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,WAAW,CAAC,OAAO,QAAQ;AAE3F,oBAAgB,QAAQ,CAAC,aAAa;AACpC,UAAI,EAAE,oBAAoBC,wBAAuB;AAC/C;AAAA,MACF;AAEA,gBAAU,IAAI,QAAQ;AAEtB,UAAI,SAAS,KAAK;AAChB,iBAAS,IAAI,SAAS,GAAG;AAAA,MAC3B;AAEA,UAAI,SAAS,WAAW;AACtB,iBAAS,IAAI,SAAS,SAAS;AAAA,MACjC;AAEA,UAAI,SAAS,cAAc;AACzB,iBAAS,IAAI,SAAS,YAAY;AAAA,MACpC;AAEA,UAAI,SAAS,cAAc;AACzB,iBAAS,IAAI,SAAS,YAAY;AAAA,MACpC;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,OAAK,iBAAiB;AACtB,aAAW,QAAQ,CAAC,aAAa;AAC/B,aAAS,QAAQ;AAAA,EACnB,CAAC;AACD,YAAU,QAAQ,CAAC,aAAa;AAC9B,aAAS,QAAQ;AAAA,EACnB,CAAC;AACD,WAAS,QAAQ,CAAC,YAAY;AAC5B,YAAQ,QAAQ;AAAA,EAClB,CAAC;AACH;AAEA,eAAe,kBAAkB,MAAc,QAA6B;AAC1E,QAAM,UAAU,OAAO,WAAW,QAC9B,MAAM,UAAU,UAAU,IAAI,IAC9B,MAAMX,eAAc,UAAU,IAAI;AAEtC,UAAQ,UAAU;AAElB,MAAI,OAAO,WAAW,SAAS;AAC7B,YAAQ,aAAaY;AAAA,EACvB;AAEA,SAAO;AACT;;;AIheA,SAAS,WAAW,eAAe;AAYnC,IAAM,iBAAiB,CAAC,oBAAoB,4BAA4B,eAAe;AAmBvF,eAAsB,yBACpB,OACA,UAA2C,CAAC,GACpB;AACxB,QAAM,WAAW,gBAAgB,KAAK;AACtC,QAAM,QAA6B,CAAC;AACpC,QAAM,WAAW,YAAY,QAAQ,YAAY,QAAQ;AACzD,QAAM,qBAAqB,QAAQ,sBAAsB;AACzD,QAAM,eAAe,oBAAI,IAAoB;AAC7C,QAAM,YAAY,oBAAI,IAAY;AAElC,aAAW,YAAY,SAAS,WAAW;AACzC,eAAW,SAAS,gBAAgB;AAClC,YAAM,SAAS,SAAS,KAAK;AAE7B,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AAEA,YAAM,cAAc,MAAM,kBAAkB,QAAQ;AAAA,QAClD;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,GAAG,QAAQ,aAAa,QAAQ,SAAS,EAAE,CAAC,IAAI,mBAAmB,KAAK,CAAC;AAAA,QACxF;AAAA,MACF,CAAC;AAED,UAAI,aAAa;AACf,iBAAS,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,aAAW,SAAS,SAAS,QAAQ;AACnC,QAAI,MAAM,SAAS,SAAS;AAC1B;AAAA,IACF;AAEA,UAAM,cAAc,MAAM,kBAAkB,MAAM,MAAM;AAAA,MACtD;AAAA,MACA;AAAA,MACA;AAAA,MACA,oBAAoB,oBAAoB,MAAM,MAAM,MAAM,SAAS,WAAW;AAAA,MAC9E,eAAe,GAAG,QAAQ,WAAW,QAAQ,MAAM,EAAE,CAAC;AAAA,MACtD;AAAA,IACF,CAAC;AAED,QAAI,aAAa;AACf,YAAM,OAAO;AAAA,IACf;AAEA,UAAM,cAAc,MAAM,SAAS;AAEnC,QAAI,OAAO,gBAAgB,YAAY,YAAY,SAAS,GAAG;AAC7D,YAAM,qBAAqB,MAAM,kBAAkB,aAAa;AAAA,QAC9D;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,GAAG,QAAQ,mBAAmB,QAAQ,MAAM,EAAE,CAAC;AAAA,QAC9D;AAAA,MACF,CAAC;AAED,UAAI,oBAAoB;AACtB,cAAM,SAAS,cAAc;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,SAAS,SAAS,MAAM,OAAO;AAEpD,MAAI,cAAc;AAChB,UAAM,oBAAoB,MAAM,kBAAkB,cAAc;AAAA,MAC9D;AAAA,MACA;AAAA,MACA;AAAA,MACA,oBAAoB,SAAS,SAAS,MAAM,OAAO,WAAW,QAAQ,QAAQ,uBAAuB,YAAY;AAAA,MACjH,eAAe,GAAG,QAAQ,aAAa,QAAQ,SAAS,SAAS,MAAM,OAAO,QAAQ,QAAQ,CAAC;AAAA,MAC/F;AAAA,IACF,CAAC;AAED,QAAI,mBAAmB;AACrB,eAAS,SAAS,MAAM,OAAO,SAAS;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,mBACpB,OACA,UAA2C,CAAC,GACpB;AACxB,SAAO,yBAAyB,OAAO,OAAO;AAChD;AAEO,SAAS,sBAAsB,OAA4C;AAChF,SAAO,OAAO,UAAU,WAAW,kBAAkB,KAAK,IAAI,kBAAkB,KAAK,UAAU,KAAK,CAAC;AACvG;AAEO,SAAS,kBAAkB,QAAuB,UAAoC,CAAC,GAAG;AAC/F,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,UAAsC;AAAA,IAC1C,CAAC,YAAY,GAAG,QAAQ,OAAO,KAAK,UAAU,OAAO,QAAQ,CAAC;AAAA,EAChE;AAEA,SAAO,MAAM,QAAQ,CAAC,SAAS;AAC7B,YAAQ,KAAK,IAAI,IAAI,KAAK;AAAA,EAC5B,CAAC;AAED,SAAO,QAAQ,SAAS;AAAA,IACtB,OAAO,QAAQ,oBAAoB;AAAA,EACrC,CAAC;AACH;AAEO,SAAS,oBACd,OACA,UAAqC,CAAC,GACvB;AACf,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,UAAU,UAAU,KAAK;AAC/B,QAAM,gBAAgB,QAAQ,YAAY;AAE1C,MAAI,CAAC,eAAe;AAClB,UAAM,IAAI,MAAM,qBAAqB,YAAY,GAAG;AAAA,EACtD;AAEA,QAAM,WAAW,kBAAkB,IAAI,YAAY,EAAE,OAAO,aAAa,CAAC;AAC1E,QAAM,QAAQ,OAAO,QAAQ,OAAO,EACjC,OAAO,CAAC,CAAC,IAAI,MAAM,SAAS,YAAY,EACxC,IAAI,CAAC,CAAC,MAAM,SAAS,OAAO;AAAA,IAC3B,OAAO;AAAA,IACP,UAAU,sBAAsB,IAAI;AAAA,IACpC;AAAA,EACF,EAAE;AAEJ,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,uBACd,QACA,UAAyC,CAAC,GACvB;AACnB,SAAO;AAAA,IACL;AAAA,IACA,cAAc,QAAQ;AAAA,IACtB,SAAS,QAAQ,WAAW;AAAA,EAC9B;AACF;AAEA,eAAsB,gCACpB,OACA,UAA2C,CAAC,GACZ;AAChC,SAAO,yBAAyB,OAAO,OAAO;AAChD;AAEO,SAAS,+BAA+B,QAA+B,UAAoC,CAAC,GAAG;AACpH,SAAO,kBAAkB,QAAQ,OAAO;AAC1C;AAEO,SAAS,8BACd,OACA,UAAqC,CAAC,GACf;AACvB,SAAO,oBAAoB,OAAO,OAAO;AAC3C;AAEA,eAAe,kBACb,QACA,SAQA;AACA,QAAM,WAAW,QAAQ,aAAa,IAAI,MAAM;AAEhD,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AAEA,MAAI,UAAU,MAAM,GAAG;AACrB,UAAM,SAAS,aAAa,MAAM;AAClC,UAAMC,QAAO;AAAA,MACX,GAAG,QAAQ,aAAa,IAAI,eAAe,OAAO,UAAU,QAAQ,kBAAkB,CAAC;AAAA,MACvF,QAAQ;AAAA,IACV;AAEA,YAAQ,MAAM,KAAK;AAAA,MACjB,OAAO,OAAO;AAAA,MACd,UAAU,OAAO;AAAA,MACjB,MAAAA;AAAA,IACF,CAAC;AACD,YAAQ,aAAa,IAAI,QAAQA,KAAI;AACrC,WAAOA;AAAA,EACT;AAEA,MAAI,CAAC,QAAQ,oBAAoB;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,MAAM,MAAM;AAEnC,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,2BAA2B,MAAM,EAAE;AAAA,EACrD;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAM,QAAQ,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AACrD,QAAM,OAAO;AAAA,IACX,GAAG,QAAQ,aAAa,IAAI,eAAe,KAAK,MAAM,QAAQ,sBAAsB,uBAAuB,MAAM,CAAC,CAAC;AAAA,IACnH,QAAQ;AAAA,EACV;AAEA,UAAQ,MAAM,KAAK;AAAA,IACjB;AAAA,IACA,UAAU,KAAK,QAAQ;AAAA,IACvB;AAAA,EACF,CAAC;AACD,UAAQ,aAAa,IAAI,QAAQ,IAAI;AAErC,SAAO;AACT;AAEA,SAAS,aAAa,QAAgB;AACpC,QAAM,QAAQ,uDAAuD,KAAK,MAAM;AAEhF,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACrC;AAEA,QAAM,WAAW,MAAM,CAAC,KAAK;AAC7B,QAAM,UAAU,MAAM,CAAC,KAAK;AAE5B,MAAI,MAAM,CAAC,GAAG;AACZ,UAAM,SAAS,KAAK,OAAO;AAC3B,UAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAE1C,aAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,YAAM,KAAK,IAAI,OAAO,WAAW,KAAK;AAAA,IACxC;AAEA,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL,OAAO,IAAI,YAAY,EAAE,OAAO,mBAAmB,OAAO,CAAC;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,OAAqB;AAC/C,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,oBAAoB,MAAc,aAAsB;AAC/D,MAAI,OAAO,gBAAgB,YAAY,YAAY,SAAS,GAAG;AAC7D,WAAO,YAAY,YAAY;AAAA,EACjC;AAEA,SAAO,uBAAuB,IAAI,KAAK;AACzC;AAEA,SAAS,eAAe,UAA8B,UAAmB;AACvE,QAAM,aAAa,UAAU,YAAY;AAEzC,MAAI,eAAe,aAAa;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,cAAc;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,iBAAiB;AAClC,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,sBAAsB;AACvC,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,mBAAmB;AACpC,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,uBAAuB,eAAe,4BAA4B;AACnF,WAAO,YAAY;AAAA,EACrB;AAEA,SAAO,YAAY;AACrB;AAEA,SAAS,uBAAuB,MAAc;AAC5C,QAAM,YAAY,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACvD,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,SAAO,MAAM,SAAS,IAAI,MAAM,GAAG,EAAE,GAAG,YAAY,IAAI;AAC1D;AAEA,SAAS,sBAAsB,MAAc;AAC3C,UAAQ,uBAAuB,IAAI,GAAG;AAAA,IACpC,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,iBAAiB,MAAc,WAAwB;AAC9D,MAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACxB,cAAU,IAAI,IAAI;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,KAAK,YAAY,GAAG;AACpC,QAAM,OAAO,WAAW,IAAI,KAAK,MAAM,GAAG,OAAO,IAAI;AACrD,QAAM,YAAY,WAAW,IAAI,KAAK,MAAM,OAAO,IAAI;AACvD,MAAI,UAAU;AAEd,SAAO,UAAU,IAAI,GAAG,IAAI,IAAI,OAAO,GAAG,SAAS,EAAE,GAAG;AACtD,eAAW;AAAA,EACb;AAEA,QAAM,WAAW,GAAG,IAAI,IAAI,OAAO,GAAG,SAAS;AAC/C,YAAU,IAAI,QAAQ;AACtB,SAAO;AACT;AAEA,SAAS,UAAU,OAAe;AAChC,SAAO,MAAM,WAAW,OAAO;AACjC;AAEA,SAAS,QAAQ,OAAe;AAC9B,QAAM,aAAa,MAChB,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE;AAEzB,SAAO,cAAc;AACvB;AAEA,SAAS,YAAY,OAAe;AAClC,SAAO,MAAM,QAAQ,cAAc,EAAE;AACvC;;;ACzZA,OAAO,YAAY;AAcZ,SAAS,qBAAqB,UAAwB;AAC3D,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO,KAAK,GAAG,GAAG,CAAC;AAAA,EACrB;AAEA,MAAI,SAAS,KAAK,GAAG,GAAG,CAAC;AAEzB,WAAS,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GAAG;AACvD,UAAM,UAAU,SAAS,KAAK;AAC9B,UAAM,OAAO,UAAU,QAAQ,KAAK,SAAS,MAAM;AAEnD,aAAS;AAAA,MACP;AAAA,MACA;AAAA,SACG,QAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,KAAK;AAAA,SACxC,QAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,KAAK;AAAA,SACxC,QAAQ,IAAI,KAAK,MAAM,QAAQ,IAAI,KAAK;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,cAAc,MAAM;AACvC,SAAO,WAAW,UAAU,MAAM,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI;AACxD;AAEO,SAAS,sBAAsB,UAAkB,SAAS,qBAAqB,QAAQ,GAA4B;AACxH,QAAM,SAAS,YAAY,QAAQ;AACnC,QAAM,mBAAmB,KAAK,IAAI,OAAO,CAAC,IAAI,OAAO,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC;AACjF,MAAI,UAAU,cAAc,UAAU,kBAAkB,MAAM,CAAC;AAE/D,MAAI,WAAW,OAAO,MAAM,GAAG;AAC7B,cAAU,cAAc,UAAU,KAAK,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC;AAAA,EAC1D;AAEA,QAAM,YAAY,cAAc,UAAU,QAAQ,OAAO,CAAC;AAE1D,SAAO,SAAS,IAAI,CAAC,WAAW;AAC9B,UAAM,SAAS,QAAQ,QAAQ,MAAM;AACrC,WAAO,CAAC,QAAQ,QAAQ,OAAO,GAAG,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAC9D,CAAC;AACH;AAEO,SAAS,kBAAkB,QAAyC;AACzE,MAAI,OAAO;AAEX,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,UAAM,CAAC,IAAI,EAAE,IAAI,OAAO,KAAK;AAC7B,UAAM,CAAC,IAAI,EAAE,IAAI,QAAQ,QAAQ,KAAK,OAAO,MAAM;AACnD,YAAQ,KAAK,KAAK,KAAK;AAAA,EACzB;AAEA,SAAO,OAAO;AAChB;AAEO,SAAS,oBAAoB,UAAkB,QAAsB;AAC1E,QAAM,SAAS,YAAY,QAAQ;AACnC,QAAM,mBAAmB,KAAK,IAAI,OAAO,CAAC,IAAI,OAAO,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC;AACjF,MAAI,UAAU,cAAc,UAAU,kBAAkB,MAAM,CAAC;AAE/D,MAAI,WAAW,OAAO,MAAM,GAAG;AAC7B,cAAU,cAAc,UAAU,KAAK,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC;AAAA,EAC1D;AAEA,QAAM,YAAY,cAAc,UAAU,QAAQ,OAAO,CAAC;AAC1D,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,MAAM,UAAU;AACjD,UAAM,aAAa,QAAQ,MAAM,MAAM;AACvC,UAAM,cAAc,QAAQ,OAAO,MAAM;AACzC,UAAM,YAAY,KAAK,MAAM,QAAQ,YAAY,SAAS,GAAG,QAAQ,YAAY,OAAO,CAAC;AACzF,UAAM,aAAa,KAAK,MAAM,QAAQ,aAAa,SAAS,GAAG,QAAQ,aAAa,OAAO,CAAC;AAE5F,WAAO,YAAY;AAAA,EACrB,CAAC;AAED,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB;AAAA,IACpB,UAAU,QAAQ,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,QAAQ,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;AAAA,EACxE;AAEA,SAAO,QAAQ,eAAe,MAAM,IAAI,IAAI,OAAO,QAAQ,IAAI;AACjE;AAEO,SAAS,mBAAmB,QAA2C;AAC5E,QAAM,YAAY,OAAO,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACnD,SAAO,OAAO,SAAS;AACzB;AAEO,SAAS,qBAAqB,UAAkB,SAAS,qBAAqB,QAAQ,GAAa;AACxG,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,YAAY,sBAAsB,UAAU,MAAM;AAExD,MAAI,KAAK,IAAI,kBAAkB,SAAS,CAAC,KAAK,MAAU;AACtD,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,mBAAmB,SAAS;AACrC;AAEO,SAAS,kBAAkB,UAAwB;AACxD,SAAO,YAAY,QAAQ;AAC7B;;;ACzFO,SAAS,sBAAsB,OAAc,UAAU,MAA4B;AACxF,MAAI,MAAM,OAAO,SAAS,GAAG;AAC3B,WAAO;AAAA,MACL,OAAO,CAAC;AAAA,MACR,UAAU,CAAC;AAAA,MACX,OAAO;AAAA,MACP,QAAQ,CAAC,qDAAqD;AAAA,IAChE;AAAA,EACF;AAEA,QAAM,iBAAiB,oBAAI,IAAsC;AACjE,QAAM,QAAkC,CAAC;AAEzC,WAAS,aAAa,GAAG,aAAa,MAAM,OAAO,QAAQ,cAAc,GAAG;AAC1E,UAAM,QAAQ,MAAM,OAAO,UAAU;AACrC,UAAM,eAAe,oBAAoB,MAAM,QAAQ,YAAY,OAAO;AAE1E,QAAI,aAAa,SAAS,GAAG;AAC3B;AAAA,IACF;AAEA,UAAM,kBAAkB,oBAAoB,cAAc,cAAc,MAAM,MAAM,CAAC;AACrF,UAAM,kBAAkB,qBAAqB,iBAAiB,MAAM,MAAM;AAE1E,QAAI,gBAAgB,SAAS,GAAG;AAC9B;AAAA,IACF;AAEA,UAAM,WAAW,gBAAgB,IAAI,CAAC,aAAa,oBAAoB,gBAAgB,UAAU,OAAO,CAAC;AACzG,UAAM,WAAW,MAAM,MAAM,UAAU;AAEvC,UAAM,KAAK;AAAA,MACT,IAAI,UAAU,MAAM,cAAc,UAAU;AAAA,MAC5C;AAAA,MACA,YAAY,UAAU;AAAA,MACtB,UAAU,UAAU;AAAA,MACpB,SAAS,UAAU;AAAA,MACnB,WAAW,SAAS,IAAI,CAAC,WAAW,OAAO,EAAE;AAAA,MAC7C;AAAA,MACA,QAAQ,kBAAkB,eAAe;AAAA,MACzC,QAAQ,cAAc,MAAM,MAAM;AAAA,MAClC;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU,MAAM,KAAK,eAAe,OAAO,CAAC;AAAA,IAC5C,OAAO,MAAM,UAAU;AAAA,IACvB,QAAQ,MAAM,UAAU,IAAI,CAAC,IAAI,CAAC,6DAA6D;AAAA,EACjG;AACF;AAEO,SAAS,0BAA0B,OAAa,OAAc,UAAU,MAA8B;AAC3G,QAAM,iBAAiB,sBAAsB,OAAO,KAAK;AAEzD,SAAO,iBAAiB,UAAU,YAAY;AAChD;AAEO,SAAS,sBAAsB,OAAa,OAAsB;AACvE,SAAO,QAAQ,MAAM,QAAQ,KAAK,IAAI,MAAM;AAC9C;AAEO,SAAS,gBACd,OACA,QACA,OACA,UAAU,MACQ;AAClB,QAAM,cAAc,QAAQ,MAAM,QAAQ,UAAU,OAAO,QAAQ,MAAM,MAAM,CAAC;AAEhF,MAAI,KAAK,IAAI,WAAW,KAAK,SAAS;AACpC,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,UAAU,UAAU,OAAO,QAAQ,MAAM,MAAM,GAAG,MAAM,QAAQ;AAClF,QAAM,aAAa,UAAU,UAAU,MAAM,QAAQ,MAAM,MAAM,GAAG,OAAO,QAAQ;AACnF,QAAM,YAAY,UAAU,UAAU,MAAM,QAAQ,OAAO,MAAM,GAAG,MAAM,QAAQ;AAElF,SAAO,UAAU,QAAQ,QAAQ,WAAW,UAAU,GAAG,SAAS,GAAG,IAAI,WAAW;AACtF;AAEA,SAAS,oBAAoB,QAAiB,YAAoB,SAAyB;AACzF,QAAM,QAAQ,OAAO,UAAU;AAC/B,QAAM,WAAW,oBAAI,IAAkB;AAEvC,WAAS,aAAa,GAAG,aAAa,OAAO,QAAQ,cAAc,GAAG;AACpE,QAAI,eAAe,YAAY;AAC7B;AAAA,IACF;AAEA,aAAS,cAAc,aAAa,GAAG,cAAc,OAAO,QAAQ,eAAe,GAAG;AACpF,UAAI,gBAAgB,YAAY;AAC9B;AAAA,MACF;AAEA,YAAM,eAAe,gBAAgB,OAAO,OAAO,UAAU,GAAG,OAAO,WAAW,GAAG,OAAO;AAE5F,UAAI,CAAC,cAAc;AACjB;AAAA,MACF;AAEA,YAAM,cAAc,KAAK,IAAI,sBAAsB,cAAc,KAAK,CAAC,KAAK,UAAU;AACtF,YAAM,kBAAkB,OAAO;AAAA,QAC7B,CAAC,mBAAmB,0BAA0B,cAAc,gBAAgB,UAAU,CAAC,MAAM;AAAA,MAC/F;AAEA,UAAI,CAAC,eAAe,CAAC,iBAAiB;AACpC;AAAA,MACF;AAEA,eAAS,IAAI,cAAc,cAAc,OAAO,GAAG,YAAY;AAAA,IACjE;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,SAAS,OAAO,CAAC;AACrC;AAEA,SAAS,oBACP,UACA,UACA,SAC0B;AAC1B,QAAM,MAAM,cAAc,UAAU,OAAO;AAC3C,QAAM,WAAW,SAAS,IAAI,GAAG;AAEjC,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,SAAS;AAAA,IACb,IAAI,gBAAgB,SAAS,IAAI;AAAA,IACjC,UAAU,KAAK,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAAA,EACnD;AAEA,WAAS,IAAI,KAAK,MAAM;AACxB,SAAO;AACT;AAEA,SAAS,cAAc,UAAgB,SAAyB;AAC9D,SAAO;AAAA,IACL,KAAK,MAAM,SAAS,IAAI,OAAO;AAAA,IAC/B,KAAK,MAAM,SAAS,IAAI,OAAO;AAAA,IAC/B,KAAK,MAAM,SAAS,IAAI,OAAO;AAAA,EACjC,EAAE,KAAK,GAAG;AACZ;;;ACvHA,IAAM,yBAAyB,oBAAI,QAAyC;AA0FrE,SAAS,iBAAiB,MAAoB,QAA4B;AAC/E,QAAM,QAAQ,qBAAqB,IAAI;AACvC,QAAM,YAAY,MAAM,cAAc,IAAI,MAAM;AAEhD,MAAI,WAAW;AACb,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,MAAM,SAAS,IAAI,MAAM;AAEtC,MAAI,CAAC,MAAM;AACT,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,MAAkB,CAAC;AACzB,MAAI,gBAAwC,KAAK;AACjD,MAAI,QAAQ;AAEZ,SAAO,iBAAiB,QAAQ,KAAK,UAAU,SAAS,GAAG;AACzD,UAAM,WAAW,MAAM,aAAa,IAAI,aAAa;AAErD,QAAI,CAAC,UAAU;AACb,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,KAAK,SAAS,MAAM;AACxB,oBAAgB,SAAS;AACzB,aAAS;AAET,QAAI,kBAAkB,KAAK,UAAU;AACnC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,IAAI,QAAQ,GAAG;AACnC,SAAO;AACT;AAEO,SAAS,gBAAgB,MAAoB,QAAsC;AACxF,QAAM,QAAQ,qBAAqB,IAAI;AAEvC,SAAO,iBAAiB,MAAM,MAAM,EACjC,IAAI,CAAC,aAAa,MAAM,WAAW,IAAI,QAAQ,CAAC,EAChD,OAAO,CAAC,WAAyC,QAAQ,MAAM,CAAC;AACrE;AA8CO,SAAS,oBAAoB,MAAoB,QAAkD;AACxG,QAAM,eAAe,gBAAgB,MAAM,MAAM;AAEjD,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,qBAAqB,aAAa,IAAI,CAAC,WAAW,OAAO,QAAQ,CAAC;AACjF,QAAM,UAAU;AAAA,IACd,aAAa,IAAI,CAAC,WAAW,OAAO,QAAQ;AAAA,IAC5C;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,aAAa,IAAI,CAAC,WAAW,OAAO,EAAE;AAAA,IACjD;AAAA,IACA;AAAA,EACF;AACF;AAuEA,SAAS,qBAAqB,MAAuC;AACnE,QAAM,SAAS,uBAAuB,IAAI,IAAI;AAE9C,MAAI,UAAU,OAAO,UAAU,KAAK,SAAS,OAAO,cAAc,KAAK,aAAa,OAAO,aAAa,KAAK,UAAU;AACrH,WAAO;AAAA,EACT;AAEA,QAAM,YAA+B;AAAA,IACnC,UAAU,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAU,CAAC;AAAA,IACpE,eAAe,oBAAI,IAAI;AAAA,IACvB,OAAO,KAAK;AAAA,IACZ,cAAc,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,aAAa,CAAC,SAAS,IAAI,QAAQ,CAAU,CAAC;AAAA,IACxF,WAAW,KAAK;AAAA,IAChB,YAAY,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,MAAM,CAAU,CAAC;AAAA,IAC/E,UAAU,KAAK;AAAA,EACjB;AAEA,yBAAuB,IAAI,MAAM,SAAS;AAC1C,SAAO;AACT;;;AC7TA,SAAS,eAAe;AACxB;AAAA,EACE,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,kBAAAC;AAAA,EACA;AAAA,EACA,0BAAAC;AAAA,EACA,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,wBAAAC;AAAA,EAEA,kBAAAC;AAAA,EACA,SAAAC;AAAA,EACA;AAAA,EACA,kBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,aAAAC,kBAAiB;AAG1B,IAAMC,cAAa,IAAIC,YAAW;AAClC,IAAM,eAAe,IAAI,aAAa;AACtC,IAAMC,aAAY,IAAIC,WAAU;AAChC,IAAMC,sBAAqB,IAAIC,eAAc;AAE7C,eAAsB,kBAAkB,OAA6E;AACnH,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,kBAAkB,KAAK;AAAA,EAChC;AAEA,MAAI,4BAA4B,KAAK,GAAG;AACtC,WAAO,8BAA8B,KAAK;AAAA,EAC5C;AAEA,SAAO,sBAAsB,KAAK;AACpC;AAaA,eAAsB,8BAA8B,UAAwD;AAC1G,QAAM,aAAa,IAAI,IAAI,SAAS,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAC5E,QAAM,gBAAgB,IAAI,IAAI,SAAS,UAAU,IAAI,CAAC,aAAa,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC;AAC3F,QAAM,oBAAoB,MAAM,QAAQ,IAAI,SAAS,UAAU,IAAI,CAAC,aAAa,uBAAuB,QAAQ,CAAC,CAAC;AAClH,QAAM,iBAAiB,SAAS,SAAS,MAAM,IAAI;AACnD,QAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,QAAM,mBAAmB,iBACrB;AAAA,IACE,GAAG,SAAS;AAAA,IACZ,OAAO;AAAA,MACL,GAAG,SAAS,SAAS;AAAA,MACrB,KAAK;AAAA,QACH,GAAG,SAAS,SAAS,MAAM;AAAA,QAC3B,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF,IACA,SAAS;AACb,QAAM,kBAA2B,CAAC;AAClC,QAAM,gBAAuC,CAAC;AAE9C,aAAW,QAAQ,SAAS,OAAO;AACjC,QAAI,YAAY,IAAI,GAAG;AACrB,oBAAc,KAAK;AAAA,QACjB,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,MAClB,CAAqE;AACrE;AAAA,IACF;AAEA,QAAI,YAAY,IAAI,GAAG;AACrB,YAAM,WAAW,MAAM,oBAAoB,MAAM,aAAa;AAC9D,oBAAc,KAAK;AAAA,QACjB,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,MAAM,iBAAiB,MAAM,kBAAkB,UAAU,SAAS,SAAS,MAAM,GAAG,IAAI;AAAA,QACxF,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,MAClB,CAAqE;AACrE;AAAA,IACF;AAEA,QAAI,WAAW,IAAI,GAAG;AACpB,YAAM,WAAW,MAAM,oBAAoB,MAAM,aAAa;AAC9D,oBAAc,KAAK;AAAA,QACjB,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,MAAM,iBAAiB,MAAM,kBAAkB,UAAU,SAAS,SAAS,MAAM,GAAG,IAAI;AAAA,QACxF,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,MAClB,CAAoE;AACpE;AAAA,IACF;AAEA,QAAI,gBAAgB,IAAI,GAAG;AACzB,YAAM,WAAW,MAAM,oBAAoB,MAAM,aAAa;AAC9D,oBAAc,KAAK;AAAA,QACjB,MAAM,KAAK;AAAA,QACX;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,MAAM,iBAAiB,MAAM,kBAAkB,UAAU,SAAS,SAAS,MAAM,GAAG,IAAI;AAAA,QACxF,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,MAClB,CAAyE;AACzE;AAAA,IACF;AAEA,QAAI,YAAY,IAAI,GAAG;AACrB,YAAM,eAAe,iBACjB,MAAM,eAAe,KAAK,MAAM,WAAW,IAAI,KAAK,KAAK,OAAO,GAAG,KAAK,IAAI,SAAS,SAAS,MAAM,GAAG,IACvG;AAEJ,sBAAgB,KAAK,GAAI,cAAc,UAAU,CAAC,CAAE;AACpD,oBAAc,KAAK;AAAA,QACjB,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,MAAM,cAAc;AAAA,QACpB,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,WAAW,KAAK;AAAA,MAClB,CAAqE;AACrE;AAAA,IACF;AAEA,QAAI,iBAAiB,IAAI,GAAG;AAC1B,YAAM,aAAa,4BAA4B,SAAS,OAAO,IAAI;AAEnE,UAAI,CAAC,cAAc,EAAE,YAAY,UAAU,KAAK,WAAW,UAAU,KAAK,gBAAgB,UAAU,KAAK,YAAY,UAAU,IAAI;AACjI;AAAA,MACF;AAEA,oBAAc,KAAK;AAAA,QACjB,MAAM;AAAA,UACJ,cAAc,WAAW;AAAA,QAC3B;AAAA,QACA,OAAO,KAAK;AAAA,QACZ,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,QACN,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,MAAM,KAAK;AAAA,QACX,WAAW,0BAA0B,KAAK,SAAS;AAAA,MACrD,CAA0E;AAC1E;AAAA,IACF;AAEA,kBAAc,KAAK;AAAA,MACjB,MAAM,KAAK;AAAA,MACX,IAAI,KAAK;AAAA,MACT,MAAM;AAAA,MACN,UAAU,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,MACf,MAAM,KAAK;AAAA,MACX,WAAW,KAAK;AAAA,IAClB,CAAqE;AAAA,EACvE;AAEA,SAAO;AAAA,IACL,QAAQ,CAAC,GAAG,SAAS,QAAQ,GAAG,eAAe;AAAA,IAC/C,UAAU,SAAS;AAAA,IACnB,QAAQ,SAAS;AAAA,IACjB,WAAW;AAAA,IACX,UAAU;AAAA,MACR;AAAA,MACA,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEA,SAAS,4BAA4B,OAAgD;AACnF,SAAO;AAAA,IACL,SACE,OAAO,UAAU,YACjB,MAAM,QAAS,MAAyC,KAAK,KAC7D,MAAM,QAAS,MAAyC,SAAS,KACjE,MAAM,QAAS,MAAyC,QAAQ;AAAA,EACpE;AACF;AAEA,eAAe,oBACb,MACA,eACA;AACA,QAAM,mBAAmB,MAAM,uBAAuB;AAAA,IACpD,OAAO,KAAK,SAAS,UAAU,YAAY,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,SAAS,YAAY;AAAA,IAChH,IAAI,qBAAqB,KAAK,EAAE;AAAA,IAChC,WAAW,KAAK,SAAS,UAAU,IAAI,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,SAAS,OAAO;AAAA,IACvG,MAAM,GAAG,KAAK,IAAI;AAAA,IAClB,WAAW,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,SAAS,OAAO;AAAA,EAC5G,CAAC;AACD,QAAM,sBAAsB,oBAAI,IAAmD;AAEnF,QAAM,aAAa,OAAO,WAQpB;AACJ,UAAM,WAAW,OAAO,iBAAiB,MAAM,uBAAuB,cAAc,IAAI,OAAO,cAAc,CAAC,IAAI;AAClH,UAAM,YAAY,oBAAoB,IAAI,SAAS,EAAE,KAAK;AAAA,MACxD,SAAS,CAAC;AAAA,MACV;AAAA,MACA,SAAS,CAAC;AAAA,MACV,WAAW,CAAC;AAAA,MACZ,KAAK,CAAC;AAAA,IACR;AACA,UAAM,eAAe,UAAU,UAAU,SAAS;AAClD,UAAM,MAAM,OAAO,OAAO,OAAO,IAAI,WAAW,OAAO,SAAS,SAC5D,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,IACvC,iBAAiB,OAAO,UAAU,OAAO,QAAQ,OAAO,SAAS,OAAO,QAAQ;AAEpF,WAAO,SAAS,QAAQ,CAAC,WAAW;AAClC,gBAAU,UAAU,KAAK,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACrD,gBAAU,QAAQ,KAAK,OAAO,OAAO,GAAG,OAAO,OAAO,GAAG,OAAO,OAAO,CAAC;AAAA,IAC1E,CAAC;AACD,cAAU,IAAI,KAAK,GAAG,GAAG;AACzB,WAAO,gBAAgB,QAAQ,CAAC,UAAU;AACxC,gBAAU,QAAQ,KAAK,eAAe,KAAK;AAAA,IAC7C,CAAC;AACD,wBAAoB,IAAI,SAAS,IAAI,SAAS;AAAA,EAChD;AAEA,MAAI,YAAY,IAAI,GAAG;AACrB,UAAM,UAAU,sBAAsB,KAAK,IAAI;AAE/C,QAAI,CAAC,QAAQ,OAAO;AAClB,aAAO,EAAE,YAAY,CAAC,EAAE;AAAA,IAC1B;AAEA,eAAW,QAAQ,QAAQ,OAAO;AAChC,YAAM,WAAW;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,QAAQ,KAAK;AAAA,QACb,iBAAiB,KAAK;AAAA,QACtB,UAAU,KAAK;AAAA,QACf,SAAS,KAAK;AAAA,QACd,UAAU,KAAK,SAAS,IAAI,CAAC,WAAW,OAAO,QAAQ;AAAA,MACzD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,WAAW,IAAI,GAAG;AACpB,eAAW,QAAQ,KAAK,KAAK,OAAO;AAClC,YAAM,eAAe,oBAAoB,KAAK,MAAM,KAAK,EAAE;AAE3D,UAAI,CAAC,cAAc;AACjB;AAAA,MACF;AAEA,YAAM,WAAW;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,QAAQ,aAAa;AAAA,QACrB,iBAAiB,aAAa;AAAA,QAC9B,UAAU,KAAK;AAAA,QACf,SAAS,KAAK;AAAA,QACd,KAAK,KAAK;AAAA,QACV,UAAU,gBAAgB,KAAK,MAAM,KAAK,EAAE,EAAE,IAAI,CAAC,WAAW,OAAO,QAAQ;AAAA,MAC/E,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,gBAAgB,IAAI,GAAG;AACzB,UAAM,WAAW,KAAK,KAAK,aAAa,MAAM,uBAAuB,cAAc,IAAI,KAAK,KAAK,UAAU,CAAC,IAAI;AAChH,UAAM,YAAY,uBAAuB,KAAK,KAAK,OAAO,KAAK,KAAK,MAAM,KAAK,KAAK,kBAAkB,EAAE;AAExG,QAAI,WAAW;AACb,0BAAoB,IAAI,SAAS,IAAI;AAAA,QACnC,SAAS,UAAU;AAAA,QACnB;AAAA,QACA,SAAS,UAAU;AAAA,QACnB,WAAW,UAAU;AAAA,QACrB,KAAK,UAAU;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,YAAY,MAAM,KAAK,oBAAoB,OAAO,CAAC;AAAA,EACrD;AACF;AAEA,eAAe,kBACb,UACA,UAC2C;AAC3C,MAAI,CAAC,SAAS,WAAW,QAAQ;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,uBAAuB,UAAU,SAAS,cAAc;AAC5E,QAAM,cAAc,uBAAuB,UAAU,SAAS,cAAc;AAC5E,QAAM,OAA6B,CAAC;AAEpC,MAAI,aAAa;AACf,SAAK,KAAK;AAAA,MACR,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,MAAI,aAAa;AACf,SAAK,KAAK;AAAA,MACR,UAAU;AAAA,MACV,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO,KAAK,SAAS,OAAO;AAC9B;AAEA,eAAe,eACb,MACA,OACA,QACA,UACwD;AACxD,MAAI,CAAC,OAAO,MAAM;AAChB,WAAO,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAU;AAAA,EACvC;AAEA,QAAM,SAAS,MAAM,yBAAyB,KAAK;AACnD,QAAM,cAAwE,CAAC;AAE/E,aAAW,CAAC,OAAO,KAAK,KAAK;AAAA,IAC3B,CAAC,OAAO,SAAS,cAAc;AAAA,IAC/B,CAAC,OAAO,SAAS,cAAc;AAAA,EACjC,GAAY;AACV,UAAM,aAAa,2BAA2B,QAAQ,KAAK;AAE3D,QAAI,CAAC,YAAY;AACf;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,sBAAsB,UAAU;AACpD,gBAAY,KAAK;AAAA,MACf,OAAO,6BAA6B,OAAO,MAAM,QAAQ,OAAO,KAAK;AAAA,MACrE;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,QAAQ,YAAY,IAAI,CAAC,UAAU,MAAM,KAAK;AAAA,IAC9C,MAAM,YAAY,SACd,YAAY,IAAI,CAAC,WAAW;AAAA,MAC1B,SAAS,MAAM,MAAM;AAAA,MACrB,OAAO,MAAM;AAAA,IACf,EAAE,IACF;AAAA,EACN;AACF;AAEA,eAAe,yBAAyB,OAAc;AACpD,QAAM,SAAS,wBAAwB,KAAK;AAE5C,MAAI,WAAW,OAAO;AACpB,UAAM,YAAY,IAAIC,WAAU;AAChC,UAAM,cAAc,qBAAqB,OAAO,aAAa;AAC7D,UAAM,sBAAsB,OAAO,gBAAgB,YAAY,YAAY,SAAS,IAAI,cAAc;AACtG,UAAM,UAAU,qBAAqB,OAAO,iBAAiB;AAE7D,QAAI,SAAS;AACX,YAAM,kBAAkBC,WAAU,MAAMC,2BAA0B,SAAS,mBAAmB,GAAG,EAAE;AACnG,sBAAgB,QAAQ;AACxB,gBAAU,aAAa,eAAe;AAAA,IACxC,OAAO;AACL,gBAAU,aAAa,MAAkB;AAAA,IAC3C;AAEA,UAAM,SAAS,MAAM,UAAU,UAAU,MAAM,IAAI;AAEnD,QAAI,CAAC,WAAW,qBAAqB;AACnC,YAAM,UAAU,MAAMC,oBAAmB,UAAU,mBAAmB;AACtE,cAAQ,QAAQC;AAChB,cAAQ,QAAQA;AAChB,cAAQ,aAAaC;AAErB,aAAO,SAAS,CAAC,UAAoB;AACnC,YAAI,iBAAiBC,OAAM;AACzB,gBAAM,WAAW,IAAIC,sBAAqB;AAAA,YACxC,KAAK;AAAA,YACL,WAAW;AAAA,YACX,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAEA,UAAQ,MAAMC,YAAW,UAAU,MAAM,IAAI,GAAG;AAClD;AAEA,SAAS,2BAA2B,QAAkB,OAAe;AACnE,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,OAAO,MAAM,IAAI;AACxC,qCAAmC,cAAc;AACjD,MAAI,sBAAsB;AAE1B,iBAAe,SAAS,CAAC,UAAoB;AAC3C,QAAI,EAAE,iBAAiBF,QAAO;AAC5B;AAAA,IACF;AAEA,QAAI,mBAAmB,SAAS,MAAM,eAAe;AACnD;AAAA,IACF;AAEA,UAAM,qBAAqB,sBAAsB,MAAM,UAAU,KAAK;AAEtE,QAAI,CAAC,oBAAoB;AACvB;AAAA,IACF;AAEA,UAAM,WAAW;AACjB,2BAAuB;AAAA,EACzB,CAAC;AAED,SAAO,sBAAsB,IAAI,iBAAiB;AACpD;AAEA,SAAS,mCAAmC,MAAgB;AAC1D,QAAM,eAA0E,CAAC;AAEjF,OAAK,SAAS,CAAC,UAAoB;AACjC,QAAI,EAAE,iBAAiBA,UAAS,CAAC,MAAM,QAAQ,MAAM,QAAQ,KAAK,MAAM,SAAS,OAAO,UAAU,KAAK,CAAC,MAAM,QAAQ;AACpH;AAAA,IACF;AAEA,UAAM,YAAY,IAAIG,OAAM;AAC5B,cAAU,OAAO,MAAM,OAAO,GAAG,MAAM,IAAI,gBAAgB;AAC3D,cAAU,SAAS,KAAK,MAAM,QAAQ;AACtC,cAAU,WAAW,KAAK,MAAM,UAAU;AAC1C,cAAU,MAAM,KAAK,MAAM,KAAK;AAChC,cAAU,UAAU,MAAM;AAC1B,cAAU,cAAc,MAAM;AAC9B,cAAU,WAAW,gBAAgB,MAAM,YAAY,CAAC,CAAC;AAEzD,UAAM,SAAS,OAAO,QAAQ,CAAC,OAAgE,eAAuB;AACpH,YAAM,WAAW,MAAM,SAAS,MAAM,aAAa,KAAK,MAAM,SAAS,CAAC;AAExE,UAAI,CAAC,UAAU;AACb;AAAA,MACF;AAEA,YAAM,eAAe,qBAAqB,MAAM,UAAU,MAAM,OAAO,MAAM,KAAK;AAClF,YAAM,WAAW,IAAIH,MAAK,cAAc,QAAQ;AAChD,eAAS,OAAO,MAAM,OAAO,GAAG,MAAM,IAAI,UAAU,UAAU,KAAK,SAAS,UAAU;AACtF,eAAS,aAAa,MAAM;AAC5B,eAAS,gBAAgB,MAAM;AAC/B,eAAS,WAAW,gBAAgB,MAAM,YAAY,CAAC,CAAC;AACxD,gBAAU,IAAI,QAAQ;AAAA,IACxB,CAAC;AAED,iBAAa,KAAK;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,MACN,QAAQ,MAAM;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AAED,eAAa,QAAQ,CAAC,EAAE,WAAW,MAAM,OAAO,MAAM;AACpD,WAAO,IAAI,SAAS;AACpB,WAAO,OAAO,IAAI;AAAA,EACpB,CAAC;AACH;AAEA,SAAS,qBAAqB,UAA0B,OAAe,OAAe;AACpF,QAAM,gBAAgB,IAAII,gBAAe;AACzC,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,aAAa,SAAS;AAE5B,SAAO,QAAQ,UAAU,EAAE,QAAQ,CAAC,CAAC,MAAM,SAAS,MAAM;AACxD,kBAAc,aAAa,MAAM,SAAS;AAAA,EAC5C,CAAC;AAED,MAAI,OAAO;AACT,kBAAc,SAAS,MAAM,KAAK,MAAM,KAA0B,EAAE,MAAM,OAAO,QAAQ,KAAK,CAAC;AAAA,EACjG,OAAO;AACL,kBAAc,SAAS,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,GAAG,WAAW,QAAQ,MAAM,CAAC;AAAA,EACrF;AAEA,gBAAc,mBAAmB;AACjC,gBAAc,sBAAsB;AACpC,SAAO;AACT;AAEA,SAAS,sBAAsB,UAA0B,OAAe;AACtE,QAAM,oBAAoB,SAAS,aAAa,UAAU;AAC1D,QAAM,cAAc,mBAAmB,SAAS;AAEhD,MAAI,CAAC,qBAAqB,cAAc,MAAM,SAAS,MAAM;AAC3D,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,SAAS,aAAa,QAAQ,IAAI,WAAW,SAAS,MAAM;AAEpF,MAAI,CAAC,gBAAgB,aAAa,QAAQ,GAAG;AAC3C,oBAAgB,qBAAqB;AAAA,EACvC;AAEA,kBAAgB,mBAAmB;AACnC,QAAM,SAAS,gBAAgB,aAAa,MAAM;AAElD,MAAI,CAAC,QAAQ;AACX,QAAI,oBAAoB,UAAU;AAChC,sBAAgB,QAAQ;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAEA,QAAM,kBAAkB,gBAAgB,aAAa,QAAQ;AAC7D,QAAM,cAAc,gBAAgB,aAAa,IAAI;AACrD,QAAM,QAAQ,gBAAgB,SAAS;AACvC,QAAM,aAAa;AAAA,IACjB;AAAA,MACE,SAAS,QAAQ,MAAM,KAAK,MAAM,KAA0B,IAAI,MAAM,KAAK,EAAE,QAAQ,YAAY,GAAG,CAAC,GAAG,UAAU,KAAK;AAAA,MACvH,UAAU;AAAA,QACR,OAAO;AAAA,QACP,IAAI;AAAA,QACJ,gBAAgB;AAAA,QAChB,MAAM;AAAA,QACN,iBAAiB;AAAA,MACnB;AAAA,MACA,SAAS,MAAM,KAAK,gBAAgB,KAA0B;AAAA,MAC9D,WAAW,MAAM,KAAK,kBAAkB,KAA0B;AAAA,MAClE,KAAK,cAAc,MAAM,KAAK,YAAY,KAA0B,IAAI,CAAC;AAAA,IAC3E;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,oBAAoB,UAAU;AAChC,oBAAgB,QAAQ;AAAA,EAC1B;AAEA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,kCAAkC,UAAU;AACvE,qBAAmB,mBAAmB;AACtC,qBAAmB,sBAAsB;AACzC,SAAO;AACT;AAEA,eAAe,sBAAsB,QAAkB;AACrD,MAAI;AACF,WAAO,MAAM,yBAAyB,MAAM;AAAA,EAC9C,QAAQ;AACN,WAAO,MAAM,yBAAyB,iCAAiC,OAAO,MAAM,IAAI,CAAC,CAAC;AAAA,EAC5F;AACF;AAEA,eAAe,yBAAyB,QAAkB;AACxD,QAAM,QAAQ,IAAIC,OAAM;AACxB,QAAM,IAAI,MAAM;AAChB,QAAM,WAAW,MAAM,aAAa,WAAW,OAAO;AAAA,IACpD,QAAQ;AAAA,IACR,yBAAyB;AAAA,EAC3B,CAAC;AAED,MAAI,EAAE,oBAAoB,cAAc;AACtC,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,SAAO,IAAI,WAAW,QAAQ;AAChC;AAEA,SAAS,iCAAiC,QAAkB;AAC1D,SAAO,SAAS,CAAC,UAAoB;AACnC,QAAI,EAAE,iBAAiBL,QAAO;AAC5B;AAAA,IACF;AAEA,UAAM,QAAQ,CAAC,aAAmC;AAChD,YAAM,QAAQ,SAAS,MAAM;AAC7B,YAAM,WAAW;AACjB,YAAM,QAAQ;AACd,YAAM,UAAU;AAChB,YAAM,kBAAkB;AACxB,YAAM,cAAc;AACpB,YAAM,WAAW;AACjB,YAAM,MAAM;AACZ,YAAM,eAAe;AACrB,YAAM,YAAY;AAClB,YAAM,eAAe;AACrB,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,QAAQ,MAAM,QAAQ,GAAG;AACjC,YAAM,WAAW,MAAM,SAAS;AAAA,QAAI,CAAC,aACnC,oBAAoBC,wBAChB,MAAM,QAAQ,IACd,IAAIA,sBAAqB;AAAA,UACvB,OAAO,WAAW,WAAW,SAAS,QAAQ;AAAA,UAC9C,WAAW,eAAe,YAAY,OAAO,SAAS,cAAc,WAAW,SAAS,YAAY;AAAA,UACpG,WAAW,eAAe,YAAY,OAAO,SAAS,cAAc,WAAW,SAAS,YAAY;AAAA,QACtG,CAAC;AAAA,MACP;AACA;AAAA,IACF;AAEA,UAAM,mBAAmB,MAAM;AAE/B,UAAM,WAAW,MAAM,oBAAoBA,wBACvC,MAAM,MAAM,QAAQ,IACpB,IAAIA,sBAAqB;AAAA,MACvB,OAAO,WAAW,mBAAmB,iBAAiB,QAAQ;AAAA,MAC9D,WAAW,eAAe,oBAAoB,OAAO,iBAAiB,cAAc,WAAW,iBAAiB,YAAY;AAAA,MAC5H,WAAW,eAAe,oBAAoB,OAAO,iBAAiB,cAAc,WAAW,iBAAiB,YAAY;AAAA,IAC9H,CAAC;AAAA,EACP,CAAC;AAED,SAAO;AACT;AAEA,SAAS,6BACP,OACA,MACA,QACA,OACA,OACO;AACP,SAAO;AAAA,IACL,IAAI,mBAAmBK,SAAQ,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC,IAAI,KAAK;AAAA,IAC5D,UAAU;AAAA,MACR,GAAG,MAAM;AAAA,MACT,cAAc;AAAA,MACd,UAAU;AAAA,MACV,kBAAkB,MAAM;AAAA,MACxB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AAAA,IACA,MAAM,oBAAoB,OAAO,mBAAmB;AAAA,IACpD,MAAM;AAAA,EACR;AACF;AAEA,SAAS,oBAAoB,OAAmB,UAAkB;AAChE,MAAI,SAAS;AACb,QAAM,YAAY;AAElB,WAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,WAAW;AAC5D,cAAU,OAAO,aAAa,GAAG,MAAM,SAAS,OAAO,QAAQ,SAAS,CAAC;AAAA,EAC3E;AAEA,SAAO,QAAQ,QAAQ,WAAW,KAAK,MAAM,CAAC;AAChD;AAEA,SAAS,0BAA0B,WAAgE;AACjG,SAAO;AAAA,IACL,UAAU,gBAAgB,UAAU,QAAQ;AAAA,IAC5C,UAAU,gBAAgB,UAAU,QAAQ;AAAA,IAC5C,OAAO,gBAAgB,UAAU,KAAK;AAAA,EACxC;AACF;AAEA,SAAS,wBAAwB,OAAc;AAC7C,QAAM,SAAS,qBAAqB,OAAO,aAAa,GAAG,YAAY;AACvE,SAAO,WAAW,SAAS,MAAM,KAAK,YAAY,EAAE,SAAS,MAAM,IAAI,QAAQ;AACjF;AAEA,SAAS,qBAAqB,OAA0B,KAAa;AACnE,QAAM,QAAQ,OAAO,SAAS,GAAG;AACjC,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAEA,SAASV,2BAA0B,SAAiB,aAAsB;AACxE,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,aAAa;AACnB,QAAM,gBAAgB,iBAAiB,KAAK,OAAO;AACnD,QAAM,aAAa,QAAQ,QAAQ,YAAY,CAAC,SAAS;AACvD,QAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,aAAO,UAAU,WAAW;AAAA,IAC9B;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SAAO,gBAAgB,aAAa,GAAG,WAAW,KAAK,CAAC;AAAA,SAAY,WAAW;AAAA;AACjF;AAEA,SAASU,SAAQ,OAAe;AAC9B,QAAM,aAAa,MAChB,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE;AAEzB,SAAO,cAAc;AACvB;AAEA,SAAS,uBAAuB,UAA2B,OAA4C;AACrG,QAAM,aAAa,SAAS,WACzB,IAAI,CAAC,cAAc,wBAAwB,WAAW,KAAK,CAAC,EAC5D,OAAO,CAAC,cAAkE,cAAc,MAAS;AAEpG,SAAO,WAAW,SAAS,EAAE,WAAW,IAAI;AAC9C;AAEA,SAAS,wBACP,WACA,OACmD;AACnD,QAAM,cAAc,KAAK,MAAM,UAAU,UAAU,SAAS,CAAC;AAC7D,QAAM,gBAAgB,KAAK,MAAM,UAAU,QAAQ,SAAS,CAAC;AAE7D,MAAI,cAAc,MAAM,gBAAgB,KAAK,SAAS,MAAM;AAC1D,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,kCAAkC,SAAS;AAC5D,QAAM,aAAa,IAAI,QAAQ,UAAU,EAAE,aAAa,IAAI,gBAAgB,KAAK,CAAC;AAClF,QAAM,SAAS,WAAW,eAAe,IAAIC,MAAK,CAAC;AACnD,QAAM,aAAa,sCAAsC,WAAW,OAAO,MAAM;AAEjF,WAAS,QAAQ;AAEjB,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,kCAAkC,WAAkD;AAC3F,QAAM,WAAW,IAAIH,gBAAe;AACpC,WAAS,aAAa,YAAY,IAAII,wBAAuB,UAAU,WAAW,CAAC,CAAC;AACpF,WAAS,aAAa,UAAU,IAAIA,wBAAuB,UAAU,SAAS,CAAC,CAAC;AAEhF,MAAI,UAAU,IAAI,QAAQ;AACxB,aAAS,aAAa,MAAM,IAAIA,wBAAuB,UAAU,KAAK,CAAC,CAAC;AAAA,EAC1E;AAEA,WAAS,SAAS,UAAU,OAAO;AACnC,SAAO;AACT;AAEA,SAAS,sCACP,WACA,OACA,QACmD;AACnD,QAAM,oBAAoB,KAAK,IAAI,GAAG,KAAK,MAAO,UAAU,UAAU,SAAS,IAAK,KAAK,IAAI,MAAM,KAAK,CAAC,CAAC;AAC1G,QAAM,OAAO,OAAO,QAAQ,IAAIC,SAAQ,CAAC;AACzC,MAAI,aAAa,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAK,iBAAiB,CAAC,CAAC;AACrE,MAAI;AAEJ,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,UAAM,aAAa,yBAAyB,WAAW,QAAQ,MAAM,KAAK,IAAI,GAAG,aAAa,OAAO,CAAC;AAEtG,QAAI,CAAC,YAAY;AACf;AAAA,IACF;AAEA,WAAO;AAEP,QAAK,WAAW,UAAU,SAAS,KAAM,mBAAmB;AAC1D;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,MAAM;AACT,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,UAAU,UAAU,UAAU,UAAU,UAAU,KAAK,QAAQ,UAAU,UAAU,QAAQ,QAAQ;AAC1G,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,yBACP,WACA,QACA,MACA,YACmD;AACnD,QAAM,MAAM,OAAO;AACnB,QAAM,YAAY,KAAK,IAAI,KAAK,IAAI,YAAY,IAAM;AACtD,QAAM,YAAY,KAAK,IAAI,KAAK,IAAI,YAAY,IAAM;AACtD,QAAM,YAAY,KAAK,IAAI,KAAK,IAAI,YAAY,IAAM;AACtD,QAAM,cAAc,UAAU,UAAU,SAAS;AACjD,QAAM,WAAW,oBAAI,IAUlB;AACH,QAAM,qBAAqB,IAAI,MAAc,WAAW;AAExD,WAAS,cAAc,GAAG,cAAc,aAAa,eAAe,GAAG;AACrE,UAAM,iBAAiB,cAAc;AACrC,UAAM,WAAW,cAAc;AAC/B,UAAM,IAAI,UAAU,UAAU,cAAc;AAC5C,UAAM,IAAI,UAAU,UAAU,iBAAiB,CAAC;AAChD,UAAM,IAAI,UAAU,UAAU,iBAAiB,CAAC;AAChD,UAAM,UAAU,UAAU,QAAQ,cAAc;AAChD,UAAM,UAAU,UAAU,QAAQ,iBAAiB,CAAC;AACpD,UAAM,UAAU,UAAU,QAAQ,iBAAiB,CAAC;AACpD,UAAM,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS;AAChD,UAAM,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS;AAChD,UAAM,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS;AAChD,UAAM,aAAa,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,oBAAoB,SAAS,SAAS,OAAO,CAAC;AAC/F,UAAM,UAAU,SAAS,IAAI,UAAU,KAAK;AAAA,MAC1C,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,WAAW;AAAA,MACX,WAAW;AAAA,MACX,WAAW;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAEA,YAAQ,SAAS;AACjB,YAAQ,aAAa;AACrB,YAAQ,aAAa;AACrB,YAAQ,aAAa;AACrB,YAAQ,WAAW;AACnB,YAAQ,WAAW;AACnB,YAAQ,WAAW;AACnB,YAAQ,OAAO,UAAU,IAAI,QAAQ,KAAK;AAC1C,YAAQ,OAAO,UAAU,IAAI,WAAW,CAAC,KAAK;AAC9C,aAAS,IAAI,YAAY,OAAO;AAChC,uBAAmB,WAAW,IAAI;AAAA,EACpC;AAEA,QAAM,kBAA4B,CAAC;AACnC,QAAM,YAAsB,CAAC;AAC7B,QAAM,UAAoB,CAAC;AAC3B,QAAM,MAAgB,CAAC;AACvB,QAAM,oBAAoB,oBAAI,IAAoB;AAElD,QAAM,qBAAqB,CAAC,eAAuB;AACjD,UAAM,WAAW,kBAAkB,IAAI,UAAU;AAEjD,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,SAAS,IAAI,UAAU;AAEvC,QAAI,CAAC,WAAW,QAAQ,UAAU,GAAG;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,cAAc,KAAK,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO,CAAC;AAC5F,UAAM,QAAQ,UAAU,SAAS;AAEjC,cAAU,KAAK,QAAQ,YAAY,QAAQ,OAAO,QAAQ,YAAY,QAAQ,OAAO,QAAQ,YAAY,QAAQ,KAAK;AACtH,YAAQ,KAAK,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;AACjE,QAAI,KAAK,QAAQ,MAAM,QAAQ,OAAO,QAAQ,MAAM,QAAQ,KAAK;AACjE,sBAAkB,IAAI,YAAY,KAAK;AACvC,WAAO;AAAA,EACT;AAEA,WAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,QAAQ,SAAS,GAAG;AAChE,UAAM,IAAI,mBAAmB,mBAAmB,UAAU,QAAQ,KAAK,CAAC,CAAC;AACzE,UAAM,IAAI,mBAAmB,mBAAmB,UAAU,QAAQ,QAAQ,CAAC,CAAC,CAAC;AAC7E,UAAM,IAAI,mBAAmB,mBAAmB,UAAU,QAAQ,QAAQ,CAAC,CAAC,CAAC;AAE7E,QAAI,MAAM,UAAa,MAAM,UAAa,MAAM,QAAW;AACzD;AAAA,IACF;AAEA,QAAI,MAAM,KAAK,MAAM,KAAK,MAAM,GAAG;AACjC;AAAA,IACF;AAEA,QAAI,aAAa,WAAW,GAAG,GAAG,CAAC,KAAK,MAAU;AAChD;AAAA,IACF;AAEA,oBAAgB,KAAK,GAAG,GAAG,CAAC;AAAA,EAC9B;AAEA,MAAI,gBAAgB,SAAS,MAAM,UAAU,UAAU,UAAU,UAAU,QAAQ;AACjF,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,UAAU,UAAU;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,GAAW,GAAW,GAAW;AAC5D,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,IAAI,CAAC;AACrB,QAAM,KAAK,KAAK,IAAI,CAAC;AAErB,MAAI,MAAM,MAAM,MAAM,IAAI;AACxB,WAAO,KAAK,IAAI,OAAO;AAAA,EACzB;AAEA,MAAI,MAAM,MAAM,MAAM,IAAI;AACxB,WAAO,KAAK,IAAI,OAAO;AAAA,EACzB;AAEA,SAAO,KAAK,IAAI,OAAO;AACzB;AAEA,SAAS,aAAa,WAAqB,GAAW,GAAW,GAAW;AAC1E,QAAM,KAAK,UAAU,IAAI,CAAC;AAC1B,QAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AAC9B,QAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AAC9B,QAAM,KAAK,UAAU,IAAI,CAAC;AAC1B,QAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AAC9B,QAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AAC9B,QAAM,KAAK,UAAU,IAAI,CAAC;AAC1B,QAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AAC9B,QAAM,KAAK,UAAU,IAAI,IAAI,CAAC;AAC9B,QAAM,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE;AACzC,QAAM,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,EAAE;AACzC,QAAM,QAAQ,UAAU,IAAI,EAAE;AAE9B,SAAO,KAAK,KAAK,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI;AAChF;AAEA,SAAS,uBAAuB,OAAgD,MAAY,gBAAwB;AAClH,QAAM,WACJ,UAAU,SACN,IAAIC,aAAY,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,IACpE,UAAU,WACR,IAAI,eAAe,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,iBAAiB,IAAI,CAAC,CAAC,IACrI,UAAU,aACR,IAAI,iBAAiB,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,GAAG,cAAc,IAC7J,IAAI,aAAa,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,GAAG,cAAc;AAC/G,QAAM,oBAAoB,SAAS,aAAa,UAAU;AAC1D,QAAM,kBAAkB,SAAS,aAAa,QAAQ;AACtD,QAAM,cAAc,SAAS,aAAa,IAAI;AAC9C,QAAM,QAAQ,SAAS,SAAS;AAEhC,QAAM,YAAY;AAAA,IAChB,SAAS,QAAQ,MAAM,KAAK,MAAM,KAA0B,IAAI,MAAM,KAAK,EAAE,QAAQ,kBAAkB,MAAM,GAAG,CAAC,GAAG,UAAU,KAAK;AAAA,IACnI,SAAS,MAAM,KAAK,gBAAgB,KAA0B;AAAA,IAC9D,WAAW,MAAM,KAAK,kBAAkB,KAA0B;AAAA,IAClE,KAAK,cAAc,MAAM,KAAK,YAAY,KAA0B,IAAI,CAAC;AAAA,EAC3E;AAEA,WAAS,QAAQ;AACjB,SAAO;AACT;AAEA,eAAe,uBAAuB,UAA+C;AACnF,QAAM,WAAW,YAAY;AAAA,IAC3B,OAAO;AAAA,IACP,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,EACb;AAEA,SAAO;AAAA,IACL,kBAAkB,MAAM,0BAA0B,SAAS,gBAAgB,gCAAgC,QAAQ,CAAC;AAAA,IACpH,OAAO,SAAS;AAAA,IAChB,IAAI,SAAS;AAAA,IACb,gBAAgB,SAAS,aAAa;AAAA,IACtC,0BAA0B,MAAM;AAAA,MAC9B,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS,aAAa;AAAA,MACtB,SAAS,aAAa;AAAA,IACxB;AAAA,IACA,MAAM,SAAS;AAAA,IACf,eAAe,MAAM,0BAA0B,SAAS,aAAa;AAAA,IACrE,iBAAiB,SAAS,aAAa;AAAA,IACvC,MAAM,SAAS;AAAA,EACjB;AACF;AAEA,SAAS,gCAAgC,UAAoB;AAC3D,SAAO,SAAS,aAAa,aACzB,6BAA6B,SAAS,OAAO,SAAS,aAAa,WAAW,SAAS,iBAAiB,KAAK,IAC7G;AACN;AAEA,SAAS,iBAAiB,UAAkB,QAAc,SAAgB,UAAiB;AACzF,QAAM,QAAQ,qBAAqB,MAAM;AACzC,QAAM,SAAS,SAAS,CAAC,KAAK,KAAK,GAAG,GAAG,CAAC;AAC1C,QAAM,SAAS,KAAK,IAAI,SAAS,KAAK,CAAC,KAAK,OAAS,IAAI,SAAS,KAAK;AACvE,QAAM,SAAS,KAAK,IAAI,SAAS,KAAK,CAAC,KAAK,OAAS,IAAI,SAAS,KAAK;AACvE,QAAM,UAAU,UAAU,KAAK;AAC/B,QAAM,UAAU,UAAU,KAAK;AAE/B,SAAO,SAAS,QAAQ,CAAC,WAAW;AAClC,UAAM,SAAS,QAAQ,QAAQ,MAAM;AACrC,WAAO,CAAC,QAAQ,QAAQ,MAAM,CAAC,IAAI,SAAS,SAAS,QAAQ,QAAQ,MAAM,CAAC,IAAI,SAAS,OAAO;AAAA,EAClG,CAAC;AACH;AAEA,SAAS,qBAAqB,QAAc;AAC1C,QAAM,mBAAmB,cAAc,MAAM;AAC7C,QAAM,YAAY,KAAK,IAAI,iBAAiB,CAAC,IAAI,OAAO,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,GAAG,CAAC;AACpF,QAAM,IAAI,cAAc,UAAU,WAAW,gBAAgB,CAAC;AAC9D,QAAM,IAAI,cAAc,UAAU,kBAAkB,CAAC,CAAC;AAEtD,SAAO,EAAE,GAAG,EAAE;AAChB;AAEA,eAAe,0BAA0B,QAAiB;AACxD,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,WAAW,OAAO,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,MAAM,MAAM;AACnC,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAM,SAAS,MAAM,KAAK,YAAY;AACtC,SAAO,QAAQ,KAAK,QAAQ,0BAA0B,WAAW,SAAS,IAAI,WAAW,MAAM,CAAC,CAAC;AACnG;AAEA,eAAe,sCACb,iBACA,iBACA,iBACA,iBACA;AACA,MAAI,CAAC,mBAAmB,CAAC,iBAAiB;AACxC,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,oBAAoB,eAAe,OAAO,sBAAsB,aAAa;AACtF,WAAO;AAAA,EACT;AAEA,QAAM,CAAC,WAAW,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC/C,gBAAgB,eAAe;AAAA,IAC/B,gBAAgB,eAAe;AAAA,EACjC,CAAC;AACD,QAAM,QAAQ,KAAK,IAAI,WAAW,SAAS,GAAG,WAAW,SAAS,CAAC;AACnE,QAAM,SAAS,KAAK,IAAI,WAAW,UAAU,GAAG,WAAW,UAAU,CAAC;AACtE,QAAM,SAAS,IAAI,gBAAgB,OAAO,MAAM;AAChD,QAAM,UAAU,OAAO,WAAW,IAAI;AAEtC,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,QAAQ,gBAAgB,OAAO,MAAM;AACvD,QAAM,eAAe,KAAK,MAAM,QAAQ,eAAe,IAAI,GAAG;AAC9D,QAAM,eAAe,KAAK,MAAM,QAAQ,eAAe,IAAI,GAAG;AAE9D,WAAS,QAAQ,GAAG,QAAQ,UAAU,KAAK,QAAQ,SAAS,GAAG;AAC7D,cAAU,KAAK,KAAK,IAAI;AACxB,cAAU,KAAK,QAAQ,CAAC,IAAI,WAAW,OAAO,KAAK,KAAK;AACxD,cAAU,KAAK,QAAQ,CAAC,IAAI,WAAW,OAAO,KAAK,KAAK;AACxD,cAAU,KAAK,QAAQ,CAAC,IAAI;AAAA,EAC9B;AAEA,UAAQ,aAAa,WAAW,GAAG,CAAC;AACpC,QAAM,OAAO,MAAM,OAAO,cAAc,EAAE,MAAM,YAAY,CAAC;AAC7D,QAAM,SAAS,MAAM,KAAK,YAAY;AACtC,SAAO,yBAAyB,SAAS,IAAI,WAAW,MAAM,CAAC,CAAC;AAClE;AAEA,eAAe,gBAAgB,QAAiB;AAC9C,MAAI,CAAC,UAAU,OAAO,oBAAoB,eAAe,OAAO,sBAAsB,aAAa;AACjG,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,MAAM,MAAM;AACnC,QAAM,OAAO,MAAM,SAAS,KAAK;AACjC,QAAM,SAAS,MAAM,kBAAkB,IAAI;AAC3C,QAAM,SAAS,IAAI,gBAAgB,OAAO,OAAO,OAAO,MAAM;AAC9D,QAAM,UAAU,OAAO,WAAW,MAAM,EAAE,oBAAoB,KAAK,CAAC;AAEpE,MAAI,CAAC,SAAS;AACZ,WAAO,MAAM;AACb,WAAO;AAAA,EACT;AAEA,UAAQ,UAAU,QAAQ,GAAG,CAAC;AAC9B,SAAO,MAAM;AACb,QAAM,YAAY,QAAQ,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAExE,SAAO;AAAA,IACL,QAAQ,UAAU;AAAA,IAClB,QAAQ,UAAU;AAAA,IAClB,OAAO,UAAU;AAAA,EACnB;AACF;AAEA,SAAS,QAAQ,OAAe;AAC9B,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AACvC;AAEA,SAAS,SAAS,OAA2B;AAC3C,MAAI,SAAS;AACb,QAAM,QAAQ,CAAC,SAAS;AACtB,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC,CAAC;AACD,SAAO,KAAK,MAAM;AACpB;;;AC5pCO,SAAS,yBAAyB,QAAuB;AAC9D,QAAM,YAAY,oBAAI,IAAoB;AAE1C,SAAO;AAAA,IACL,UAAU;AACR,gBAAU,QAAQ,CAAC,QAAQ;AACzB,YAAI,gBAAgB,GAAG;AAAA,MACzB,CAAC;AACD,gBAAU,MAAM;AAAA,IAClB;AAAA,IACA,QAAQ,MAAc;AACpB,YAAM,WAAW,UAAU,IAAI,IAAI;AAEnC,UAAI,UAAU;AACZ,eAAO;AAAA,MACT;AAEA,YAAM,OAAO,OAAO,MAAM,KAAK,CAAC,UAAU,MAAM,SAAS,IAAI;AAE7D,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AAEA,YAAM,QAAQ,IAAI,WAAW,KAAK,MAAM,UAAU;AAClD,YAAM,IAAI,KAAK,KAAK;AACpB,YAAM,MAAM,IAAI,gBAAgB,IAAI,KAAK,CAAC,MAAM,MAAM,GAAG,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC;AACjF,gBAAU,IAAI,MAAM,GAAG;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,mCAAmC,QAA+B;AAChF,SAAO,yBAAyB,MAAM;AACxC;AAEO,SAASC,gCAA+B,QAA+B,SAA2D;AACvI,SAAO,+BAA0B,QAAQ,OAAO;AAClD;AAEO,SAASC,+BAA8B,aAAyB,SAA6D;AAClI,SAAO,8BAA4B,aAAa,OAAO;AACzD;AAEO,SAASC,iCACd,OACA,SACA;AACA,SAAO,gCAAsC,OAAO,OAAO;AAC7D;","names":["AmbientLight","BackSide","Box3","BoxGeometry","BufferGeometry","DirectionalLight","DoubleSide","Euler","Float32BufferAttribute","FrontSide","Group","InstancedMesh","HemisphereLight","LOD","Matrix4","Mesh","MeshStandardMaterial","Object3D","PointLight","Quaternion","SRGBColorSpace","SpotLight","TextureLoader","RepeatWrapping","Vector3","GLTFLoader","MTLLoader","OBJLoader","Euler","Matrix4","Quaternion","Vector3","lodObject","textureLoader","TextureLoader","gltfLoader","GLTFLoader","mtlLoader","MTLLoader","Group","AmbientLight","Mesh","InstancedMesh","BufferGeometry","MeshStandardMaterial","SRGBColorSpace","path","Box3","BoxGeometry","BufferGeometry","Float32BufferAttribute","Group","Mesh","MeshStandardMaterial","RepeatWrapping","Scene","SRGBColorSpace","TextureLoader","Vector3","GLTFLoader","MTLLoader","OBJLoader","gltfLoader","GLTFLoader","mtlLoader","MTLLoader","modelTextureLoader","TextureLoader","OBJLoader","mtlLoader","patchMtlTextureReferences","modelTextureLoader","RepeatWrapping","SRGBColorSpace","Mesh","MeshStandardMaterial","gltfLoader","Group","BufferGeometry","Scene","slugify","Box3","Float32BufferAttribute","Vector3","BoxGeometry","createWebHammerEngineBundleZip","parseWebHammerEngineBundleZip","externalizeWebHammerEngineScene"]}
|
|
1
|
+
{"version":3,"sources":["../src/loader.ts","../src/object-factory.ts","../src/bundle.ts"],"sourcesContent":["import type { Asset, MaterialRenderSide, PropPhysics, SceneSkyboxSettings, Transform, Vec3 } from \"@ggez/shared\";\nimport { resolveInstancingSourceNode, resolveSceneGraph, vec3 } from \"@ggez/shared\";\nimport {\n AmbientLight,\n BackSide,\n Box3,\n BoxGeometry,\n BufferGeometry,\n Color,\n DirectionalLight,\n DoubleSide,\n EquirectangularReflectionMapping,\n Euler,\n Fog,\n Float32BufferAttribute,\n FrontSide,\n Group,\n InstancedMesh,\n HemisphereLight,\n LOD,\n Matrix4,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n PointLight,\n Quaternion,\n SRGBColorSpace,\n Scene,\n SpotLight,\n Texture,\n TextureLoader,\n RepeatWrapping,\n Vector3\n} from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport { HDRLoader } from \"three/examples/jsm/loaders/HDRLoader.js\";\nimport { MTLLoader } from \"three/examples/jsm/loaders/MTLLoader.js\";\nimport { OBJLoader } from \"three/examples/jsm/loaders/OBJLoader.js\";\nimport {\n isRuntimeBundle,\n isRuntimeScene,\n parseRuntimeScene,\n type RuntimeScene\n} from \"@ggez/runtime-format\";\nimport {\n createWebHammerSceneObjectFactory,\n extractPhysics as extractNodePhysics,\n findPrimaryLight as findNodePrimaryLight\n} from \"./object-factory\";\nimport type {\n WebHammerEngineBundle,\n WebHammerEngineModelNode,\n WebHammerEngineGeometryNode,\n WebHammerEngineNode,\n WebHammerEngineScene,\n WebHammerExportGeometry,\n WebHammerExportGeometryLod,\n WebHammerExportModelLod,\n WebHammerExportMaterial\n} from \"./types\";\n\ntype TextureSlot = \"baseColorTexture\" | \"metallicRoughnessTexture\" | \"normalTexture\";\n\nexport type WebHammerAssetResolverContext =\n | {\n kind: \"model\";\n node: Extract<WebHammerEngineNode, { kind: \"model\" }>;\n asset?: Asset;\n path: string;\n format: \"gltf\" | \"obj\";\n }\n | {\n kind: \"texture\";\n material: WebHammerExportMaterial;\n path: string;\n slot: TextureSlot;\n }\n | {\n kind: \"skybox\";\n path: string;\n skybox: SceneSkyboxSettings;\n };\n\nexport type WebHammerSceneLoaderOptions = {\n applyToScene?: Scene;\n castShadow?: boolean;\n lod?: WebHammerSceneLodOptions;\n receiveShadow?: boolean;\n resolveAssetUrl?: (context: WebHammerAssetResolverContext) => Promise<string> | string;\n};\n\nexport type WebHammerSceneLodOptions = {\n lowDistance: number;\n midDistance: number;\n};\n\nexport type ThreeRuntimeSceneInstance = {\n dispose: () => void;\n entities: WebHammerEngineScene[\"entities\"];\n lights: Object3D[];\n nodesById: Map<string, Object3D>;\n physicsDescriptors: Array<{\n nodeId: string;\n object: Object3D;\n physics: PropPhysics;\n }>;\n root: Group;\n scene: WebHammerEngineScene;\n};\n\nexport type WebHammerLoadedScene = ThreeRuntimeSceneInstance & {\n nodes: ThreeRuntimeSceneInstance[\"nodesById\"];\n physicsNodes: ThreeRuntimeSceneInstance[\"physicsDescriptors\"];\n};\n\nexport type ThreeRuntimeAssetResolverContext = WebHammerAssetResolverContext;\nexport type ThreeRuntimeSceneInstanceOptions = WebHammerSceneLoaderOptions;\nexport type ThreeRuntimeSceneLodOptions = WebHammerSceneLodOptions;\n\nconst textureLoader = new TextureLoader();\nconst gltfLoader = new GLTFLoader();\nconst hdrLoader = new HDRLoader();\nconst mtlLoader = new MTLLoader();\n\nexport function isWebHammerEngineScene(value: unknown): value is WebHammerEngineScene {\n return isRuntimeScene(value);\n}\n\nexport function isWebHammerEngineBundle(value: unknown): value is WebHammerEngineBundle {\n return isRuntimeBundle(value);\n}\n\nexport function parseWebHammerEngineScene(text: string): WebHammerEngineScene {\n return parseRuntimeScene(text);\n}\n\nexport async function fetchWebHammerEngineScene(url: string, init?: RequestInit): Promise<WebHammerEngineScene> {\n const response = await fetch(url, init);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch engine scene: ${response.status} ${response.statusText}`);\n }\n\n return parseWebHammerEngineScene(await response.text());\n}\n\nexport async function createThreeRuntimeSceneInstance(\n input: RuntimeScene | string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<ThreeRuntimeSceneInstance> {\n const engineScene = typeof input === \"string\" ? parseRuntimeScene(input) : parseRuntimeScene(JSON.stringify(input));\n const root = new Group();\n const nodesById = new Map<string, Object3D>();\n const lights: Object3D[] = [];\n const physicsDescriptors: ThreeRuntimeSceneInstance[\"physicsDescriptors\"] = [];\n const runtimeNodesById = new Map(engineScene.nodes.map((node) => [node.id, node]));\n const sceneGraph = resolveSceneGraph(engineScene.nodes, engineScene.entities);\n const objectFactory = createWebHammerSceneObjectFactory(engineScene, options);\n const createdObjects = await Promise.all(\n engineScene.nodes.map(async (node) => [node.id, await objectFactory.createNodeObject(node)] as const)\n );\n const attachedNodeIds = new Set<string>();\n const attachStack = new Set<string>();\n\n root.name = \"Web Hammer Scene\";\n root.userData.webHammer = {\n metadata: engineScene.metadata,\n settings: engineScene.settings\n };\n\n if (options.applyToScene) {\n await applyWebHammerWorldSettings(options.applyToScene, engineScene, options);\n }\n\n const worldAmbient = createWorldAmbientLight(engineScene);\n\n if (worldAmbient) {\n root.add(worldAmbient);\n lights.push(worldAmbient);\n }\n\n createdObjects.forEach(([nodeId, object]) => {\n nodesById.set(nodeId, object);\n });\n\n const attachNode = (nodeId: string) => {\n if (attachedNodeIds.has(nodeId)) {\n return;\n }\n\n const node = runtimeNodesById.get(nodeId);\n const object = nodesById.get(nodeId);\n\n if (!node || !object) {\n return;\n }\n\n if (attachStack.has(nodeId)) {\n root.add(object);\n attachedNodeIds.add(nodeId);\n return;\n }\n\n attachStack.add(nodeId);\n\n const parentObject =\n node.parentId && node.parentId !== node.id\n ? nodesById.get(node.parentId)\n : undefined;\n\n if (parentObject && !attachStack.has(node.parentId!)) {\n attachNode(node.parentId!);\n parentObject.add(object);\n } else {\n root.add(object);\n }\n\n attachStack.delete(nodeId);\n attachedNodeIds.add(nodeId);\n };\n\n for (const node of engineScene.nodes) {\n attachNode(node.id);\n }\n\n const instancingObjects = await objectFactory.createInstancingObjects();\n\n instancingObjects.forEach((object) => {\n root.add(object);\n });\n\n for (const node of engineScene.nodes) {\n const object = nodesById.get(node.id);\n\n if (!object) {\n continue;\n }\n\n const light = findNodePrimaryLight(object);\n\n if (light) {\n lights.push(light);\n }\n\n const physics = extractNodePhysics(node);\n\n if (physics?.enabled) {\n physicsDescriptors.push({\n nodeId: node.id,\n object,\n physics\n });\n }\n }\n\n return {\n dispose() {\n disposeThreeRuntimeSceneInstance(root);\n },\n entities: engineScene.entities.map((entity) => ({\n ...entity,\n transform: sceneGraph.entityWorldTransforms.get(entity.id) ?? entity.transform\n })),\n lights,\n nodesById,\n physicsDescriptors,\n root,\n scene: engineScene\n };\n}\n\nexport async function loadWebHammerEngineScene(\n input: WebHammerEngineScene | string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<WebHammerLoadedScene> {\n const instance = await createThreeRuntimeSceneInstance(input, options);\n\n return {\n ...instance,\n nodes: instance.nodesById,\n physicsNodes: instance.physicsDescriptors\n };\n}\n\nexport async function loadWebHammerEngineSceneFromUrl(\n url: string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<WebHammerLoadedScene> {\n const scene = await fetchWebHammerEngineScene(url);\n return loadWebHammerEngineScene(scene, options);\n}\n\nexport async function loadThreeRuntimeSceneInstanceFromUrl(\n url: string,\n options: WebHammerSceneLoaderOptions = {}\n): Promise<ThreeRuntimeSceneInstance> {\n const scene = await fetchWebHammerEngineScene(url);\n return createThreeRuntimeSceneInstance(scene, options);\n}\n\ntype AppliedWorldSettingsState = {\n requestId: number;\n skyboxTexture?: Texture;\n};\n\nconst APPLIED_WORLD_SETTINGS_KEY = \"__webHammerWorldSettings\";\n\nexport async function applyWebHammerWorldSettings(\n target: Scene,\n engineScene: Pick<WebHammerEngineScene, \"settings\">,\n options: Pick<WebHammerSceneLoaderOptions, \"resolveAssetUrl\"> = {}\n) {\n const state = getAppliedWorldSettingsState(target);\n state.requestId += 1;\n disposeAppliedSkybox(target, state);\n\n const { fogColor, fogFar, fogNear } = engineScene.settings.world;\n target.fog = fogFar > fogNear ? new Fog(new Color(fogColor), fogNear, fogFar) : null;\n\n const skybox = engineScene.settings.world.skybox;\n\n if (!skybox.enabled || !skybox.source) {\n return;\n }\n\n const requestId = state.requestId;\n\n try {\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"skybox\",\n path: skybox.source,\n skybox\n })\n : skybox.source;\n const texture = await loadSkyboxTexture(resolvedPath, skybox);\n\n if (getAppliedWorldSettingsState(target).requestId !== requestId) {\n texture.dispose();\n return;\n }\n\n target.background = texture;\n target.backgroundBlurriness = skybox.blur;\n target.backgroundIntensity = skybox.intensity;\n target.environment = skybox.affectsLighting ? texture : null;\n target.environmentIntensity = skybox.affectsLighting ? skybox.lightingIntensity : 1;\n state.skyboxTexture = texture;\n } catch {\n if (getAppliedWorldSettingsState(target).requestId === requestId) {\n disposeAppliedSkybox(target, state);\n }\n }\n}\n\nexport function clearWebHammerWorldSettings(target: Scene) {\n const state = getAppliedWorldSettingsState(target);\n state.requestId += 1;\n disposeAppliedSkybox(target, state);\n target.fog = null;\n}\n\nexport const applyRuntimeWorldSettingsToThreeScene = applyWebHammerWorldSettings;\nexport const clearRuntimeWorldSettingsFromThreeScene = clearWebHammerWorldSettings;\n\nfunction createWorldAmbientLight(engineScene: WebHammerEngineScene) {\n const { ambientColor, ambientIntensity } = engineScene.settings.world;\n\n if (ambientIntensity <= 0) {\n return undefined;\n }\n\n const light = new AmbientLight(ambientColor, ambientIntensity);\n light.name = \"World Ambient\";\n light.userData.webHammer = {\n source: \"world-settings\"\n };\n\n return light;\n}\n\nfunction getAppliedWorldSettingsState(target: Scene): AppliedWorldSettingsState {\n const userData = target.userData as Record<string, AppliedWorldSettingsState | undefined>;\n const existing = userData[APPLIED_WORLD_SETTINGS_KEY];\n\n if (existing) {\n return existing;\n }\n\n const created: AppliedWorldSettingsState = {\n requestId: 0\n };\n userData[APPLIED_WORLD_SETTINGS_KEY] = created;\n return created;\n}\n\nfunction disposeAppliedSkybox(target: Scene, state: AppliedWorldSettingsState) {\n if (state.skyboxTexture) {\n if (target.background === state.skyboxTexture) {\n target.background = null;\n }\n\n if (target.environment === state.skyboxTexture) {\n target.environment = null;\n }\n\n state.skyboxTexture.dispose();\n state.skyboxTexture = undefined;\n }\n\n target.backgroundBlurriness = 0;\n target.backgroundIntensity = 1;\n target.environmentIntensity = 1;\n}\n\nfunction disposeThreeRuntimeSceneInstance(root: Group) {\n const geometries = new Set<BufferGeometry>();\n const materials = new Set<MeshStandardMaterial>();\n const textures = new Set<Texture>();\n\n root.traverse((object) => {\n if (!(object instanceof Mesh || object instanceof InstancedMesh)) {\n return;\n }\n\n if (object.geometry instanceof BufferGeometry) {\n geometries.add(object.geometry);\n }\n\n const objectMaterials = Array.isArray(object.material) ? object.material : [object.material];\n\n objectMaterials.forEach((material) => {\n if (!(material instanceof MeshStandardMaterial)) {\n return;\n }\n\n materials.add(material);\n\n if (material.map) {\n textures.add(material.map);\n }\n\n if (material.normalMap) {\n textures.add(material.normalMap);\n }\n\n if (material.metalnessMap) {\n textures.add(material.metalnessMap);\n }\n\n if (material.roughnessMap) {\n textures.add(material.roughnessMap);\n }\n });\n });\n\n root.removeFromParent();\n geometries.forEach((geometry) => {\n geometry.dispose();\n });\n materials.forEach((material) => {\n material.dispose();\n });\n textures.forEach((texture) => {\n texture.dispose();\n });\n}\n\nasync function loadSkyboxTexture(path: string, skybox: SceneSkyboxSettings) {\n const texture = skybox.format === \"hdr\"\n ? await hdrLoader.loadAsync(path)\n : await textureLoader.loadAsync(path);\n\n texture.mapping = EquirectangularReflectionMapping;\n\n if (skybox.format === \"image\") {\n texture.colorSpace = SRGBColorSpace;\n }\n\n return texture;\n}\n\nasync function createObjectForNode(\n node: WebHammerEngineNode,\n assetsById: Map<string, Asset>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const anchor = new Group();\n const content = new Group();\n const pivot = node.transform.pivot;\n\n anchor.name = node.name;\n applyTransform(anchor, node.transform);\n anchor.userData.webHammer = {\n data: node.data,\n hooks: node.hooks,\n id: node.id,\n kind: node.kind,\n metadata: node.metadata,\n tags: node.tags\n };\n\n if (pivot) {\n content.position.set(-pivot.x, -pivot.y, -pivot.z);\n }\n\n anchor.add(content);\n\n if (node.kind === \"light\") {\n const light = createThreeLight(node);\n\n if (light) {\n content.add(light);\n }\n\n return anchor;\n }\n\n if (node.kind === \"model\") {\n const modelObject = await createModelObject(node, assetsById.get(node.data.assetId), options);\n const lodObject = await createLodObjectForModelNode(node, modelObject, assetsById, options);\n content.add(lodObject ?? modelObject);\n return anchor;\n }\n\n if (node.kind === \"instancing\") {\n anchor.visible = false;\n return anchor;\n }\n\n if (node.kind === \"group\") {\n return anchor;\n }\n\n const lodObject = await createLodObjectForGeometryNode(node, materialCache, textureCache, options);\n\n if (lodObject) {\n content.add(lodObject);\n }\n\n return anchor;\n}\n\nasync function createInstancingObjects(\n engineScene: WebHammerEngineScene,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const batches = new Map<string, Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>>();\n\n engineScene.nodes.forEach((node) => {\n if (node.kind !== \"instancing\") {\n return;\n }\n\n const sourceNode = resolveInstancingSourceNode(engineScene.nodes, node.data.sourceNodeId);\n\n if (!sourceNode || !(sourceNode.kind === \"brush\" || sourceNode.kind === \"mesh\" || sourceNode.kind === \"primitive\")) {\n return;\n }\n\n const instances = batches.get(sourceNode.id);\n\n if (instances) {\n instances.push(node);\n return;\n }\n\n batches.set(sourceNode.id, [node]);\n });\n\n const objects: Object3D[] = [];\n\n for (const [sourceNodeId, instances] of batches) {\n const sourceNode = engineScene.nodes.find((node) => node.id === sourceNodeId);\n\n if (!sourceNode || !(sourceNode.kind === \"brush\" || sourceNode.kind === \"mesh\" || sourceNode.kind === \"primitive\")) {\n continue;\n }\n\n const object = await createInstancedObjectForGeometryNode(sourceNode, instances, sceneGraph, materialCache, textureCache, options);\n\n if (object) {\n objects.push(object);\n }\n }\n\n return objects;\n}\n\nasync function createInstancedObjectForGeometryNode(\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const baseGroup = await createInstancedGeometryObject(sourceNode.geometry, sourceNode, instances, sceneGraph, materialCache, textureCache, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !sourceNode.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${sourceNode.name}:InstancingLOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of sourceNode.lods) {\n const levelGroup = await createInstancedGeometryObject(\n level.geometry,\n sourceNode,\n instances,\n sceneGraph,\n materialCache,\n textureCache,\n options,\n level\n );\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n levelOrder: [\"high\", ...(sourceNode.lods ?? []).map((level) => level.level)],\n sourceNodeId: sourceNode.id\n };\n return lod;\n}\n\nasync function createInstancedGeometryObject(\n geometry: WebHammerExportGeometry,\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const pivot = sourceNode.transform.pivot ?? vec3(0, 0, 0);\n\n for (const primitive of geometry.primitives) {\n const primitiveGeometry = new BufferGeometry();\n primitiveGeometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n primitiveGeometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n primitiveGeometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n primitiveGeometry.setIndex(primitive.indices);\n primitiveGeometry.computeBoundingBox();\n primitiveGeometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, materialCache, textureCache, options);\n const mesh = new InstancedMesh(primitiveGeometry, material, instances.length);\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${sourceNode.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}:instanced`;\n mesh.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n sourceNodeId: sourceNode.id\n };\n\n instances.forEach((instance, index) => {\n const worldTransform = sceneGraph.nodeWorldTransforms.get(instance.id) ?? instance.transform;\n mesh.setMatrixAt(index, composeInstancedMatrix(worldTransform, pivot));\n });\n\n mesh.instanceMatrix.needsUpdate = true;\n group.add(mesh);\n }\n\n group.name = `${sourceNode.name}:instances`;\n group.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n sourceNodeId: sourceNode.id\n };\n return group;\n}\n\nasync function createLodObjectForGeometryNode(\n node: WebHammerEngineGeometryNode,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const baseGroup = await createGeometryObject(node.geometry, node, materialCache, textureCache, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of node.lods) {\n const levelGroup = await createGeometryObject(level.geometry, node, materialCache, textureCache, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createLodObjectForModelNode(\n node: WebHammerEngineModelNode,\n baseModel: Object3D,\n assetsById: Map<string, Asset>,\n options: WebHammerSceneLoaderOptions\n) {\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return undefined;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseModel, 0);\n\n for (const level of node.lods) {\n const levelModel = await createModelObject(node, assetsById.get(level.assetId), options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelModel, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createGeometryObject(\n geometry: WebHammerExportGeometry,\n node: Pick<WebHammerEngineNode, \"id\" | \"name\">,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const meshes: Mesh[] = [];\n\n for (const primitive of geometry.primitives) {\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n geometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n geometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n geometry.setIndex(primitive.indices);\n geometry.computeBoundingBox();\n geometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, materialCache, textureCache, options);\n const mesh = new Mesh(geometry, material);\n\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${node.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}`;\n mesh.userData.webHammer = {\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n nodeId: node.id\n };\n\n meshes.push(mesh);\n }\n\n meshes.forEach((mesh) => {\n group.add(mesh);\n });\n\n return group;\n}\n\nfunction resolveSceneLodOptions(lod?: WebHammerSceneLodOptions): WebHammerSceneLodOptions | undefined {\n if (!lod) {\n return undefined;\n }\n\n const midDistance = Math.max(0, lod.midDistance);\n const lowDistance = Math.max(midDistance + 0.01, lod.lowDistance);\n\n return {\n lowDistance,\n midDistance\n };\n}\n\nasync function createThreeMaterial(\n materialSpec: WebHammerExportMaterial,\n materialCache: Map<string, MeshStandardMaterial>,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const cached = materialCache.get(materialSpec.id);\n\n if (cached) {\n return cached;\n }\n\n const material = new MeshStandardMaterial({\n color: materialSpec.color,\n metalness: materialSpec.metallicFactor,\n roughness: materialSpec.roughnessFactor,\n side: resolveMaterialSide(materialSpec.side)\n });\n\n if (materialSpec.baseColorTexture) {\n const texture = await loadTexture(materialSpec.baseColorTexture, materialSpec, \"baseColorTexture\", textureCache, options);\n texture.colorSpace = SRGBColorSpace;\n material.map = texture;\n }\n\n if (materialSpec.normalTexture) {\n material.normalMap = await loadTexture(materialSpec.normalTexture, materialSpec, \"normalTexture\", textureCache, options);\n }\n\n if (materialSpec.metallicRoughnessTexture) {\n const ormTexture = await loadTexture(\n materialSpec.metallicRoughnessTexture,\n materialSpec,\n \"metallicRoughnessTexture\",\n textureCache,\n options\n );\n material.metalnessMap = ormTexture;\n material.roughnessMap = ormTexture;\n }\n\n material.name = materialSpec.name;\n material.needsUpdate = true;\n materialCache.set(materialSpec.id, material);\n\n return material;\n}\n\nasync function loadTexture(\n path: string,\n material: WebHammerExportMaterial,\n slot: TextureSlot,\n textureCache: Map<string, Promise<Texture>>,\n options: WebHammerSceneLoaderOptions\n) {\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material,\n path,\n slot\n })\n : path;\n const cacheKey = `${slot}:${resolvedPath}`;\n const cached = textureCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const pendingTexture = textureLoader.loadAsync(resolvedPath);\n const configuredTexture = pendingTexture.then((texture) => {\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n return texture;\n });\n textureCache.set(\n cacheKey,\n configuredTexture\n );\n return configuredTexture;\n}\n\nasync function createModelObject(\n node: Extract<WebHammerEngineNode, { kind: \"model\" }>,\n asset: Asset | undefined,\n options: WebHammerSceneLoaderOptions,\n lodLevel?: WebHammerExportModelLod\n) {\n const fallback = createMissingModelFallback(asset);\n const modelPath = asset?.path ?? node.data.path;\n\n if (!modelPath) {\n return fallback;\n }\n\n const format = resolveModelFormat(asset?.metadata.modelFormat, modelPath);\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n asset,\n format,\n kind: \"model\",\n node,\n path: modelPath\n })\n : modelPath;\n const texturePath = readAssetString(asset, \"texturePath\");\n const resolvedTexturePath =\n texturePath && options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material: {\n color: \"#ffffff\",\n id: `material:model-texture:${node.id}`,\n metallicFactor: 0,\n name: `${node.name} Model Texture`,\n roughnessFactor: 1\n },\n path: texturePath,\n slot: \"baseColorTexture\"\n })\n : texturePath;\n\n try {\n const object =\n format === \"obj\"\n ? await loadObjModel(asset, resolvedPath, resolvedTexturePath)\n : await loadGltfModel(asset, resolvedPath);\n\n object.name = `${node.name}:${lodLevel?.level ?? \"high\"}`;\n object.userData.webHammer = {\n ...(object.userData.webHammer ?? {}),\n lodLevel: lodLevel?.level ?? \"high\",\n nodeId: node.id\n };\n return object;\n } catch {\n fallback.name = `${node.name}:${lodLevel?.level ?? \"high\"}:fallback`;\n fallback.userData.webHammer = {\n ...(fallback.userData.webHammer ?? {}),\n lodLevel: lodLevel?.level ?? \"high\",\n nodeId: node.id\n };\n return fallback;\n }\n}\n\nasync function loadObjModel(asset: Asset | undefined, resolvedPath: string, resolvedTexturePath?: string) {\n const objLoader = new OBJLoader();\n const mtlText = readAssetString(asset, \"materialMtlText\");\n\n if (mtlText) {\n const materialCreator = mtlLoader.parse(patchMtlTextureReferences(mtlText, resolvedTexturePath), \"\");\n materialCreator.preload();\n objLoader.setMaterials(materialCreator);\n }\n\n const object = await objLoader.loadAsync(resolvedPath);\n\n if (!mtlText && resolvedTexturePath) {\n const texture = await textureLoader.loadAsync(resolvedTexturePath);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.colorSpace = SRGBColorSpace;\n\n object.traverse((child: Object3D) => {\n if (child instanceof Mesh) {\n child.material = new MeshStandardMaterial({\n map: texture,\n metalness: 0.12,\n roughness: 0.76\n });\n }\n });\n }\n\n centerObject(object, readAssetVec3(asset, \"nativeCenter\"));\n return object;\n}\n\nasync function loadGltfModel(asset: Asset | undefined, resolvedPath: string) {\n const gltf = await gltfLoader.loadAsync(resolvedPath);\n const object = gltf.scene;\n centerObject(object, readAssetVec3(asset, \"nativeCenter\"));\n object.userData.webHammer = {\n ...(object.userData.webHammer ?? {}),\n animations: gltf.animations\n };\n return object;\n}\n\nfunction centerObject(object: Object3D, center: Vec3 | undefined) {\n const resolvedCenter = center ?? computeObjectCenter(object);\n object.position.set(-resolvedCenter.x, -resolvedCenter.y, -resolvedCenter.z);\n}\n\nfunction computeObjectCenter(object: Object3D) {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n\n return {\n x: center.x,\n y: center.y,\n z: center.z\n };\n}\n\nfunction createMissingModelFallback(asset: Asset | undefined) {\n const previewColor = readAssetString(asset, \"previewColor\") ?? \"#7f8ea3\";\n const size = readAssetVec3(asset, \"nativeSize\") ?? { x: 1.4, y: 1.4, z: 1.4 };\n const geometry = new BoxGeometry(size.x, size.y, size.z);\n const material = new MeshStandardMaterial({\n color: previewColor,\n metalness: 0.08,\n roughness: 0.72\n });\n const mesh = new Mesh(geometry, material);\n\n mesh.name = \"Missing Model\";\n return mesh;\n}\n\nfunction createThreeLight(node: Extract<WebHammerEngineNode, { kind: \"light\" }>) {\n if (!node.data.enabled) {\n return undefined;\n }\n\n switch (node.data.type) {\n case \"ambient\": {\n return new AmbientLight(node.data.color, node.data.intensity);\n }\n case \"hemisphere\": {\n const light = new HemisphereLight(node.data.color, node.data.groundColor ?? \"#0f1721\", node.data.intensity);\n return light;\n }\n case \"point\": {\n const light = new PointLight(node.data.color, node.data.intensity, node.data.distance ?? 0, node.data.decay ?? 2);\n light.castShadow = node.data.castShadow;\n return light;\n }\n case \"directional\": {\n const group = new Group();\n const light = new DirectionalLight(node.data.color, node.data.intensity);\n const target = new Object3D();\n\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(light);\n group.add(target);\n light.target = target;\n return group;\n }\n case \"spot\": {\n const group = new Group();\n const light = new SpotLight(\n node.data.color,\n node.data.intensity,\n node.data.distance ?? 0,\n node.data.angle ?? Math.PI / 3,\n node.data.penumbra ?? 0,\n node.data.decay ?? 2\n );\n const target = new Object3D();\n\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(light);\n group.add(target);\n light.target = target;\n return group;\n }\n default:\n return undefined;\n }\n}\n\nfunction applyTransform(object: Object3D, transform: Transform) {\n object.position.set(transform.position.x, transform.position.y, transform.position.z);\n object.rotation.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\");\n object.scale.set(transform.scale.x, transform.scale.y, transform.scale.z);\n}\n\nfunction composeInstancedMatrix(transform: Transform, pivot: Vec3) {\n return new Matrix4()\n .compose(\n new Vector3(transform.position.x, transform.position.y, transform.position.z),\n new Quaternion().setFromEuler(new Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\")),\n new Vector3(transform.scale.x, transform.scale.y, transform.scale.z)\n )\n .multiply(new Matrix4().makeTranslation(-pivot.x, -pivot.y, -pivot.z));\n}\n\nfunction extractPhysics(node: WebHammerEngineNode) {\n if (node.kind === \"primitive\") {\n return node.data.physics;\n }\n\n if (node.kind === \"mesh\") {\n return node.data.physics;\n }\n\n return undefined;\n}\n\nfunction findPrimaryLight(object: Object3D) {\n let resolved: Object3D | undefined;\n\n object.traverse((child: Object3D) => {\n if (!resolved && \"isLight\" in child && child.isLight) {\n resolved = child;\n }\n });\n\n return resolved;\n}\n\nfunction resolveModelFormat(format: unknown, path: string): \"gltf\" | \"obj\" {\n if (typeof format === \"string\" && format.toLowerCase() === \"obj\") {\n return \"obj\";\n }\n\n return path.toLowerCase().endsWith(\".obj\") ? \"obj\" : \"gltf\";\n}\n\nfunction readAssetString(asset: Asset | undefined, key: string) {\n const value = asset?.metadata[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction readAssetVec3(asset: Asset | undefined, keyPrefix: \"nativeCenter\" | \"nativeSize\") {\n if (!asset) {\n return undefined;\n }\n\n const x = asset.metadata[`${keyPrefix}X`];\n const y = asset.metadata[`${keyPrefix}Y`];\n const z = asset.metadata[`${keyPrefix}Z`];\n\n if (typeof x !== \"number\" || typeof y !== \"number\" || typeof z !== \"number\") {\n return undefined;\n }\n\n return { x, y, z };\n}\n\nfunction resolveMaterialSide(side?: MaterialRenderSide) {\n switch (side) {\n case \"back\":\n return BackSide;\n case \"double\":\n return DoubleSide;\n default:\n return FrontSide;\n }\n}\n\nfunction patchMtlTextureReferences(mtlText: string, texturePath?: string) {\n if (!texturePath) {\n return mtlText;\n }\n\n const mapPattern = /^(map_Ka|map_Kd|map_d|map_Bump|bump)\\s+.+$/gm;\n const hasDiffuseMap = /^map_Kd\\s+.+$/m.test(mtlText);\n const normalized = mtlText.replace(mapPattern, (line) => {\n if (line.startsWith(\"map_Kd \")) {\n return `map_Kd ${texturePath}`;\n }\n\n return line;\n });\n\n return hasDiffuseMap ? normalized : `${normalized.trim()}\\nmap_Kd ${texturePath}\\n`;\n}\n","import type { Asset, PropPhysics, Transform, Vec3 } from \"@ggez/shared\";\nimport { resolveInstancingSourceNode, resolveSceneGraph, vec3 } from \"@ggez/shared\";\nimport {\n AmbientLight,\n BackSide,\n Box3,\n BoxGeometry,\n BufferGeometry,\n DirectionalLight,\n DoubleSide,\n Euler,\n Float32BufferAttribute,\n FrontSide,\n Group,\n HemisphereLight,\n InstancedMesh,\n LOD,\n Matrix4,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n PointLight,\n Quaternion,\n RepeatWrapping,\n SRGBColorSpace,\n SpotLight,\n Texture,\n TextureLoader,\n Vector3\n} from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/loaders/GLTFLoader.js\";\nimport { MTLLoader } from \"three/examples/jsm/loaders/MTLLoader.js\";\nimport { OBJLoader } from \"three/examples/jsm/loaders/OBJLoader.js\";\nimport type {\n WebHammerEngineGeometryNode,\n WebHammerEngineModelNode,\n WebHammerEngineNode,\n WebHammerEngineScene,\n WebHammerExportGeometry,\n WebHammerExportGeometryLod,\n WebHammerExportMaterial,\n WebHammerExportModelLod\n} from \"./types\";\nimport type { WebHammerSceneLoaderOptions, WebHammerSceneLodOptions } from \"./loader\";\n\ntype TextureSlot = \"baseColorTexture\" | \"metallicRoughnessTexture\" | \"normalTexture\";\n\ntype WebHammerSceneObjectFactoryOptions = Pick<\n WebHammerSceneLoaderOptions,\n \"castShadow\" | \"lod\" | \"receiveShadow\" | \"resolveAssetUrl\"\n>;\n\ntype CreateNodeObjectOverrides = {\n transform?: Transform;\n};\n\ntype ModelReference = {\n asset?: Asset;\n assetId?: string;\n center?: Vec3;\n fallbackName: string;\n format: \"gltf\" | \"obj\";\n modelPath?: string;\n nodeId: string;\n nodeName: string;\n texturePath?: string;\n};\n\ntype WebHammerSceneObjectFactoryResources = {\n assetsById: Map<string, Asset>;\n materialCache: Map<string, MeshStandardMaterial>;\n modelTemplateCache: Map<string, Promise<Object3D>>;\n textureCache: Map<string, Promise<Texture>>;\n};\n\nconst textureLoader = new TextureLoader();\nconst gltfLoader = new GLTFLoader();\nconst mtlLoader = new MTLLoader();\nconst modelTextureLoader = new TextureLoader();\nconst tempModelInstanceMatrix = new Matrix4();\nconst tempModelChildMatrix = new Matrix4();\nconst tempPivotMatrix = new Matrix4();\nconst tempInstancePosition = new Vector3();\nconst tempInstanceQuaternion = new Quaternion();\nconst tempInstanceScale = new Vector3();\n\nexport type WebHammerSceneObjectFactory = {\n createInstancingObjects: () => Promise<Object3D[]>;\n createNodeObject: (node: WebHammerEngineNode, overrides?: CreateNodeObjectOverrides) => Promise<Object3D>;\n};\n\nexport function createWebHammerSceneObjectFactory(\n engineScene: Pick<WebHammerEngineScene, \"assets\" | \"nodes\">,\n options: WebHammerSceneObjectFactoryOptions = {}\n): WebHammerSceneObjectFactory {\n const resources: WebHammerSceneObjectFactoryResources = {\n assetsById: new Map(engineScene.assets.map((asset) => [asset.id, asset])),\n materialCache: new Map(),\n modelTemplateCache: new Map(),\n textureCache: new Map()\n };\n\n return {\n createInstancingObjects: () => createInstancingObjects(engineScene, resources, options),\n createNodeObject: (node, overrides) => createObjectForNode(node, resources, options, overrides)\n };\n}\n\nexport const createThreeRuntimeObjectFactory = createWebHammerSceneObjectFactory;\n\nasync function createObjectForNode(\n node: WebHammerEngineNode,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n overrides?: CreateNodeObjectOverrides\n) {\n const anchor = new Group();\n const content = new Group();\n const transform = overrides?.transform ?? node.transform;\n const pivot = transform.pivot;\n\n anchor.name = node.name;\n applyTransform(anchor, transform);\n anchor.userData.webHammer = {\n data: node.data,\n hooks: node.hooks,\n id: node.id,\n kind: node.kind,\n metadata: node.metadata,\n tags: node.tags\n };\n\n if (pivot) {\n content.position.set(-pivot.x, -pivot.y, -pivot.z);\n }\n\n anchor.add(content);\n\n if (node.kind === \"light\") {\n const light = createThreeLight(node);\n\n if (light) {\n content.add(light);\n }\n\n return anchor;\n }\n\n if (node.kind === \"group\") {\n return anchor;\n }\n\n if (node.kind === \"instancing\") {\n anchor.visible = false;\n return anchor;\n }\n\n if (node.kind === \"model\") {\n const modelObject = await createModelObject(node, resources, options);\n const lodObject = await createLodObjectForModelNode(node, modelObject, resources, options);\n content.add(lodObject ?? modelObject);\n return anchor;\n }\n\n const lodObject = await createLodObjectForGeometryNode(node, resources, options);\n\n if (lodObject) {\n content.add(lodObject);\n }\n\n return anchor;\n}\n\nasync function createInstancingObjects(\n engineScene: Pick<WebHammerEngineScene, \"assets\" | \"nodes\">,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const sceneGraph = resolveSceneGraph(engineScene.nodes);\n const batches = new Map<string, Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>>();\n\n engineScene.nodes.forEach((node) => {\n if (node.kind !== \"instancing\") {\n return;\n }\n\n const sourceNode = resolveInstancingSourceNode(engineScene.nodes, node.data.sourceNodeId);\n\n if (!sourceNode) {\n return;\n }\n\n const instances = batches.get(sourceNode.id);\n\n if (instances) {\n instances.push(node);\n return;\n }\n\n batches.set(sourceNode.id, [node]);\n });\n\n const objects: Object3D[] = [];\n\n for (const [sourceNodeId, instances] of batches) {\n const sourceNode = resolveInstancingSourceNode(engineScene.nodes, sourceNodeId);\n\n if (!sourceNode) {\n continue;\n }\n\n const exportedSourceNode = engineScene.nodes.find((node) => node.id === sourceNode.id);\n\n if (!exportedSourceNode || exportedSourceNode.kind === \"group\" || exportedSourceNode.kind === \"instancing\" || exportedSourceNode.kind === \"light\") {\n continue;\n }\n\n const object =\n exportedSourceNode.kind === \"model\"\n ? await createInstancedObjectForModelNode(exportedSourceNode, instances, sceneGraph, resources, options)\n : await createInstancedObjectForGeometryNode(exportedSourceNode, instances, sceneGraph, resources, options);\n\n if (object) {\n objects.push(object);\n }\n }\n\n return objects;\n}\n\nasync function createInstancedObjectForGeometryNode(\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const baseGroup = await createInstancedGeometryObject(sourceNode.geometry, sourceNode, instances, sceneGraph, resources, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !sourceNode.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${sourceNode.name}:InstancingLOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of sourceNode.lods) {\n const levelGroup = await createInstancedGeometryObject(\n level.geometry,\n sourceNode,\n instances,\n sceneGraph,\n resources,\n options,\n level\n );\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n levelOrder: [\"high\", ...(sourceNode.lods ?? []).map((level) => level.level)],\n sourceNodeId: sourceNode.id\n };\n return lod;\n}\n\nasync function createInstancedGeometryObject(\n geometry: WebHammerExportGeometry,\n sourceNode: WebHammerEngineGeometryNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const pivot = sourceNode.transform.pivot ?? vec3(0, 0, 0);\n\n for (const primitive of geometry.primitives) {\n const primitiveGeometry = new BufferGeometry();\n primitiveGeometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n primitiveGeometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n primitiveGeometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n primitiveGeometry.setIndex(primitive.indices);\n primitiveGeometry.computeBoundingBox();\n primitiveGeometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, resources, options);\n const mesh = new InstancedMesh(primitiveGeometry, material, instances.length);\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${sourceNode.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}:instanced`;\n mesh.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n sourceNodeId: sourceNode.id\n };\n\n instances.forEach((instance, index) => {\n const worldTransform = sceneGraph.nodeWorldTransforms.get(instance.id) ?? instance.transform;\n mesh.setMatrixAt(index, composeGeometryInstanceMatrix(worldTransform, pivot));\n });\n\n mesh.instanceMatrix.needsUpdate = true;\n group.add(mesh);\n }\n\n group.name = `${sourceNode.name}:instances`;\n group.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n sourceNodeId: sourceNode.id\n };\n return group;\n}\n\nasync function createInstancedObjectForModelNode(\n sourceNode: WebHammerEngineModelNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const baseGroup = await createInstancedModelObject(sourceNode, instances, sceneGraph, resources, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !sourceNode.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${sourceNode.name}:InstancingLOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of sourceNode.lods) {\n const levelGroup = await createInstancedModelObject(sourceNode, instances, sceneGraph, resources, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n instanceNodeIds: instances.map((instance) => instance.id),\n levelOrder: [\"high\", ...(sourceNode.lods ?? []).map((level) => level.level)],\n sourceNodeId: sourceNode.id\n };\n return lod;\n}\n\nasync function createInstancedModelObject(\n sourceNode: WebHammerEngineModelNode,\n instances: Array<Extract<WebHammerEngineNode, { kind: \"instancing\" }>>,\n sceneGraph: ReturnType<typeof resolveSceneGraph>,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportModelLod\n) {\n const group = new Group();\n const template = await loadModelTemplate(resolveModelReference(sourceNode, resources.assetsById, lodLevel), options, resources);\n const templateInstanceNodeIds = instances.map((instance) => instance.id);\n let modelMeshIndex = 0;\n\n template.updateMatrixWorld(true);\n\n template.traverse((child) => {\n if (!(child instanceof Mesh) || !(child.geometry instanceof BufferGeometry)) {\n return;\n }\n\n const instancedMesh = new InstancedMesh(child.geometry, child.material, instances.length);\n instancedMesh.castShadow = options.castShadow ?? true;\n instancedMesh.receiveShadow = options.receiveShadow ?? true;\n instancedMesh.name = `${sourceNode.name}:${lodLevel?.level ?? \"high\"}:${child.name || modelMeshIndex}:instanced`;\n instancedMesh.userData.webHammer = {\n instanceNodeIds: templateInstanceNodeIds,\n lodLevel: lodLevel?.level ?? \"high\",\n modelMeshIndex,\n sourceNodeId: sourceNode.id\n };\n\n tempModelChildMatrix.copy(child.matrixWorld);\n\n instances.forEach((instance, index) => {\n const worldTransform = sceneGraph.nodeWorldTransforms.get(instance.id) ?? instance.transform;\n tempModelInstanceMatrix.copy(composeTransformMatrix(worldTransform)).multiply(tempModelChildMatrix);\n instancedMesh.setMatrixAt(index, tempModelInstanceMatrix);\n });\n\n instancedMesh.instanceMatrix.needsUpdate = true;\n group.add(instancedMesh);\n modelMeshIndex += 1;\n });\n\n group.name = `${sourceNode.name}:instances`;\n group.userData.webHammer = {\n instanceNodeIds: templateInstanceNodeIds,\n sourceNodeId: sourceNode.id\n };\n return group;\n}\n\nasync function createLodObjectForGeometryNode(\n node: WebHammerEngineGeometryNode,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const baseGroup = await createGeometryObject(node.geometry, node, resources, options);\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return baseGroup;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseGroup, 0);\n\n for (const level of node.lods) {\n const levelGroup = await createGeometryObject(level.geometry, node, resources, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelGroup, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createLodObjectForModelNode(\n node: WebHammerEngineModelNode,\n baseModel: Object3D,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const lodOptions = resolveSceneLodOptions(options.lod);\n\n if (!lodOptions || !node.lods?.length) {\n return undefined;\n }\n\n const lod = new LOD();\n lod.name = `${node.name}:LOD`;\n lod.autoUpdate = true;\n lod.addLevel(baseModel, 0);\n\n for (const level of node.lods) {\n const levelModel = await createModelObject(node, resources, options, level);\n const distance = level.level === \"mid\" ? lodOptions.midDistance : lodOptions.lowDistance;\n lod.addLevel(levelModel, distance);\n }\n\n lod.userData.webHammer = {\n levelOrder: [\"high\", ...(node.lods ?? []).map((level) => level.level)],\n nodeId: node.id\n };\n return lod;\n}\n\nasync function createGeometryObject(\n geometry: WebHammerExportGeometry,\n node: Pick<WebHammerEngineNode, \"id\" | \"name\">,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportGeometryLod\n) {\n const group = new Group();\n const meshes: Mesh[] = [];\n\n for (const primitive of geometry.primitives) {\n const primitiveGeometry = new BufferGeometry();\n primitiveGeometry.setAttribute(\"position\", new Float32BufferAttribute(primitive.positions, 3));\n primitiveGeometry.setAttribute(\"normal\", new Float32BufferAttribute(primitive.normals, 3));\n\n if (primitive.uvs.length > 0) {\n primitiveGeometry.setAttribute(\"uv\", new Float32BufferAttribute(primitive.uvs, 2));\n }\n\n primitiveGeometry.setIndex(primitive.indices);\n primitiveGeometry.computeBoundingBox();\n primitiveGeometry.computeBoundingSphere();\n\n const material = await createThreeMaterial(primitive.material, resources, options);\n const mesh = new Mesh(primitiveGeometry, material);\n\n mesh.castShadow = options.castShadow ?? true;\n mesh.receiveShadow = options.receiveShadow ?? true;\n mesh.name = `${node.name}:${lodLevel?.level ?? \"high\"}:${primitive.material.name}`;\n mesh.userData.webHammer = {\n lodLevel: lodLevel?.level ?? \"high\",\n materialId: primitive.material.id,\n nodeId: node.id\n };\n\n meshes.push(mesh);\n }\n\n meshes.forEach((mesh) => {\n group.add(mesh);\n });\n\n return group;\n}\n\nasync function createThreeMaterial(\n materialSpec: WebHammerExportMaterial,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const cached = resources.materialCache.get(materialSpec.id);\n\n if (cached) {\n return cached;\n }\n\n const material = new MeshStandardMaterial({\n color: materialSpec.color,\n metalness: materialSpec.metallicFactor,\n roughness: materialSpec.roughnessFactor,\n side: resolveMaterialSide(materialSpec.side)\n });\n\n if (materialSpec.baseColorTexture) {\n const texture = await loadTexture(materialSpec.baseColorTexture, materialSpec, \"baseColorTexture\", resources, options);\n texture.colorSpace = SRGBColorSpace;\n material.map = texture;\n }\n\n if (materialSpec.normalTexture) {\n material.normalMap = await loadTexture(materialSpec.normalTexture, materialSpec, \"normalTexture\", resources, options);\n }\n\n if (materialSpec.metallicRoughnessTexture) {\n const ormTexture = await loadTexture(\n materialSpec.metallicRoughnessTexture,\n materialSpec,\n \"metallicRoughnessTexture\",\n resources,\n options\n );\n material.metalnessMap = ormTexture;\n material.roughnessMap = ormTexture;\n }\n\n material.name = materialSpec.name;\n material.needsUpdate = true;\n resources.materialCache.set(materialSpec.id, material);\n\n return material;\n}\n\nasync function loadTexture(\n path: string,\n material: WebHammerExportMaterial,\n slot: TextureSlot,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions\n) {\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material,\n path,\n slot\n })\n : path;\n const cacheKey = `${slot}:${resolvedPath}`;\n const cached = resources.textureCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const pendingTexture = textureLoader.loadAsync(resolvedPath);\n const configuredTexture = pendingTexture.then((texture) => {\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n return texture;\n });\n resources.textureCache.set(cacheKey, configuredTexture);\n return configuredTexture;\n}\n\nasync function createModelObject(\n node: WebHammerEngineModelNode,\n resources: WebHammerSceneObjectFactoryResources,\n options: WebHammerSceneObjectFactoryOptions,\n lodLevel?: WebHammerExportModelLod\n) {\n const template = await loadModelTemplate(resolveModelReference(node, resources.assetsById, lodLevel), options, resources);\n const clone = template.clone(true);\n\n clone.name = `${node.name}:${lodLevel?.level ?? \"high\"}`;\n clone.userData.webHammer = {\n ...(clone.userData.webHammer ?? {}),\n lodLevel: lodLevel?.level ?? \"high\",\n nodeId: node.id\n };\n clone.traverse((child) => {\n if (child instanceof Mesh) {\n child.castShadow = options.castShadow ?? true;\n child.receiveShadow = options.receiveShadow ?? true;\n }\n });\n\n return clone;\n}\n\nfunction resolveModelReference(\n node: WebHammerEngineModelNode,\n assetsById: Map<string, Asset>,\n lodLevel?: WebHammerExportModelLod\n): ModelReference {\n const asset = lodLevel ? assetsById.get(lodLevel.assetId) : assetsById.get(node.data.assetId);\n const modelPath = asset?.path ?? node.data.path;\n\n return {\n asset,\n assetId: asset?.id ?? (lodLevel ? lodLevel.assetId : node.data.assetId),\n center: readAssetVec3(asset, \"nativeCenter\"),\n fallbackName: `${node.name}:${lodLevel?.level ?? \"high\"}:fallback`,\n format: resolveModelFormat(asset?.metadata.modelFormat, modelPath),\n modelPath,\n nodeId: node.id,\n nodeName: node.name,\n texturePath: readAssetString(asset, \"texturePath\")\n };\n}\n\nasync function loadModelTemplate(\n reference: ModelReference,\n options: WebHammerSceneObjectFactoryOptions,\n resources: WebHammerSceneObjectFactoryResources\n) {\n if (!reference.modelPath) {\n return createMissingModelFallback(reference.asset, reference.fallbackName);\n }\n\n const resolvedPath = options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n asset: reference.asset,\n format: reference.format,\n kind: \"model\",\n node: {\n data: {\n assetId: reference.assetId ?? \"\",\n path: reference.modelPath\n },\n id: reference.nodeId,\n kind: \"model\",\n name: reference.nodeName,\n transform: {\n position: vec3(0, 0, 0),\n rotation: vec3(0, 0, 0),\n scale: vec3(1, 1, 1)\n }\n },\n path: reference.modelPath\n })\n : reference.modelPath;\n const resolvedTexturePath =\n reference.texturePath && options.resolveAssetUrl\n ? await options.resolveAssetUrl({\n kind: \"texture\",\n material: {\n color: \"#ffffff\",\n id: `material:model-texture:${reference.nodeId}`,\n metallicFactor: 0,\n name: `${reference.nodeName} Model Texture`,\n roughnessFactor: 1\n },\n path: reference.texturePath,\n slot: \"baseColorTexture\"\n })\n : reference.texturePath;\n const cacheKey = `${reference.format}:${resolvedPath}:${resolvedTexturePath ?? \"\"}:${readAssetString(reference.asset, \"materialMtlText\") ?? \"\"}`;\n const cached = resources.modelTemplateCache.get(cacheKey);\n\n if (cached) {\n return cached;\n }\n\n const pending = (async () => {\n try {\n const object =\n reference.format === \"obj\"\n ? await loadObjModel(reference.asset, resolvedPath, resolvedTexturePath)\n : await loadGltfModel(reference.asset, resolvedPath);\n centerObject(object, reference.center);\n return object;\n } catch {\n return createMissingModelFallback(reference.asset, reference.fallbackName);\n }\n })();\n\n resources.modelTemplateCache.set(cacheKey, pending);\n return pending;\n}\n\nasync function loadObjModel(asset: Asset | undefined, resolvedPath: string, resolvedTexturePath?: string) {\n const objLoader = new OBJLoader();\n const mtlText = readAssetString(asset, \"materialMtlText\");\n\n if (mtlText) {\n const materialCreator = mtlLoader.parse(patchMtlTextureReferences(mtlText, resolvedTexturePath), \"\");\n materialCreator.preload();\n objLoader.setMaterials(materialCreator);\n }\n\n const object = await objLoader.loadAsync(resolvedPath);\n\n if (!mtlText && resolvedTexturePath) {\n const texture = await loadModelTexture(resolvedTexturePath);\n\n object.traverse((child: Object3D) => {\n if (child instanceof Mesh) {\n child.material = new MeshStandardMaterial({\n map: texture,\n metalness: 0.12,\n roughness: 0.76\n });\n }\n });\n }\n\n return object;\n}\n\nasync function loadGltfModel(asset: Asset | undefined, resolvedPath: string) {\n const gltf = await gltfLoader.loadAsync(resolvedPath);\n const object = gltf.scene;\n object.userData.webHammer = {\n ...(object.userData.webHammer ?? {}),\n animations: gltf.animations,\n nativeCenter: readAssetVec3(asset, \"nativeCenter\")\n };\n return object;\n}\n\nasync function loadModelTexture(path: string) {\n const texture = await modelTextureLoader.loadAsync(path);\n texture.wrapS = RepeatWrapping;\n texture.wrapT = RepeatWrapping;\n texture.colorSpace = SRGBColorSpace;\n return texture;\n}\n\nfunction centerObject(object: Object3D, center: Vec3 | undefined) {\n const resolvedCenter = center ?? computeObjectCenter(object);\n object.position.set(-resolvedCenter.x, -resolvedCenter.y, -resolvedCenter.z);\n}\n\nfunction computeObjectCenter(object: Object3D) {\n const box = new Box3().setFromObject(object);\n const center = box.getCenter(new Vector3());\n\n return {\n x: center.x,\n y: center.y,\n z: center.z\n };\n}\n\nfunction createMissingModelFallback(asset: Asset | undefined, name = \"Missing Model\") {\n const previewColor = readAssetString(asset, \"previewColor\") ?? \"#7f8ea3\";\n const size = readAssetVec3(asset, \"nativeSize\") ?? { x: 1.4, y: 1.4, z: 1.4 };\n const geometry = new BoxGeometry(size.x, size.y, size.z);\n const material = new MeshStandardMaterial({\n color: previewColor,\n metalness: 0.08,\n roughness: 0.72\n });\n const mesh = new Mesh(geometry, material);\n\n mesh.name = name;\n return mesh;\n}\n\nfunction createThreeLight(node: Extract<WebHammerEngineNode, { kind: \"light\" }>) {\n if (!node.data.enabled) {\n return undefined;\n }\n\n switch (node.data.type) {\n case \"ambient\": {\n return new AmbientLight(node.data.color, node.data.intensity);\n }\n case \"hemisphere\": {\n return new HemisphereLight(node.data.color, node.data.groundColor ?? \"#0f1721\", node.data.intensity);\n }\n case \"point\": {\n const light = new PointLight(node.data.color, node.data.intensity, node.data.distance ?? 0, node.data.decay ?? 2);\n light.castShadow = node.data.castShadow;\n return light;\n }\n case \"directional\": {\n const group = new Group();\n const light = new DirectionalLight(node.data.color, node.data.intensity);\n const target = new Object3D();\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(target);\n group.add(light);\n light.target = target;\n return group;\n }\n case \"spot\": {\n const group = new Group();\n const light = new SpotLight(\n node.data.color,\n node.data.intensity,\n node.data.distance,\n node.data.angle,\n node.data.penumbra,\n node.data.decay\n );\n const target = new Object3D();\n light.castShadow = node.data.castShadow;\n target.position.set(0, 0, -6);\n group.add(target);\n group.add(light);\n light.target = target;\n return group;\n }\n default:\n return undefined;\n }\n}\n\nfunction applyTransform(object: Object3D, transform: Transform) {\n object.position.set(transform.position.x, transform.position.y, transform.position.z);\n object.rotation.set(transform.rotation.x, transform.rotation.y, transform.rotation.z);\n object.scale.set(transform.scale.x, transform.scale.y, transform.scale.z);\n}\n\nfunction composeGeometryInstanceMatrix(transform: Transform, pivot: Vec3) {\n return composeTransformMatrix(transform).multiply(\n tempPivotMatrix.makeTranslation(-pivot.x, -pivot.y, -pivot.z)\n );\n}\n\nfunction composeTransformMatrix(transform: Transform) {\n tempInstancePosition.set(transform.position.x, transform.position.y, transform.position.z);\n tempInstanceQuaternion.setFromEuler(new Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z, \"XYZ\"));\n tempInstanceScale.set(transform.scale.x, transform.scale.y, transform.scale.z);\n\n return new Matrix4().compose(tempInstancePosition, tempInstanceQuaternion, tempInstanceScale);\n}\n\nfunction resolveSceneLodOptions(lod?: WebHammerSceneLodOptions): WebHammerSceneLodOptions | undefined {\n if (!lod) {\n return undefined;\n }\n\n const midDistance = Math.max(0, lod.midDistance);\n const lowDistance = Math.max(midDistance + 0.01, lod.lowDistance);\n\n return {\n lowDistance,\n midDistance\n };\n}\n\nfunction resolveMaterialSide(side?: WebHammerExportMaterial[\"side\"]) {\n switch (side) {\n case \"back\":\n return BackSide;\n case \"double\":\n return DoubleSide;\n default:\n return FrontSide;\n }\n}\n\nfunction resolveModelFormat(format: unknown, path?: string): \"gltf\" | \"obj\" {\n if (typeof format === \"string\" && format.toLowerCase() === \"obj\") {\n return \"obj\";\n }\n\n return path?.toLowerCase().endsWith(\".obj\") ? \"obj\" : \"gltf\";\n}\n\nfunction readAssetString(asset: Asset | undefined, key: string) {\n const value = asset?.metadata[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction readAssetVec3(asset: Asset | undefined, keyPrefix: \"nativeCenter\" | \"nativeSize\") {\n const x = asset?.metadata[`${keyPrefix}X`];\n const y = asset?.metadata[`${keyPrefix}Y`];\n const z = asset?.metadata[`${keyPrefix}Z`];\n\n if (typeof x !== \"number\" || typeof y !== \"number\" || typeof z !== \"number\") {\n return undefined;\n }\n\n return { x, y, z };\n}\n\nfunction patchMtlTextureReferences(mtlText: string, texturePath?: string) {\n if (!texturePath) {\n return mtlText;\n }\n\n const mapPattern = /^(map_Ka|map_Kd|map_d|map_Bump|bump)\\s+.+$/gm;\n const hasDiffuseMap = /^map_Kd\\s+.+$/m.test(mtlText);\n const normalized = mtlText.replace(mapPattern, (line) => {\n if (line.startsWith(\"map_Kd \")) {\n return `map_Kd ${texturePath}`;\n }\n\n return line;\n });\n\n return hasDiffuseMap\n ? normalized\n : `${normalized.trim()}\\nmap_Kd ${texturePath}\\n`;\n}\n\nexport function extractPhysics(node: WebHammerEngineNode): PropPhysics | undefined {\n if (node.kind === \"primitive\") {\n return node.data.physics;\n }\n\n if (node.kind === \"mesh\") {\n return node.data.physics;\n }\n\n return undefined;\n}\n\nexport function findPrimaryLight(object: Object3D) {\n if (\"isLight\" in object && object.isLight) {\n return object;\n }\n\n return object.children.find((child) => \"isLight\" in child && child.isLight);\n}\n","import {\n createWebHammerEngineBundleZip as packWebHammerEngineBundle,\n externalizeWebHammerEngineScene as externalizeWebHammerEngineSceneAssets,\n parseWebHammerEngineBundleZip as unpackWebHammerEngineBundle\n} from \"@ggez/runtime-build\";\nimport type { RuntimeBundle, WebHammerEngineBundle } from \"@ggez/runtime-format\";\n\nexport {\n buildRuntimeBundle,\n buildRuntimeScene,\n buildRuntimeWorldIndex,\n externalizeRuntimeAssets,\n packRuntimeBundle,\n unpackRuntimeBundle\n} from \"@ggez/runtime-build\";\n\nexport function createThreeAssetResolver(bundle: RuntimeBundle) {\n const urlByPath = new Map<string, string>();\n\n return {\n dispose() {\n urlByPath.forEach((url) => {\n URL.revokeObjectURL(url);\n });\n urlByPath.clear();\n },\n resolve(path: string) {\n const existing = urlByPath.get(path);\n\n if (existing) {\n return existing;\n }\n\n const file = bundle.files.find((entry) => entry.path === path);\n\n if (!file) {\n return path;\n }\n\n const bytes = new Uint8Array(file.bytes.byteLength);\n bytes.set(file.bytes);\n const url = URL.createObjectURL(new Blob([bytes.buffer], { type: file.mimeType }));\n urlByPath.set(path, url);\n return url;\n }\n };\n}\n\nexport function createWebHammerBundleAssetResolver(bundle: WebHammerEngineBundle) {\n return createThreeAssetResolver(bundle);\n}\n\nexport function createWebHammerEngineBundleZip(bundle: WebHammerEngineBundle, options?: Parameters<typeof packWebHammerEngineBundle>[1]) {\n return packWebHammerEngineBundle(bundle, options);\n}\n\nexport function parseWebHammerEngineBundleZip(bundleBytes: Uint8Array, options?: Parameters<typeof unpackWebHammerEngineBundle>[1]) {\n return unpackWebHammerEngineBundle(bundleBytes, options);\n}\n\nexport function externalizeWebHammerEngineScene(\n scene: WebHammerEngineBundle[\"manifest\"],\n options?: Parameters<typeof externalizeWebHammerEngineSceneAssets>[1]\n) {\n return externalizeWebHammerEngineSceneAssets(scene, options);\n}\n"],"mappings":"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","names":["resolveInstancingSourceNode","resolveSceneGraph","vec3","AmbientLight","BackSide","Box3","BoxGeometry","BufferGeometry","DirectionalLight","DoubleSide","Euler","Float32BufferAttribute","FrontSide","Group","InstancedMesh","HemisphereLight","LOD","Matrix4","Mesh","MeshStandardMaterial","Object3D","PointLight","Quaternion","SRGBColorSpace","SpotLight","TextureLoader","RepeatWrapping","Vector3","GLTFLoader","MTLLoader","OBJLoader","lodObject","textureLoader","TextureLoader","gltfLoader","GLTFLoader","mtlLoader","MTLLoader","Group","resolveSceneGraph","AmbientLight","Mesh","InstancedMesh","BufferGeometry","MeshStandardMaterial","SRGBColorSpace"]}
|