@ggez/workers 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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/manager.ts","../../shared/src/utils.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/bundle.ts","../../runtime-format/src/types.ts","../../runtime-build/src/snapshot-build.ts","../src/export-tasks.ts","../src/tasks.ts"],"sourcesContent":["import type { WorkerTask } from \"./tasks\";\n\nexport type WorkerJobStatus = \"queued\" | \"running\" | \"completed\";\n\nexport type WorkerJob = {\n id: string;\n label: string;\n status: WorkerJobStatus;\n task: WorkerTask;\n};\n\ntype Listener = (jobs: WorkerJob[]) => void;\n\nexport type WorkerTaskManager = {\n enqueue: (task: WorkerTask, label: string, durationMs?: number) => string;\n getJobs: () => WorkerJob[];\n subscribe: (listener: Listener) => () => void;\n};\n\nexport function createWorkerTaskManager(): WorkerTaskManager {\n let counter = 0;\n const jobs = new Map<string, WorkerJob>();\n const listeners = new Set<Listener>();\n\n const emit = () => {\n const snapshot = Array.from(jobs.values());\n listeners.forEach((listener) => {\n listener(snapshot);\n });\n };\n\n return {\n enqueue(task, label, durationMs = 900) {\n const id = `job:${counter++}`;\n jobs.set(id, {\n id,\n label,\n status: \"queued\",\n task\n });\n emit();\n\n queueMicrotask(() => {\n const job = jobs.get(id);\n\n if (!job) {\n return;\n }\n\n job.status = \"running\";\n emit();\n\n window.setTimeout(() => {\n const runningJob = jobs.get(id);\n\n if (!runningJob) {\n return;\n }\n\n runningJob.status = \"completed\";\n emit();\n\n window.setTimeout(() => {\n jobs.delete(id);\n emit();\n }, 900);\n }, durationMs);\n });\n\n return id;\n },\n getJobs() {\n return Array.from(jobs.values());\n },\n subscribe(listener) {\n listeners.add(listener);\n listener(Array.from(jobs.values()));\n\n return () => {\n listeners.delete(listener);\n };\n }\n };\n}\n","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 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 { 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 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 { 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 { 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 buildRuntimeBundleFromSnapshot,\n buildRuntimeSceneFromSnapshot,\n serializeRuntimeScene,\n type WebHammerEngineBundle\n} from \"@ggez/runtime-build\";\nimport {\n type WebHammerEngineScene,\n type WebHammerExportGeometry,\n type WebHammerExportGeometryLod,\n type WebHammerExportModelLod,\n type WebHammerExportMaterial\n} from \"@ggez/runtime-format\";\nimport { MeshBVH } from \"three-mesh-bvh\";\nimport {\n Box3,\n BoxGeometry,\n BufferGeometry,\n ConeGeometry,\n CylinderGeometry,\n Euler,\n Float32BufferAttribute,\n Group,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n Quaternion,\n RepeatWrapping,\n Scene,\n SphereGeometry,\n SRGBColorSpace,\n TextureLoader,\n Vector3\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\";\n\nexport type WorkerExportKind = \"whmap-load\" | \"whmap-save\" | \"engine-export\" | \"gltf-export\" | \"ai-model-generate\";\n\nexport type WorkerRequest =\n | {\n id: string;\n kind: \"whmap-save\";\n snapshot: SceneDocumentSnapshot;\n }\n | {\n id: string;\n kind: \"whmap-load\";\n text: string;\n }\n | {\n id: string;\n kind: \"engine-export\" | \"gltf-export\";\n snapshot: SceneDocumentSnapshot;\n }\n | {\n id: string;\n kind: \"ai-model-generate\";\n prompt: string;\n };\n\nexport type WorkerResponse =\n | {\n id: string;\n kind: WorkerExportKind;\n ok: true;\n payload: string | SceneDocumentSnapshot | WebHammerEngineBundle;\n }\n | {\n id: string;\n kind: WorkerExportKind;\n ok: false;\n error: string;\n };\n\nconst gltfLoader = new GLTFLoader();\nconst gltfExporter = new GLTFExporter();\nconst mtlLoader = new MTLLoader();\nconst modelTextureLoader = new TextureLoader();\n\nexport async function executeWorkerRequest(request: WorkerRequest): Promise<WorkerResponse> {\n try {\n if (request.kind === \"whmap-save\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: serializeWhmap(request.snapshot)\n };\n }\n\n if (request.kind === \"whmap-load\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: parseWhmap(request.text)\n };\n }\n\n if (request.kind === \"engine-export\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: await exportEngineBundle(request.snapshot)\n };\n }\n\n if (request.kind === \"ai-model-generate\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: await generateAiModel(request.prompt)\n };\n }\n\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: await serializeGltfScene(request.snapshot)\n };\n } catch (error) {\n return {\n id: request.id,\n kind: request.kind,\n ok: false,\n error: error instanceof Error ? error.message : \"Unknown worker error.\"\n };\n }\n}\n\nasync function generateAiModel(prompt: string): Promise<string> {\n const response = await fetch(new URL(\"/api/ai/models\", self.location.origin), {\n body: JSON.stringify({ prompt }),\n headers: {\n \"Content-Type\": \"application/json\"\n },\n method: \"POST\"\n });\n\n const payload = await response.text();\n\n if (!response.ok) {\n try {\n const parsed = JSON.parse(payload) as { error?: string };\n throw new Error(parsed.error ?? \"Failed to generate AI model.\");\n } catch {\n throw new Error(payload || \"Failed to generate AI model.\");\n }\n }\n\n return payload;\n}\n\nexport function serializeWhmap(snapshot: SceneDocumentSnapshot): string {\n return JSON.stringify(\n {\n format: \"whmap\",\n version: 1,\n scene: snapshot\n },\n null,\n 2\n );\n}\n\nexport function parseWhmap(text: string): SceneDocumentSnapshot {\n const parsed = JSON.parse(text) as {\n format?: string;\n scene?: SceneDocumentSnapshot;\n version?: number;\n };\n\n if (parsed.format !== \"whmap\" || !parsed.scene) {\n throw new Error(\"Invalid .whmap file.\");\n }\n\n return parsed.scene;\n}\n\nexport async function serializeEngineScene(snapshot: SceneDocumentSnapshot): Promise<string> {\n return serializeRuntimeScene(snapshot);\n}\n\nexport async function exportEngineBundle(snapshot: SceneDocumentSnapshot): Promise<WebHammerEngineBundle> {\n return buildRuntimeBundleFromSnapshot(snapshot);\n}\n\nasync function buildEngineScene(snapshot: SceneDocumentSnapshot): Promise<WebHammerEngineScene> {\n return buildRuntimeSceneFromSnapshot(snapshot);\n}\n\nexport async function serializeGltfScene(snapshot: SceneDocumentSnapshot): Promise<string> {\n const materialsById = new Map(snapshot.materials.map((material) => [material.id, material]));\n const assetsById = new Map(snapshot.assets.map((asset) => [asset.id, asset]));\n const exportedNodes: Array<{\n id: string;\n mesh?: {\n name: string;\n primitives: Array<{\n indices: number[];\n material: WebHammerExportMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n }>;\n };\n meshKey?: string;\n name: string;\n parentId?: string;\n rotation?: [number, number, number, number];\n scale: [number, number, number];\n translation: [number, number, number];\n }> = [];\n\n for (const node of snapshot.nodes) {\n if (isGroupNode(node)) {\n exportedNodes.push({\n id: node.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(node.transform.rotation),\n scale: [node.transform.scale.x, node.transform.scale.y, node.transform.scale.z],\n translation: [node.transform.position.x, node.transform.position.y, node.transform.position.z]\n });\n continue;\n }\n\n if (isBrushNode(node) || isMeshNode(node) || isPrimitiveNode(node)) {\n const geometry = await buildExportGeometry(node, materialsById);\n\n if (geometry.primitives.length === 0) {\n continue;\n }\n\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: node.name,\n primitives: geometry.primitives\n },\n meshKey: node.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(node.transform.rotation),\n scale: [node.transform.scale.x, node.transform.scale.y, node.transform.scale.z],\n translation: [node.transform.position.x, node.transform.position.y, node.transform.position.z]\n });\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 const instanceTransform = sanitizeInstanceTransform(node.transform);\n\n if (isModelNode(sourceNode)) {\n const previewColor = assetsById.get(sourceNode.data.assetId)?.metadata.previewColor;\n const primitive = createCylinderPrimitive();\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: sourceNode.name,\n primitives: [\n {\n indices: primitive.indices,\n material: await resolveExportMaterial({\n color: typeof previewColor === \"string\" ? previewColor : \"#7f8ea3\",\n id: `material:model:${sourceNode.id}`,\n metalness: 0.1,\n name: `${sourceNode.name} Material`,\n roughness: 0.55\n }),\n normals: computePrimitiveNormals(primitive.positions, primitive.indices),\n positions: primitive.positions,\n uvs: computeCylinderUvs(primitive.positions)\n }\n ]\n },\n meshKey: sourceNode.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(instanceTransform.rotation),\n scale: [instanceTransform.scale.x, instanceTransform.scale.y, instanceTransform.scale.z],\n translation: [instanceTransform.position.x, instanceTransform.position.y, instanceTransform.position.z]\n });\n continue;\n }\n\n const geometry = await buildExportGeometry(sourceNode, materialsById);\n\n if (geometry.primitives.length === 0) {\n continue;\n }\n\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: sourceNode.name,\n primitives: geometry.primitives\n },\n meshKey: sourceNode.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(instanceTransform.rotation),\n scale: [instanceTransform.scale.x, instanceTransform.scale.y, instanceTransform.scale.z],\n translation: [instanceTransform.position.x, instanceTransform.position.y, instanceTransform.position.z]\n });\n continue;\n }\n\n if (isModelNode(node)) {\n const previewColor = assetsById.get(node.data.assetId)?.metadata.previewColor;\n const primitive = createCylinderPrimitive();\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: node.name,\n primitives: [\n {\n indices: primitive.indices,\n material: await resolveExportMaterial({\n color: typeof previewColor === \"string\" ? previewColor : \"#7f8ea3\",\n id: `material:model:${node.id}`,\n metalness: 0.1,\n name: `${node.name} Material`,\n roughness: 0.55\n }),\n normals: computePrimitiveNormals(primitive.positions, primitive.indices),\n positions: primitive.positions,\n uvs: computeCylinderUvs(primitive.positions)\n }\n ]\n },\n meshKey: node.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(node.transform.rotation),\n scale: [node.transform.scale.x, node.transform.scale.y, node.transform.scale.z],\n translation: [node.transform.position.x, node.transform.position.y, node.transform.position.z]\n });\n }\n }\n\n return buildGltfDocument(exportedNodes);\n}\n\nasync function buildGltfDocument(\n exportedNodes: Array<{\n id: string;\n mesh?: {\n name: string;\n primitives: Array<{\n indices: number[];\n material: WebHammerExportMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n }>;\n };\n meshKey?: string;\n name: string;\n parentId?: string;\n rotation?: [number, number, number, number];\n scale: [number, number, number];\n translation: [number, number, number];\n }>\n): Promise<string> {\n const nodes: Array<Record<string, unknown>> = [];\n const gltfMeshes: Array<Record<string, unknown>> = [];\n const materials: Array<Record<string, unknown>> = [];\n const textures: Array<Record<string, unknown>> = [];\n const images: Array<Record<string, unknown>> = [];\n const samplers: Array<Record<string, unknown>> = [\n {\n magFilter: 9729,\n minFilter: 9987,\n wrapS: 10497,\n wrapT: 10497\n }\n ];\n const accessors: Array<Record<string, unknown>> = [];\n const bufferViews: Array<Record<string, unknown>> = [];\n const chunks: Uint8Array[] = [];\n const imageIndexByUri = new Map<string, number>();\n const textureIndexByUri = new Map<string, number>();\n const materialIndexById = new Map<string, number>();\n const meshIndexByKey = new Map<string, number>();\n\n const pushBuffer = (bytes: Uint8Array, target?: number) => {\n const padding = (4 - (bytes.byteLength % 4)) % 4;\n const padded = new Uint8Array(bytes.byteLength + padding);\n padded.set(bytes);\n const byteOffset = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n chunks.push(padded);\n bufferViews.push({\n buffer: 0,\n byteLength: bytes.byteLength,\n byteOffset,\n ...(target ? { target } : {})\n });\n return bufferViews.length - 1;\n };\n\n const nodeIndexById = new Map<string, number>();\n\n for (const exportedNode of exportedNodes) {\n let meshIndex: number | undefined;\n\n if (exportedNode.mesh) {\n const meshKey = exportedNode.meshKey ?? exportedNode.id;\n const cachedMeshIndex = meshIndexByKey.get(meshKey);\n\n if (cachedMeshIndex !== undefined) {\n meshIndex = cachedMeshIndex;\n } else {\n const gltfPrimitives: Array<Record<string, unknown>> = [];\n\n for (const primitive of exportedNode.mesh.primitives) {\n const positions = new Float32Array(primitive.positions);\n const normals = new Float32Array(primitive.normals);\n const uvs = new Float32Array(primitive.uvs);\n const indices = new Uint32Array(primitive.indices);\n const positionView = pushBuffer(new Uint8Array(positions.buffer.slice(0)), 34962);\n const normalView = pushBuffer(new Uint8Array(normals.buffer.slice(0)), 34962);\n const uvView = pushBuffer(new Uint8Array(uvs.buffer.slice(0)), 34962);\n const indexView = pushBuffer(new Uint8Array(indices.buffer.slice(0)), 34963);\n\n const bounds = computePositionBounds(primitive.positions);\n accessors.push({\n bufferView: positionView,\n componentType: 5126,\n count: positions.length / 3,\n max: bounds.max,\n min: bounds.min,\n type: \"VEC3\"\n });\n const positionAccessor = accessors.length - 1;\n\n accessors.push({\n bufferView: normalView,\n componentType: 5126,\n count: normals.length / 3,\n type: \"VEC3\"\n });\n const normalAccessor = accessors.length - 1;\n\n accessors.push({\n bufferView: uvView,\n componentType: 5126,\n count: uvs.length / 2,\n type: \"VEC2\"\n });\n const uvAccessor = accessors.length - 1;\n\n accessors.push({\n bufferView: indexView,\n componentType: 5125,\n count: indices.length,\n type: \"SCALAR\"\n });\n const indexAccessor = accessors.length - 1;\n\n const materialIndex = await ensureGltfMaterial(\n primitive.material,\n materials,\n textures,\n images,\n imageIndexByUri,\n textureIndexByUri,\n materialIndexById\n );\n\n gltfPrimitives.push({\n attributes: {\n NORMAL: normalAccessor,\n POSITION: positionAccessor,\n TEXCOORD_0: uvAccessor\n },\n indices: indexAccessor,\n material: materialIndex\n });\n }\n\n gltfMeshes.push({\n name: exportedNode.mesh.name,\n primitives: gltfPrimitives\n });\n meshIndex = gltfMeshes.length - 1;\n meshIndexByKey.set(meshKey, meshIndex);\n }\n }\n\n nodes.push({\n ...(meshIndex !== undefined ? { mesh: meshIndex } : {}),\n name: exportedNode.name,\n ...(exportedNode.rotation ? { rotation: exportedNode.rotation } : {}),\n scale: exportedNode.scale,\n translation: exportedNode.translation\n });\n nodeIndexById.set(exportedNode.id, nodes.length - 1);\n }\n\n const rootNodeIndices: number[] = [];\n\n exportedNodes.forEach((exportedNode, index) => {\n const parentIndex =\n exportedNode.parentId\n ? nodeIndexById.get(exportedNode.parentId)\n : undefined;\n\n if (parentIndex === undefined) {\n rootNodeIndices.push(index);\n return;\n }\n\n const parent = nodes[parentIndex] as { children?: number[] };\n parent.children = [...(parent.children ?? []), index];\n });\n\n const totalByteLength = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const merged = new Uint8Array(totalByteLength);\n let cursor = 0;\n chunks.forEach((chunk) => {\n merged.set(chunk, cursor);\n cursor += chunk.byteLength;\n });\n\n const gltf = {\n accessors,\n asset: {\n generator: \"web-hammer\",\n version: \"2.0\"\n },\n bufferViews,\n buffers: [\n {\n byteLength: merged.byteLength,\n uri: `data:application/octet-stream;base64,${toBase64(merged)}`\n }\n ],\n images,\n materials,\n meshes: gltfMeshes,\n nodes,\n samplers,\n scene: 0,\n scenes: [\n {\n nodes: rootNodeIndices\n }\n ],\n textures\n };\n\n return JSON.stringify(gltf, null, 2);\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 resolveExportMaterial({\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, {\n indices: number[];\n material: WebHammerExportMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n }>();\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 resolveExportMaterial(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 resolveExportMaterial(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: WebHammerExportGeometry,\n settings: SceneDocumentSnapshot[\"settings\"][\"world\"][\"lod\"]\n): Promise<WebHammerExportGeometryLod[] | 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: WebHammerExportGeometryLod[] = [];\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?: WebHammerExportModelLod[] }> {\n if (!asset?.path) {\n return { assets: [], lods: undefined };\n }\n\n const source = await loadModelSceneForLodBake(asset);\n const bakedLevels: Array<{ asset: Asset; level: WebHammerExportModelLod[\"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) => {\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) => {\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) => {\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) =>\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 child.material = child.material instanceof MeshStandardMaterial\n ? strip(child.material)\n : new MeshStandardMaterial({\n color: \"color\" in child.material ? child.material.color : \"#7f8ea3\",\n metalness: \"metalness\" in child.material && typeof child.material.metalness === \"number\" ? child.material.metalness : 0.1,\n roughness: \"roughness\" in child.material && typeof child.material.roughness === \"number\" ? child.material.roughness : 0.8\n });\n });\n\n return object;\n}\n\nfunction createGeneratedModelLodAsset(\n asset: Asset,\n name: string,\n nodeId: string,\n level: WebHammerExportModelLod[\"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: WebHammerExportGeometry, ratio: number): WebHammerExportGeometry | undefined {\n const primitives = geometry.primitives\n .map((primitive) => simplifyExportPrimitive(primitive, ratio))\n .filter((primitive): primitive is WebHammerExportGeometry[\"primitives\"][number] => primitive !== undefined);\n\n return primitives.length ? { primitives } : undefined;\n}\n\nfunction simplifyExportPrimitive(\n primitive: WebHammerExportGeometry[\"primitives\"][number],\n ratio: number\n): WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"primitives\"][number],\n ratio: number,\n bounds: Box3\n): WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"primitives\"][number],\n bounds: Box3,\n size: Vector3,\n resolution: number\n): WebHammerExportGeometry[\"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(\n cluster.positionX / cluster.count,\n cluster.positionY / cluster.count,\n cluster.positionZ / cluster.count\n );\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 resolveExportMaterial(material?: Material) {\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 } satisfies WebHammerExportMaterial;\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\nasync function ensureGltfMaterial(\n material: WebHammerExportMaterial,\n materials: Array<Record<string, unknown>>,\n textures: Array<Record<string, unknown>>,\n images: Array<Record<string, unknown>>,\n imageIndexByUri: Map<string, number>,\n textureIndexByUri: Map<string, number>,\n materialIndexById: Map<string, number>\n) {\n const existing = materialIndexById.get(material.id);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const baseColorTextureIndex = material.baseColorTexture\n ? ensureGltfTexture(material.baseColorTexture, textures, images, imageIndexByUri, textureIndexByUri)\n : undefined;\n const normalTextureIndex = material.normalTexture\n ? ensureGltfTexture(material.normalTexture, textures, images, imageIndexByUri, textureIndexByUri)\n : undefined;\n const metallicRoughnessTextureIndex = material.metallicRoughnessTexture\n ? ensureGltfTexture(material.metallicRoughnessTexture, textures, images, imageIndexByUri, textureIndexByUri)\n : undefined;\n\n materials.push({\n name: material.name,\n normalTexture: normalTextureIndex !== undefined ? { index: normalTextureIndex } : undefined,\n pbrMetallicRoughness: {\n ...(baseColorTextureIndex !== undefined ? { baseColorTexture: { index: baseColorTextureIndex } } : {}),\n ...(metallicRoughnessTextureIndex !== undefined\n ? { metallicRoughnessTexture: { index: metallicRoughnessTextureIndex } }\n : {}),\n baseColorFactor: hexToRgba(material.color),\n metallicFactor: material.metallicFactor,\n roughnessFactor: material.roughnessFactor\n }\n });\n\n const index = materials.length - 1;\n materialIndexById.set(material.id, index);\n return index;\n}\n\nfunction ensureGltfTexture(\n uri: string,\n textures: Array<Record<string, unknown>>,\n images: Array<Record<string, unknown>>,\n imageIndexByUri: Map<string, number>,\n textureIndexByUri: Map<string, number>\n) {\n const existingTexture = textureIndexByUri.get(uri);\n\n if (existingTexture !== undefined) {\n return existingTexture;\n }\n\n const imageIndex = imageIndexByUri.get(uri) ?? images.length;\n\n if (!imageIndexByUri.has(uri)) {\n images.push({ uri });\n imageIndexByUri.set(uri, imageIndex);\n }\n\n textures.push({ sampler: 0, source: imageIndex });\n const textureIndex = textures.length - 1;\n textureIndexByUri.set(uri, textureIndex);\n return textureIndex;\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 computePrimitiveNormals(positions: number[], indices: number[]) {\n const normals = new Array<number>(positions.length).fill(0);\n\n for (let index = 0; index < indices.length; index += 3) {\n const a = indices[index] * 3;\n const b = indices[index + 1] * 3;\n const c = indices[index + 2] * 3;\n const normal = normalizeVec3(\n crossVec3(\n vec3(positions[b] - positions[a], positions[b + 1] - positions[a + 1], positions[b + 2] - positions[a + 2]),\n vec3(positions[c] - positions[a], positions[c + 1] - positions[a + 1], positions[c + 2] - positions[a + 2])\n )\n );\n\n [a, b, c].forEach((offset) => {\n normals[offset] = normal.x;\n normals[offset + 1] = normal.y;\n normals[offset + 2] = normal.z;\n });\n }\n\n return normals;\n}\n\nfunction computeCylinderUvs(positions: number[]) {\n const uvs: number[] = [];\n\n for (let index = 0; index < positions.length; index += 3) {\n const x = positions[index];\n const y = positions[index + 1];\n const z = positions[index + 2];\n const u = (Math.atan2(z, x) / (Math.PI * 2) + 1) % 1;\n const v = y > 0 ? 1 : 0;\n uvs.push(u, v);\n }\n\n return uvs;\n}\n\nfunction clamp01(value: number) {\n return Math.max(0, Math.min(1, value));\n}\n\nfunction toQuaternion(rotation: Vec3): [number, number, number, number] {\n const quaternion = new Quaternion().setFromEuler(new Euler(rotation.x, rotation.y, rotation.z, \"XYZ\"));\n return [quaternion.x, quaternion.y, quaternion.z, quaternion.w];\n}\n\nfunction createCylinderPrimitive() {\n const radius = 0.65;\n const halfHeight = 1.1;\n const segments = 12;\n const positions: number[] = [];\n const indices: number[] = [];\n\n for (let index = 0; index < segments; index += 1) {\n const angle = (index / segments) * Math.PI * 2;\n const x = Math.cos(angle) * radius;\n const z = Math.sin(angle) * radius;\n positions.push(x, -halfHeight, z, x, halfHeight, z);\n }\n\n for (let index = 0; index < segments; index += 1) {\n const next = (index + 1) % segments;\n const bottom = index * 2;\n const top = bottom + 1;\n const nextBottom = next * 2;\n const nextTop = nextBottom + 1;\n\n indices.push(bottom, nextBottom, top, top, nextBottom, nextTop);\n }\n\n return { indices, positions };\n}\n\nfunction computePositionBounds(positions: number[]) {\n const min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];\n const max = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];\n\n for (let index = 0; index < positions.length; index += 3) {\n min[0] = Math.min(min[0], positions[index]);\n min[1] = Math.min(min[1], positions[index + 1]);\n min[2] = Math.min(min[2], positions[index + 2]);\n max[0] = Math.max(max[0], positions[index]);\n max[1] = Math.max(max[1], positions[index + 1]);\n max[2] = Math.max(max[2], positions[index + 2]);\n }\n\n return { max, min };\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\nfunction hexToRgba(hex: string): [number, number, number, number] {\n const normalized = hex.replace(\"#\", \"\");\n const parsed = Number.parseInt(normalized, 16);\n return [((parsed >> 16) & 255) / 255, ((parsed >> 8) & 255) / 255, (parsed & 255) / 255, 1];\n}\n","export const workerIds = [\"geometryWorker\", \"meshWorker\", \"navWorker\", \"exportWorker\"] as const;\n\nexport type WorkerId = (typeof workerIds)[number];\n\nexport type WorkerTask =\n | { worker: \"geometryWorker\"; task: \"brush-rebuild\" | \"clip\" | \"triangulation\" }\n | { worker: \"meshWorker\"; task: \"triangulation\" | \"loop-cut\" | \"bevel\" }\n | { worker: \"navWorker\"; task: \"navmesh\" }\n | { worker: \"exportWorker\"; task: \"ai-model-generate\" | \"engine-format\" | \"gltf\" | \"usd\" | \"whmap-load\" | \"whmap-save\" };\n"],"mappings":";AAmBO,SAAS,0BAA6C;AAC3D,MAAI,UAAU;AACd,QAAM,OAAO,oBAAI,IAAuB;AACxC,QAAM,YAAY,oBAAI,IAAc;AAEpC,QAAM,OAAO,MAAM;AACjB,UAAM,WAAW,MAAM,KAAK,KAAK,OAAO,CAAC;AACzC,cAAU,QAAQ,CAAC,aAAa;AAC9B,eAAS,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,QAAQ,MAAM,OAAO,aAAa,KAAK;AACrC,YAAM,KAAK,OAAO,SAAS;AAC3B,WAAK,IAAI,IAAI;AAAA,QACX;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AACD,WAAK;AAEL,qBAAe,MAAM;AACnB,cAAM,MAAM,KAAK,IAAI,EAAE;AAEvB,YAAI,CAAC,KAAK;AACR;AAAA,QACF;AAEA,YAAI,SAAS;AACb,aAAK;AAEL,eAAO,WAAW,MAAM;AACtB,gBAAM,aAAa,KAAK,IAAI,EAAE;AAE9B,cAAI,CAAC,YAAY;AACf;AAAA,UACF;AAEA,qBAAW,SAAS;AACpB,eAAK;AAEL,iBAAO,WAAW,MAAM;AACtB,iBAAK,OAAO,EAAE;AACd,iBAAK;AAAA,UACP,GAAG,GAAG;AAAA,QACR,GAAG,UAAU;AAAA,MACf,CAAC;AAED,aAAO;AAAA,IACT;AAAA,IACA,UAAU;AACR,aAAO,MAAM,KAAK,KAAK,OAAO,CAAC;AAAA,IACjC;AAAA,IACA,UAAU,UAAU;AAClB,gBAAU,IAAI,QAAQ;AACtB,eAAS,MAAM,KAAK,KAAK,OAAO,CAAC,CAAC;AAElC,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;;;ACjEA,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;AAiRvB,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;;;ACtfA,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;;;AC7VA,SAAS,WAAW,eAAe;;;ACiB5B,IAAM,gCAAgC;;;ADL7C,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;AAqFA,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,UAAMA,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;AA4BA,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;;;AEzXA,SAAS,eAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAAC;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,iBAAiB;AAG1B,IAAM,aAAa,IAAI,WAAW;AAClC,IAAM,eAAe,IAAI,aAAa;AACtC,IAAM,YAAY,IAAI,UAAU;AAChC,IAAM,qBAAqB,IAAI,cAAc;AAc7C,eAAsB,+BACpB,UACA,UAA2C,CAAC,GACpB;AACxB,SAAO,yBAAyB,MAAM,8BAA8B,QAAQ,GAAG,OAAO;AACxF;AAEA,eAAsB,sBAAsB,UAAkD;AAC5F,SAAO,KAAK,UAAU,MAAM,8BAA8B,QAAQ,CAAC;AACrE;AAEA,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;AAYA,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,IAAI,UAAU;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,kBAAkB,UAAU,MAAM,0BAA0B,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,MAAM,mBAAmB,UAAU,mBAAmB;AACtE,cAAQ,QAAQ;AAChB,cAAQ,QAAQ;AAChB,cAAQ,aAAa;AAErB,aAAO,SAAS,CAAC,UAAoB;AACnC,YAAI,iBAAiB,MAAM;AACzB,gBAAM,WAAW,IAAI,qBAAqB;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,MAAM,WAAW,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,iBAAiB,OAAO;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,iBAAiB,SAAS,CAAC,MAAM,QAAQ,MAAM,QAAQ,KAAK,MAAM,SAAS,OAAO,UAAU,KAAK,CAAC,MAAM,QAAQ;AACpH;AAAA,IACF;AAEA,UAAM,YAAY,IAAI,MAAM;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,IAAI,KAAK,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,IAAI,eAAe;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,IAAI,MAAM;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,iBAAiB,OAAO;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,oBAAoB,uBAChB,MAAM,QAAQ,IACd,IAAI,qBAAqB;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,oBAAoB,uBACvC,MAAM,MAAM,QAAQ,IACpB,IAAI,qBAAqB;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,mBAAmBC,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,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,gBAAgB,aAAa,GAAG,WAAW,KAAK,CAAC;AAAA,SAAY,WAAW;AAAA;AACjF;AAEA,SAASA,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,IAAI,KAAK,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,IAAI,eAAe;AACpC,WAAS,aAAa,YAAY,IAAI,uBAAuB,UAAU,WAAW,CAAC,CAAC;AACpF,WAAS,aAAa,UAAU,IAAI,uBAAuB,UAAU,SAAS,CAAC,CAAC;AAEhF,MAAI,UAAU,IAAI,QAAQ;AACxB,aAAS,aAAa,MAAM,IAAI,uBAAuB,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,IAAI,YAAY,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;;;ACzoCA,SAAS,WAAAC,gBAAe;AACxB;AAAA,EACE,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,oBAAAC;AAAA,EACA,SAAAC;AAAA,EACA,0BAAAC;AAAA,EACA,SAAAC;AAAA,EACA,QAAAC;AAAA,EACA,wBAAAC;AAAA,EAEA,cAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,SAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,WAAAC;AAAA,OACK;AACP,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,aAAAC,kBAAiB;AAwC1B,IAAMC,cAAa,IAAIH,YAAW;AAClC,IAAMI,gBAAe,IAAIL,cAAa;AACtC,IAAMM,aAAY,IAAIJ,WAAU;AAChC,IAAMK,sBAAqB,IAAIT,eAAc;AAE7C,eAAsB,qBAAqB,SAAiD;AAC1F,MAAI;AACF,QAAI,QAAQ,SAAS,cAAc;AACjC,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,IAAI;AAAA,QACJ,SAAS,eAAe,QAAQ,QAAQ;AAAA,MAC1C;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,cAAc;AACjC,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,IAAI;AAAA,QACJ,SAAS,WAAW,QAAQ,IAAI;AAAA,MAClC;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,iBAAiB;AACpC,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,IAAI;AAAA,QACJ,SAAS,MAAM,mBAAmB,QAAQ,QAAQ;AAAA,MACpD;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,qBAAqB;AACxC,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,IAAI;AAAA,QACJ,SAAS,MAAM,gBAAgB,QAAQ,MAAM;AAAA,MAC/C;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,IAAI;AAAA,MACJ,SAAS,MAAM,mBAAmB,QAAQ,QAAQ;AAAA,IACpD;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,IAAI;AAAA,MACJ,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;AAEA,eAAe,gBAAgB,QAAiC;AAC9D,QAAM,WAAW,MAAM,MAAM,IAAI,IAAI,kBAAkB,KAAK,SAAS,MAAM,GAAG;AAAA,IAC5E,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,IAC/B,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,IACA,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,UAAU,MAAM,SAAS,KAAK;AAEpC,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,OAAO;AACjC,YAAM,IAAI,MAAM,OAAO,SAAS,8BAA8B;AAAA,IAChE,QAAQ;AACN,YAAM,IAAI,MAAM,WAAW,8BAA8B;AAAA,IAC3D;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,eAAe,UAAyC;AACtE,SAAO,KAAK;AAAA,IACV;AAAA,MACE,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,WAAW,MAAqC;AAC9D,QAAM,SAAS,KAAK,MAAM,IAAI;AAM9B,MAAI,OAAO,WAAW,WAAW,CAAC,OAAO,OAAO;AAC9C,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AAEA,SAAO,OAAO;AAChB;AAEA,eAAsB,qBAAqB,UAAkD;AAC3F,SAAO,sBAAsB,QAAQ;AACvC;AAEA,eAAsB,mBAAmB,UAAiE;AACxG,SAAO,+BAA+B,QAAQ;AAChD;AAMA,eAAsB,mBAAmB,UAAkD;AACzF,QAAM,gBAAgB,IAAI,IAAI,SAAS,UAAU,IAAI,CAAC,aAAa,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC;AAC3F,QAAM,aAAa,IAAI,IAAI,SAAS,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AAC5E,QAAM,gBAkBD,CAAC;AAEN,aAAW,QAAQ,SAAS,OAAO;AACjC,QAAI,YAAY,IAAI,GAAG;AACrB,oBAAc,KAAK;AAAA,QACjB,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,UAAU,aAAa,KAAK,UAAU,QAAQ;AAAA,QAC9C,OAAO,CAAC,KAAK,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,CAAC;AAAA,QAC9E,aAAa,CAAC,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,SAAS,CAAC;AAAA,MAC/F,CAAC;AACD;AAAA,IACF;AAEA,QAAI,YAAY,IAAI,KAAK,WAAW,IAAI,KAAK,gBAAgB,IAAI,GAAG;AAClE,YAAM,WAAW,MAAMU,qBAAoB,MAAM,aAAa;AAE9D,UAAI,SAAS,WAAW,WAAW,GAAG;AACpC;AAAA,MACF;AAEA,oBAAc,KAAK;AAAA,QACjB,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,UACJ,MAAM,KAAK;AAAA,UACX,YAAY,SAAS;AAAA,QACvB;AAAA,QACA,SAAS,KAAK;AAAA,QACd,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,UAAU,aAAa,KAAK,UAAU,QAAQ;AAAA,QAC9C,OAAO,CAAC,KAAK,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,CAAC;AAAA,QAC9E,aAAa,CAAC,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,SAAS,CAAC;AAAA,MAC/F,CAAC;AACD;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,YAAM,oBAAoBC,2BAA0B,KAAK,SAAS;AAElE,UAAI,YAAY,UAAU,GAAG;AAC3B,cAAM,eAAe,WAAW,IAAI,WAAW,KAAK,OAAO,GAAG,SAAS;AACvE,cAAM,YAAY,wBAAwB;AAC1C,sBAAc,KAAK;AAAA,UACjB,IAAI,KAAK;AAAA,UACT,MAAM;AAAA,YACJ,MAAM,WAAW;AAAA,YACjB,YAAY;AAAA,cACV;AAAA,gBACE,SAAS,UAAU;AAAA,gBACnB,UAAU,MAAM,sBAAsB;AAAA,kBACpC,OAAO,OAAO,iBAAiB,WAAW,eAAe;AAAA,kBACzD,IAAI,kBAAkB,WAAW,EAAE;AAAA,kBACnC,WAAW;AAAA,kBACX,MAAM,GAAG,WAAW,IAAI;AAAA,kBACxB,WAAW;AAAA,gBACb,CAAC;AAAA,gBACD,SAAS,wBAAwB,UAAU,WAAW,UAAU,OAAO;AAAA,gBACvE,WAAW,UAAU;AAAA,gBACrB,KAAK,mBAAmB,UAAU,SAAS;AAAA,cAC7C;AAAA,YACF;AAAA,UACF;AAAA,UACA,SAAS,WAAW;AAAA,UACpB,MAAM,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,UAAU,aAAa,kBAAkB,QAAQ;AAAA,UACjD,OAAO,CAAC,kBAAkB,MAAM,GAAG,kBAAkB,MAAM,GAAG,kBAAkB,MAAM,CAAC;AAAA,UACvF,aAAa,CAAC,kBAAkB,SAAS,GAAG,kBAAkB,SAAS,GAAG,kBAAkB,SAAS,CAAC;AAAA,QACxG,CAAC;AACD;AAAA,MACF;AAEA,YAAM,WAAW,MAAMD,qBAAoB,YAAY,aAAa;AAEpE,UAAI,SAAS,WAAW,WAAW,GAAG;AACpC;AAAA,MACF;AAEA,oBAAc,KAAK;AAAA,QACjB,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,UACJ,MAAM,WAAW;AAAA,UACjB,YAAY,SAAS;AAAA,QACvB;AAAA,QACA,SAAS,WAAW;AAAA,QACpB,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,UAAU,aAAa,kBAAkB,QAAQ;AAAA,QACjD,OAAO,CAAC,kBAAkB,MAAM,GAAG,kBAAkB,MAAM,GAAG,kBAAkB,MAAM,CAAC;AAAA,QACvF,aAAa,CAAC,kBAAkB,SAAS,GAAG,kBAAkB,SAAS,GAAG,kBAAkB,SAAS,CAAC;AAAA,MACxG,CAAC;AACD;AAAA,IACF;AAEA,QAAI,YAAY,IAAI,GAAG;AACrB,YAAM,eAAe,WAAW,IAAI,KAAK,KAAK,OAAO,GAAG,SAAS;AACjE,YAAM,YAAY,wBAAwB;AAC1C,oBAAc,KAAK;AAAA,QACjB,IAAI,KAAK;AAAA,QACT,MAAM;AAAA,UACJ,MAAM,KAAK;AAAA,UACX,YAAY;AAAA,YACV;AAAA,cACE,SAAS,UAAU;AAAA,cACnB,UAAU,MAAM,sBAAsB;AAAA,gBACpC,OAAO,OAAO,iBAAiB,WAAW,eAAe;AAAA,gBACzD,IAAI,kBAAkB,KAAK,EAAE;AAAA,gBAC7B,WAAW;AAAA,gBACX,MAAM,GAAG,KAAK,IAAI;AAAA,gBAClB,WAAW;AAAA,cACb,CAAC;AAAA,cACD,SAAS,wBAAwB,UAAU,WAAW,UAAU,OAAO;AAAA,cACvE,WAAW,UAAU;AAAA,cACrB,KAAK,mBAAmB,UAAU,SAAS;AAAA,YAC7C;AAAA,UACF;AAAA,QACF;AAAA,QACA,SAAS,KAAK;AAAA,QACd,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,UAAU,aAAa,KAAK,UAAU,QAAQ;AAAA,QAC9C,OAAO,CAAC,KAAK,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,GAAG,KAAK,UAAU,MAAM,CAAC;AAAA,QAC9E,aAAa,CAAC,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,SAAS,GAAG,KAAK,UAAU,SAAS,CAAC;AAAA,MAC/F,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,kBAAkB,aAAa;AACxC;AAEA,eAAe,kBACb,eAmBiB;AACjB,QAAM,QAAwC,CAAC;AAC/C,QAAM,aAA6C,CAAC;AACpD,QAAM,YAA4C,CAAC;AACnD,QAAM,WAA2C,CAAC;AAClD,QAAM,SAAyC,CAAC;AAChD,QAAM,WAA2C;AAAA,IAC/C;AAAA,MACE,WAAW;AAAA,MACX,WAAW;AAAA,MACX,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,YAA4C,CAAC;AACnD,QAAM,cAA8C,CAAC;AACrD,QAAM,SAAuB,CAAC;AAC9B,QAAM,kBAAkB,oBAAI,IAAoB;AAChD,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,iBAAiB,oBAAI,IAAoB;AAE/C,QAAM,aAAa,CAAC,OAAmB,WAAoB;AACzD,UAAM,WAAW,IAAK,MAAM,aAAa,KAAM;AAC/C,UAAM,SAAS,IAAI,WAAW,MAAM,aAAa,OAAO;AACxD,WAAO,IAAI,KAAK;AAChB,UAAM,aAAa,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,YAAY,CAAC;AAC1E,WAAO,KAAK,MAAM;AAClB,gBAAY,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,YAAY,MAAM;AAAA,MAClB;AAAA,MACA,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC7B,CAAC;AACD,WAAO,YAAY,SAAS;AAAA,EAC9B;AAEA,QAAM,gBAAgB,oBAAI,IAAoB;AAE9C,aAAW,gBAAgB,eAAe;AACxC,QAAI;AAEJ,QAAI,aAAa,MAAM;AACrB,YAAM,UAAU,aAAa,WAAW,aAAa;AACrD,YAAM,kBAAkB,eAAe,IAAI,OAAO;AAElD,UAAI,oBAAoB,QAAW;AACjC,oBAAY;AAAA,MACd,OAAO;AACL,cAAM,iBAAiD,CAAC;AAExD,mBAAW,aAAa,aAAa,KAAK,YAAY;AACpD,gBAAM,YAAY,IAAI,aAAa,UAAU,SAAS;AACtD,gBAAM,UAAU,IAAI,aAAa,UAAU,OAAO;AAClD,gBAAM,MAAM,IAAI,aAAa,UAAU,GAAG;AAC1C,gBAAM,UAAU,IAAI,YAAY,UAAU,OAAO;AACjD,gBAAM,eAAe,WAAW,IAAI,WAAW,UAAU,OAAO,MAAM,CAAC,CAAC,GAAG,KAAK;AAChF,gBAAM,aAAa,WAAW,IAAI,WAAW,QAAQ,OAAO,MAAM,CAAC,CAAC,GAAG,KAAK;AAC5E,gBAAM,SAAS,WAAW,IAAI,WAAW,IAAI,OAAO,MAAM,CAAC,CAAC,GAAG,KAAK;AACpE,gBAAM,YAAY,WAAW,IAAI,WAAW,QAAQ,OAAO,MAAM,CAAC,CAAC,GAAG,KAAK;AAE3E,gBAAM,SAAS,sBAAsB,UAAU,SAAS;AACxD,oBAAU,KAAK;AAAA,YACb,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,OAAO,UAAU,SAAS;AAAA,YAC1B,KAAK,OAAO;AAAA,YACZ,KAAK,OAAO;AAAA,YACZ,MAAM;AAAA,UACR,CAAC;AACD,gBAAM,mBAAmB,UAAU,SAAS;AAE5C,oBAAU,KAAK;AAAA,YACb,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,OAAO,QAAQ,SAAS;AAAA,YACxB,MAAM;AAAA,UACR,CAAC;AACD,gBAAM,iBAAiB,UAAU,SAAS;AAE1C,oBAAU,KAAK;AAAA,YACb,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,OAAO,IAAI,SAAS;AAAA,YACpB,MAAM;AAAA,UACR,CAAC;AACD,gBAAM,aAAa,UAAU,SAAS;AAEtC,oBAAU,KAAK;AAAA,YACb,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,OAAO,QAAQ;AAAA,YACf,MAAM;AAAA,UACR,CAAC;AACD,gBAAM,gBAAgB,UAAU,SAAS;AAEzC,gBAAM,gBAAgB,MAAM;AAAA,YAC1B,UAAU;AAAA,YACV;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,yBAAe,KAAK;AAAA,YAClB,YAAY;AAAA,cACV,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YACA,SAAS;AAAA,YACT,UAAU;AAAA,UACZ,CAAC;AAAA,QACH;AAEA,mBAAW,KAAK;AAAA,UACd,MAAM,aAAa,KAAK;AAAA,UACxB,YAAY;AAAA,QACd,CAAC;AACD,oBAAY,WAAW,SAAS;AAChC,uBAAe,IAAI,SAAS,SAAS;AAAA,MACvC;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,MACT,GAAI,cAAc,SAAY,EAAE,MAAM,UAAU,IAAI,CAAC;AAAA,MACrD,MAAM,aAAa;AAAA,MACnB,GAAI,aAAa,WAAW,EAAE,UAAU,aAAa,SAAS,IAAI,CAAC;AAAA,MACnE,OAAO,aAAa;AAAA,MACpB,aAAa,aAAa;AAAA,IAC5B,CAAC;AACD,kBAAc,IAAI,aAAa,IAAI,MAAM,SAAS,CAAC;AAAA,EACrD;AAEA,QAAM,kBAA4B,CAAC;AAEnC,gBAAc,QAAQ,CAAC,cAAc,UAAU;AAC7C,UAAM,cACJ,aAAa,WACT,cAAc,IAAI,aAAa,QAAQ,IACvC;AAEN,QAAI,gBAAgB,QAAW;AAC7B,sBAAgB,KAAK,KAAK;AAC1B;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,WAAW;AAChC,WAAO,WAAW,CAAC,GAAI,OAAO,YAAY,CAAC,GAAI,KAAK;AAAA,EACtD,CAAC;AAED,QAAM,kBAAkB,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,YAAY,CAAC;AAC/E,QAAM,SAAS,IAAI,WAAW,eAAe;AAC7C,MAAI,SAAS;AACb,SAAO,QAAQ,CAAC,UAAU;AACxB,WAAO,IAAI,OAAO,MAAM;AACxB,cAAU,MAAM;AAAA,EAClB,CAAC;AAED,QAAM,OAAO;AAAA,IACX;AAAA,IACA,OAAO;AAAA,MACL,WAAW;AAAA,MACX,SAAS;AAAA,IACX;AAAA,IACA;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,YAAY,OAAO;AAAA,QACnB,KAAK,wCAAwCE,UAAS,MAAM,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,MACN;AAAA,QACE,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAEA,SAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AACrC;AAEA,eAAeF,qBACb,MACA,eACA;AACA,QAAM,mBAAmB,MAAM,sBAAsB;AAAA,IACnD,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,IAM7B;AAEH,QAAM,aAAa,OAAO,WAQpB;AACJ,UAAM,WAAW,OAAO,iBAAiB,MAAM,sBAAsB,cAAc,IAAI,OAAO,cAAc,CAAC,IAAI;AACjH,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,IACvCG,kBAAiB,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,sBAAsB,cAAc,IAAI,KAAK,KAAK,UAAU,CAAC,IAAI;AAC/G,UAAM,YAAYC,wBAAuB,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;AAqXA,SAASC,2BAA0B,WAAgE;AACjG,SAAO;AAAA,IACL,UAAU,gBAAgB,UAAU,QAAQ;AAAA,IAC5C,UAAU,gBAAgB,UAAU,QAAQ;AAAA,IAC5C,OAAO,gBAAgB,UAAU,KAAK;AAAA,EACxC;AACF;AA0RA,SAASC,wBAAuB,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,IAAIC,gBAAe,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,IAAIC,kBAAiB,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,IAAIC,cAAa,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,sBAAsB,UAAqB;AACxD,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,MAAMC,2BAA0B,SAAS,gBAAgBC,iCAAgC,QAAQ,CAAC;AAAA,IACpH,OAAO,SAAS;AAAA,IAChB,IAAI,SAAS;AAAA,IACb,gBAAgB,SAAS,aAAa;AAAA,IACtC,0BAA0B,MAAMC;AAAA,MAC9B,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS,aAAa;AAAA,MACtB,SAAS,aAAa;AAAA,IACxB;AAAA,IACA,MAAM,SAAS;AAAA,IACf,eAAe,MAAMF,2BAA0B,SAAS,aAAa;AAAA,IACrE,iBAAiB,SAAS,aAAa;AAAA,IACvC,MAAM,SAAS;AAAA,EACjB;AACF;AAEA,SAASC,iCAAgC,UAAoB;AAC3D,SAAO,SAAS,aAAa,aACzB,6BAA6B,SAAS,OAAO,SAAS,aAAa,WAAW,SAAS,iBAAiB,KAAK,IAC7G;AACN;AAEA,eAAe,mBACb,UACA,WACA,UACA,QACA,iBACA,mBACA,mBACA;AACA,QAAM,WAAW,kBAAkB,IAAI,SAAS,EAAE;AAElD,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,wBAAwB,SAAS,mBACnC,kBAAkB,SAAS,kBAAkB,UAAU,QAAQ,iBAAiB,iBAAiB,IACjG;AACJ,QAAM,qBAAqB,SAAS,gBAChC,kBAAkB,SAAS,eAAe,UAAU,QAAQ,iBAAiB,iBAAiB,IAC9F;AACJ,QAAM,gCAAgC,SAAS,2BAC3C,kBAAkB,SAAS,0BAA0B,UAAU,QAAQ,iBAAiB,iBAAiB,IACzG;AAEJ,YAAU,KAAK;AAAA,IACb,MAAM,SAAS;AAAA,IACf,eAAe,uBAAuB,SAAY,EAAE,OAAO,mBAAmB,IAAI;AAAA,IAClF,sBAAsB;AAAA,MACpB,GAAI,0BAA0B,SAAY,EAAE,kBAAkB,EAAE,OAAO,sBAAsB,EAAE,IAAI,CAAC;AAAA,MACpG,GAAI,kCAAkC,SAClC,EAAE,0BAA0B,EAAE,OAAO,8BAA8B,EAAE,IACrE,CAAC;AAAA,MACL,iBAAiB,UAAU,SAAS,KAAK;AAAA,MACzC,gBAAgB,SAAS;AAAA,MACzB,iBAAiB,SAAS;AAAA,IAC5B;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,UAAU,SAAS;AACjC,oBAAkB,IAAI,SAAS,IAAI,KAAK;AACxC,SAAO;AACT;AAEA,SAAS,kBACP,KACA,UACA,QACA,iBACA,mBACA;AACA,QAAM,kBAAkB,kBAAkB,IAAI,GAAG;AAEjD,MAAI,oBAAoB,QAAW;AACjC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,gBAAgB,IAAI,GAAG,KAAK,OAAO;AAEtD,MAAI,CAAC,gBAAgB,IAAI,GAAG,GAAG;AAC7B,WAAO,KAAK,EAAE,IAAI,CAAC;AACnB,oBAAgB,IAAI,KAAK,UAAU;AAAA,EACrC;AAEA,WAAS,KAAK,EAAE,SAAS,GAAG,QAAQ,WAAW,CAAC;AAChD,QAAM,eAAe,SAAS,SAAS;AACvC,oBAAkB,IAAI,KAAK,YAAY;AACvC,SAAO;AACT;AAEA,SAASE,kBAAiB,UAAkB,QAAc,SAAgB,UAAiB;AACzF,QAAM,QAAQC,sBAAqB,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,SAASA,sBAAqB,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,eAAeJ,2BAA0B,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,WAAWK,UAAS,IAAI,WAAW,MAAM,CAAC,CAAC;AACnG;AAEA,eAAeH,uCACb,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/CI,iBAAgB,eAAe;AAAA,IAC/BA,iBAAgB,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,MAAMC,SAAQ,eAAe,IAAI,GAAG;AAC9D,QAAM,eAAe,KAAK,MAAMA,SAAQ,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,yBAAyBF,UAAS,IAAI,WAAW,MAAM,CAAC,CAAC;AAClE;AAEA,eAAeC,iBAAgB,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,wBAAwB,WAAqB,SAAmB;AACvE,QAAM,UAAU,IAAI,MAAc,UAAU,MAAM,EAAE,KAAK,CAAC;AAE1D,WAAS,QAAQ,GAAG,QAAQ,QAAQ,QAAQ,SAAS,GAAG;AACtD,UAAM,IAAI,QAAQ,KAAK,IAAI;AAC3B,UAAM,IAAI,QAAQ,QAAQ,CAAC,IAAI;AAC/B,UAAM,IAAI,QAAQ,QAAQ,CAAC,IAAI;AAC/B,UAAM,SAAS;AAAA,MACb;AAAA,QACE,KAAK,UAAU,CAAC,IAAI,UAAU,CAAC,GAAG,UAAU,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,GAAG,UAAU,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC;AAAA,QAC1G,KAAK,UAAU,CAAC,IAAI,UAAU,CAAC,GAAG,UAAU,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,GAAG,UAAU,IAAI,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC;AAAA,MAC5G;AAAA,IACF;AAEA,KAAC,GAAG,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW;AAC5B,cAAQ,MAAM,IAAI,OAAO;AACzB,cAAQ,SAAS,CAAC,IAAI,OAAO;AAC7B,cAAQ,SAAS,CAAC,IAAI,OAAO;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,WAAqB;AAC/C,QAAM,MAAgB,CAAC;AAEvB,WAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACxD,UAAM,IAAI,UAAU,KAAK;AACzB,UAAM,IAAI,UAAU,QAAQ,CAAC;AAC7B,UAAM,IAAI,UAAU,QAAQ,CAAC;AAC7B,UAAM,KAAK,KAAK,MAAM,GAAG,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK;AACnD,UAAM,IAAI,IAAI,IAAI,IAAI;AACtB,QAAI,KAAK,GAAG,CAAC;AAAA,EACf;AAEA,SAAO;AACT;AAEA,SAASC,SAAQ,OAAe;AAC9B,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AACvC;AAEA,SAAS,aAAa,UAAkD;AACtE,QAAM,aAAa,IAAIC,YAAW,EAAE,aAAa,IAAIC,OAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,CAAC;AACrG,SAAO,CAAC,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAChE;AAEA,SAAS,0BAA0B;AACjC,QAAM,SAAS;AACf,QAAM,aAAa;AACnB,QAAM,WAAW;AACjB,QAAM,YAAsB,CAAC;AAC7B,QAAM,UAAoB,CAAC;AAE3B,WAAS,QAAQ,GAAG,QAAQ,UAAU,SAAS,GAAG;AAChD,UAAM,QAAS,QAAQ,WAAY,KAAK,KAAK;AAC7C,UAAM,IAAI,KAAK,IAAI,KAAK,IAAI;AAC5B,UAAM,IAAI,KAAK,IAAI,KAAK,IAAI;AAC5B,cAAU,KAAK,GAAG,CAAC,YAAY,GAAG,GAAG,YAAY,CAAC;AAAA,EACpD;AAEA,WAAS,QAAQ,GAAG,QAAQ,UAAU,SAAS,GAAG;AAChD,UAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAM,SAAS,QAAQ;AACvB,UAAM,MAAM,SAAS;AACrB,UAAM,aAAa,OAAO;AAC1B,UAAM,UAAU,aAAa;AAE7B,YAAQ,KAAK,QAAQ,YAAY,KAAK,KAAK,YAAY,OAAO;AAAA,EAChE;AAEA,SAAO,EAAE,SAAS,UAAU;AAC9B;AAEA,SAAS,sBAAsB,WAAqB;AAClD,QAAM,MAAM,CAAC,OAAO,mBAAmB,OAAO,mBAAmB,OAAO,iBAAiB;AACzF,QAAM,MAAM,CAAC,OAAO,mBAAmB,OAAO,mBAAmB,OAAO,iBAAiB;AAEzF,WAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS,GAAG;AACxD,QAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,UAAU,KAAK,CAAC;AAC1C,QAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,UAAU,QAAQ,CAAC,CAAC;AAC9C,QAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,UAAU,QAAQ,CAAC,CAAC;AAC9C,QAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,UAAU,KAAK,CAAC;AAC1C,QAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,UAAU,QAAQ,CAAC,CAAC;AAC9C,QAAI,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,UAAU,QAAQ,CAAC,CAAC;AAAA,EAChD;AAEA,SAAO,EAAE,KAAK,IAAI;AACpB;AAEA,SAASJ,UAAS,OAA2B;AAC3C,MAAI,SAAS;AACb,QAAM,QAAQ,CAAC,SAAS;AACtB,cAAU,OAAO,aAAa,IAAI;AAAA,EACpC,CAAC;AACD,SAAO,KAAK,MAAM;AACpB;AAEA,SAAS,UAAU,KAA+C;AAChE,QAAM,aAAa,IAAI,QAAQ,KAAK,EAAE;AACtC,QAAM,SAAS,OAAO,SAAS,YAAY,EAAE;AAC7C,SAAO,EAAG,UAAU,KAAM,OAAO,MAAO,UAAU,IAAK,OAAO,MAAM,SAAS,OAAO,KAAK,CAAC;AAC5F;;;ACnqDO,IAAM,YAAY,CAAC,kBAAkB,cAAc,aAAa,cAAc;","names":["path","Vector3","slugify","Vector3","MeshBVH","Box3","BoxGeometry","BufferGeometry","ConeGeometry","CylinderGeometry","Euler","Float32BufferAttribute","Group","Mesh","MeshStandardMaterial","Quaternion","RepeatWrapping","Scene","SphereGeometry","SRGBColorSpace","TextureLoader","Vector3","GLTFExporter","GLTFLoader","MTLLoader","OBJLoader","gltfLoader","gltfExporter","mtlLoader","modelTextureLoader","buildExportGeometry","sanitizeInstanceTransform","toBase64","projectPlanarUvs","buildPrimitiveGeometry","sanitizeInstanceTransform","buildPrimitiveGeometry","BoxGeometry","SphereGeometry","CylinderGeometry","ConeGeometry","resolveEmbeddedTextureUri","resolveGeneratedBlockoutTexture","createMetallicRoughnessTextureDataUri","projectPlanarUvs","createFacePlaneBasis","toBase64","loadImagePixels","clamp01","Quaternion","Euler"]}
1
+ {"version":3,"sources":["../src/manager.ts","../src/export-tasks.ts","../src/tasks.ts"],"sourcesContent":["import type { WorkerTask } from \"./tasks\";\n\nexport type WorkerJobStatus = \"queued\" | \"running\" | \"completed\";\n\nexport type WorkerJob = {\n id: string;\n label: string;\n status: WorkerJobStatus;\n task: WorkerTask;\n};\n\ntype Listener = (jobs: WorkerJob[]) => void;\n\nexport type WorkerTaskManager = {\n enqueue: (task: WorkerTask, label: string, durationMs?: number) => string;\n getJobs: () => WorkerJob[];\n subscribe: (listener: Listener) => () => void;\n};\n\nexport function createWorkerTaskManager(): WorkerTaskManager {\n let counter = 0;\n const jobs = new Map<string, WorkerJob>();\n const listeners = new Set<Listener>();\n\n const emit = () => {\n const snapshot = Array.from(jobs.values());\n listeners.forEach((listener) => {\n listener(snapshot);\n });\n };\n\n return {\n enqueue(task, label, durationMs = 900) {\n const id = `job:${counter++}`;\n jobs.set(id, {\n id,\n label,\n status: \"queued\",\n task\n });\n emit();\n\n queueMicrotask(() => {\n const job = jobs.get(id);\n\n if (!job) {\n return;\n }\n\n job.status = \"running\";\n emit();\n\n window.setTimeout(() => {\n const runningJob = jobs.get(id);\n\n if (!runningJob) {\n return;\n }\n\n runningJob.status = \"completed\";\n emit();\n\n window.setTimeout(() => {\n jobs.delete(id);\n emit();\n }, 900);\n }, durationMs);\n });\n\n return id;\n },\n getJobs() {\n return Array.from(jobs.values());\n },\n subscribe(listener) {\n listeners.add(listener);\n listener(Array.from(jobs.values()));\n\n return () => {\n listeners.delete(listener);\n };\n }\n };\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 buildRuntimeBundleFromSnapshot,\n buildRuntimeSceneFromSnapshot,\n serializeRuntimeScene,\n type WebHammerEngineBundle\n} from \"@ggez/runtime-build\";\nimport {\n type WebHammerEngineScene,\n type WebHammerExportGeometry,\n type WebHammerExportGeometryLod,\n type WebHammerExportModelLod,\n type WebHammerExportMaterial\n} from \"@ggez/runtime-format\";\nimport { MeshBVH } from \"three-mesh-bvh\";\nimport {\n Box3,\n BoxGeometry,\n BufferGeometry,\n ConeGeometry,\n CylinderGeometry,\n Euler,\n Float32BufferAttribute,\n Group,\n Mesh,\n MeshStandardMaterial,\n Object3D,\n Quaternion,\n RepeatWrapping,\n Scene,\n SphereGeometry,\n SRGBColorSpace,\n TextureLoader,\n Vector3\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\";\n\nexport type WorkerExportKind = \"whmap-load\" | \"whmap-save\" | \"engine-export\" | \"gltf-export\" | \"ai-model-generate\";\n\nexport type WorkerRequest =\n | {\n id: string;\n kind: \"whmap-save\";\n snapshot: SceneDocumentSnapshot;\n }\n | {\n id: string;\n kind: \"whmap-load\";\n text: string;\n }\n | {\n id: string;\n kind: \"engine-export\" | \"gltf-export\";\n snapshot: SceneDocumentSnapshot;\n }\n | {\n id: string;\n kind: \"ai-model-generate\";\n prompt: string;\n };\n\nexport type WorkerResponse =\n | {\n id: string;\n kind: WorkerExportKind;\n ok: true;\n payload: string | SceneDocumentSnapshot | WebHammerEngineBundle;\n }\n | {\n id: string;\n kind: WorkerExportKind;\n ok: false;\n error: string;\n };\n\nconst gltfLoader = new GLTFLoader();\nconst gltfExporter = new GLTFExporter();\nconst mtlLoader = new MTLLoader();\nconst modelTextureLoader = new TextureLoader();\n\nexport async function executeWorkerRequest(request: WorkerRequest): Promise<WorkerResponse> {\n try {\n if (request.kind === \"whmap-save\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: serializeWhmap(request.snapshot)\n };\n }\n\n if (request.kind === \"whmap-load\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: parseWhmap(request.text)\n };\n }\n\n if (request.kind === \"engine-export\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: await exportEngineBundle(request.snapshot)\n };\n }\n\n if (request.kind === \"ai-model-generate\") {\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: await generateAiModel(request.prompt)\n };\n }\n\n return {\n id: request.id,\n kind: request.kind,\n ok: true,\n payload: await serializeGltfScene(request.snapshot)\n };\n } catch (error) {\n return {\n id: request.id,\n kind: request.kind,\n ok: false,\n error: error instanceof Error ? error.message : \"Unknown worker error.\"\n };\n }\n}\n\nasync function generateAiModel(prompt: string): Promise<string> {\n const response = await fetch(new URL(\"/api/ai/models\", self.location.origin), {\n body: JSON.stringify({ prompt }),\n headers: {\n \"Content-Type\": \"application/json\"\n },\n method: \"POST\"\n });\n\n const payload = await response.text();\n\n if (!response.ok) {\n try {\n const parsed = JSON.parse(payload) as { error?: string };\n throw new Error(parsed.error ?? \"Failed to generate AI model.\");\n } catch {\n throw new Error(payload || \"Failed to generate AI model.\");\n }\n }\n\n return payload;\n}\n\nexport function serializeWhmap(snapshot: SceneDocumentSnapshot): string {\n return JSON.stringify(\n {\n format: \"whmap\",\n version: 1,\n scene: snapshot\n },\n null,\n 2\n );\n}\n\nexport function parseWhmap(text: string): SceneDocumentSnapshot {\n const parsed = JSON.parse(text) as {\n format?: string;\n scene?: SceneDocumentSnapshot;\n version?: number;\n };\n\n if (parsed.format !== \"whmap\" || !parsed.scene) {\n throw new Error(\"Invalid .whmap file.\");\n }\n\n return parsed.scene;\n}\n\nexport async function serializeEngineScene(snapshot: SceneDocumentSnapshot): Promise<string> {\n return serializeRuntimeScene(snapshot);\n}\n\nexport async function exportEngineBundle(snapshot: SceneDocumentSnapshot): Promise<WebHammerEngineBundle> {\n return buildRuntimeBundleFromSnapshot(snapshot);\n}\n\nasync function buildEngineScene(snapshot: SceneDocumentSnapshot): Promise<WebHammerEngineScene> {\n return buildRuntimeSceneFromSnapshot(snapshot);\n}\n\nexport async function serializeGltfScene(snapshot: SceneDocumentSnapshot): Promise<string> {\n const materialsById = new Map(snapshot.materials.map((material) => [material.id, material]));\n const assetsById = new Map(snapshot.assets.map((asset) => [asset.id, asset]));\n const exportedNodes: Array<{\n id: string;\n mesh?: {\n name: string;\n primitives: Array<{\n indices: number[];\n material: WebHammerExportMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n }>;\n };\n meshKey?: string;\n name: string;\n parentId?: string;\n rotation?: [number, number, number, number];\n scale: [number, number, number];\n translation: [number, number, number];\n }> = [];\n\n for (const node of snapshot.nodes) {\n if (isGroupNode(node)) {\n exportedNodes.push({\n id: node.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(node.transform.rotation),\n scale: [node.transform.scale.x, node.transform.scale.y, node.transform.scale.z],\n translation: [node.transform.position.x, node.transform.position.y, node.transform.position.z]\n });\n continue;\n }\n\n if (isBrushNode(node) || isMeshNode(node) || isPrimitiveNode(node)) {\n const geometry = await buildExportGeometry(node, materialsById);\n\n if (geometry.primitives.length === 0) {\n continue;\n }\n\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: node.name,\n primitives: geometry.primitives\n },\n meshKey: node.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(node.transform.rotation),\n scale: [node.transform.scale.x, node.transform.scale.y, node.transform.scale.z],\n translation: [node.transform.position.x, node.transform.position.y, node.transform.position.z]\n });\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 const instanceTransform = sanitizeInstanceTransform(node.transform);\n\n if (isModelNode(sourceNode)) {\n const previewColor = assetsById.get(sourceNode.data.assetId)?.metadata.previewColor;\n const primitive = createCylinderPrimitive();\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: sourceNode.name,\n primitives: [\n {\n indices: primitive.indices,\n material: await resolveExportMaterial({\n color: typeof previewColor === \"string\" ? previewColor : \"#7f8ea3\",\n id: `material:model:${sourceNode.id}`,\n metalness: 0.1,\n name: `${sourceNode.name} Material`,\n roughness: 0.55\n }),\n normals: computePrimitiveNormals(primitive.positions, primitive.indices),\n positions: primitive.positions,\n uvs: computeCylinderUvs(primitive.positions)\n }\n ]\n },\n meshKey: sourceNode.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(instanceTransform.rotation),\n scale: [instanceTransform.scale.x, instanceTransform.scale.y, instanceTransform.scale.z],\n translation: [instanceTransform.position.x, instanceTransform.position.y, instanceTransform.position.z]\n });\n continue;\n }\n\n const geometry = await buildExportGeometry(sourceNode, materialsById);\n\n if (geometry.primitives.length === 0) {\n continue;\n }\n\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: sourceNode.name,\n primitives: geometry.primitives\n },\n meshKey: sourceNode.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(instanceTransform.rotation),\n scale: [instanceTransform.scale.x, instanceTransform.scale.y, instanceTransform.scale.z],\n translation: [instanceTransform.position.x, instanceTransform.position.y, instanceTransform.position.z]\n });\n continue;\n }\n\n if (isModelNode(node)) {\n const previewColor = assetsById.get(node.data.assetId)?.metadata.previewColor;\n const primitive = createCylinderPrimitive();\n exportedNodes.push({\n id: node.id,\n mesh: {\n name: node.name,\n primitives: [\n {\n indices: primitive.indices,\n material: await resolveExportMaterial({\n color: typeof previewColor === \"string\" ? previewColor : \"#7f8ea3\",\n id: `material:model:${node.id}`,\n metalness: 0.1,\n name: `${node.name} Material`,\n roughness: 0.55\n }),\n normals: computePrimitiveNormals(primitive.positions, primitive.indices),\n positions: primitive.positions,\n uvs: computeCylinderUvs(primitive.positions)\n }\n ]\n },\n meshKey: node.id,\n name: node.name,\n parentId: node.parentId,\n rotation: toQuaternion(node.transform.rotation),\n scale: [node.transform.scale.x, node.transform.scale.y, node.transform.scale.z],\n translation: [node.transform.position.x, node.transform.position.y, node.transform.position.z]\n });\n }\n }\n\n return buildGltfDocument(exportedNodes);\n}\n\nasync function buildGltfDocument(\n exportedNodes: Array<{\n id: string;\n mesh?: {\n name: string;\n primitives: Array<{\n indices: number[];\n material: WebHammerExportMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n }>;\n };\n meshKey?: string;\n name: string;\n parentId?: string;\n rotation?: [number, number, number, number];\n scale: [number, number, number];\n translation: [number, number, number];\n }>\n): Promise<string> {\n const nodes: Array<Record<string, unknown>> = [];\n const gltfMeshes: Array<Record<string, unknown>> = [];\n const materials: Array<Record<string, unknown>> = [];\n const textures: Array<Record<string, unknown>> = [];\n const images: Array<Record<string, unknown>> = [];\n const samplers: Array<Record<string, unknown>> = [\n {\n magFilter: 9729,\n minFilter: 9987,\n wrapS: 10497,\n wrapT: 10497\n }\n ];\n const accessors: Array<Record<string, unknown>> = [];\n const bufferViews: Array<Record<string, unknown>> = [];\n const chunks: Uint8Array[] = [];\n const imageIndexByUri = new Map<string, number>();\n const textureIndexByUri = new Map<string, number>();\n const materialIndexById = new Map<string, number>();\n const meshIndexByKey = new Map<string, number>();\n\n const pushBuffer = (bytes: Uint8Array, target?: number) => {\n const padding = (4 - (bytes.byteLength % 4)) % 4;\n const padded = new Uint8Array(bytes.byteLength + padding);\n padded.set(bytes);\n const byteOffset = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n chunks.push(padded);\n bufferViews.push({\n buffer: 0,\n byteLength: bytes.byteLength,\n byteOffset,\n ...(target ? { target } : {})\n });\n return bufferViews.length - 1;\n };\n\n const nodeIndexById = new Map<string, number>();\n\n for (const exportedNode of exportedNodes) {\n let meshIndex: number | undefined;\n\n if (exportedNode.mesh) {\n const meshKey = exportedNode.meshKey ?? exportedNode.id;\n const cachedMeshIndex = meshIndexByKey.get(meshKey);\n\n if (cachedMeshIndex !== undefined) {\n meshIndex = cachedMeshIndex;\n } else {\n const gltfPrimitives: Array<Record<string, unknown>> = [];\n\n for (const primitive of exportedNode.mesh.primitives) {\n const positions = new Float32Array(primitive.positions);\n const normals = new Float32Array(primitive.normals);\n const uvs = new Float32Array(primitive.uvs);\n const indices = new Uint32Array(primitive.indices);\n const positionView = pushBuffer(new Uint8Array(positions.buffer.slice(0)), 34962);\n const normalView = pushBuffer(new Uint8Array(normals.buffer.slice(0)), 34962);\n const uvView = pushBuffer(new Uint8Array(uvs.buffer.slice(0)), 34962);\n const indexView = pushBuffer(new Uint8Array(indices.buffer.slice(0)), 34963);\n\n const bounds = computePositionBounds(primitive.positions);\n accessors.push({\n bufferView: positionView,\n componentType: 5126,\n count: positions.length / 3,\n max: bounds.max,\n min: bounds.min,\n type: \"VEC3\"\n });\n const positionAccessor = accessors.length - 1;\n\n accessors.push({\n bufferView: normalView,\n componentType: 5126,\n count: normals.length / 3,\n type: \"VEC3\"\n });\n const normalAccessor = accessors.length - 1;\n\n accessors.push({\n bufferView: uvView,\n componentType: 5126,\n count: uvs.length / 2,\n type: \"VEC2\"\n });\n const uvAccessor = accessors.length - 1;\n\n accessors.push({\n bufferView: indexView,\n componentType: 5125,\n count: indices.length,\n type: \"SCALAR\"\n });\n const indexAccessor = accessors.length - 1;\n\n const materialIndex = await ensureGltfMaterial(\n primitive.material,\n materials,\n textures,\n images,\n imageIndexByUri,\n textureIndexByUri,\n materialIndexById\n );\n\n gltfPrimitives.push({\n attributes: {\n NORMAL: normalAccessor,\n POSITION: positionAccessor,\n TEXCOORD_0: uvAccessor\n },\n indices: indexAccessor,\n material: materialIndex\n });\n }\n\n gltfMeshes.push({\n name: exportedNode.mesh.name,\n primitives: gltfPrimitives\n });\n meshIndex = gltfMeshes.length - 1;\n meshIndexByKey.set(meshKey, meshIndex);\n }\n }\n\n nodes.push({\n ...(meshIndex !== undefined ? { mesh: meshIndex } : {}),\n name: exportedNode.name,\n ...(exportedNode.rotation ? { rotation: exportedNode.rotation } : {}),\n scale: exportedNode.scale,\n translation: exportedNode.translation\n });\n nodeIndexById.set(exportedNode.id, nodes.length - 1);\n }\n\n const rootNodeIndices: number[] = [];\n\n exportedNodes.forEach((exportedNode, index) => {\n const parentIndex =\n exportedNode.parentId\n ? nodeIndexById.get(exportedNode.parentId)\n : undefined;\n\n if (parentIndex === undefined) {\n rootNodeIndices.push(index);\n return;\n }\n\n const parent = nodes[parentIndex] as { children?: number[] };\n parent.children = [...(parent.children ?? []), index];\n });\n\n const totalByteLength = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);\n const merged = new Uint8Array(totalByteLength);\n let cursor = 0;\n chunks.forEach((chunk) => {\n merged.set(chunk, cursor);\n cursor += chunk.byteLength;\n });\n\n const gltf = {\n accessors,\n asset: {\n generator: \"web-hammer\",\n version: \"2.0\"\n },\n bufferViews,\n buffers: [\n {\n byteLength: merged.byteLength,\n uri: `data:application/octet-stream;base64,${toBase64(merged)}`\n }\n ],\n images,\n materials,\n meshes: gltfMeshes,\n nodes,\n samplers,\n scene: 0,\n scenes: [\n {\n nodes: rootNodeIndices\n }\n ],\n textures\n };\n\n return JSON.stringify(gltf, null, 2);\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 resolveExportMaterial({\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, {\n indices: number[];\n material: WebHammerExportMaterial;\n normals: number[];\n positions: number[];\n uvs: number[];\n }>();\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 resolveExportMaterial(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 resolveExportMaterial(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: WebHammerExportGeometry,\n settings: SceneDocumentSnapshot[\"settings\"][\"world\"][\"lod\"]\n): Promise<WebHammerExportGeometryLod[] | 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: WebHammerExportGeometryLod[] = [];\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?: WebHammerExportModelLod[] }> {\n if (!asset?.path) {\n return { assets: [], lods: undefined };\n }\n\n const source = await loadModelSceneForLodBake(asset);\n const bakedLevels: Array<{ asset: Asset; level: WebHammerExportModelLod[\"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) => {\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) => {\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) => {\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) =>\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 child.material = child.material instanceof MeshStandardMaterial\n ? strip(child.material)\n : new MeshStandardMaterial({\n color: \"color\" in child.material ? child.material.color : \"#7f8ea3\",\n metalness: \"metalness\" in child.material && typeof child.material.metalness === \"number\" ? child.material.metalness : 0.1,\n roughness: \"roughness\" in child.material && typeof child.material.roughness === \"number\" ? child.material.roughness : 0.8\n });\n });\n\n return object;\n}\n\nfunction createGeneratedModelLodAsset(\n asset: Asset,\n name: string,\n nodeId: string,\n level: WebHammerExportModelLod[\"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: WebHammerExportGeometry, ratio: number): WebHammerExportGeometry | undefined {\n const primitives = geometry.primitives\n .map((primitive) => simplifyExportPrimitive(primitive, ratio))\n .filter((primitive): primitive is WebHammerExportGeometry[\"primitives\"][number] => primitive !== undefined);\n\n return primitives.length ? { primitives } : undefined;\n}\n\nfunction simplifyExportPrimitive(\n primitive: WebHammerExportGeometry[\"primitives\"][number],\n ratio: number\n): WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"primitives\"][number],\n ratio: number,\n bounds: Box3\n): WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"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: WebHammerExportGeometry[\"primitives\"][number],\n bounds: Box3,\n size: Vector3,\n resolution: number\n): WebHammerExportGeometry[\"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(\n cluster.positionX / cluster.count,\n cluster.positionY / cluster.count,\n cluster.positionZ / cluster.count\n );\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 resolveExportMaterial(material?: Material) {\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 } satisfies WebHammerExportMaterial;\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\nasync function ensureGltfMaterial(\n material: WebHammerExportMaterial,\n materials: Array<Record<string, unknown>>,\n textures: Array<Record<string, unknown>>,\n images: Array<Record<string, unknown>>,\n imageIndexByUri: Map<string, number>,\n textureIndexByUri: Map<string, number>,\n materialIndexById: Map<string, number>\n) {\n const existing = materialIndexById.get(material.id);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const baseColorTextureIndex = material.baseColorTexture\n ? ensureGltfTexture(material.baseColorTexture, textures, images, imageIndexByUri, textureIndexByUri)\n : undefined;\n const normalTextureIndex = material.normalTexture\n ? ensureGltfTexture(material.normalTexture, textures, images, imageIndexByUri, textureIndexByUri)\n : undefined;\n const metallicRoughnessTextureIndex = material.metallicRoughnessTexture\n ? ensureGltfTexture(material.metallicRoughnessTexture, textures, images, imageIndexByUri, textureIndexByUri)\n : undefined;\n\n materials.push({\n name: material.name,\n normalTexture: normalTextureIndex !== undefined ? { index: normalTextureIndex } : undefined,\n pbrMetallicRoughness: {\n ...(baseColorTextureIndex !== undefined ? { baseColorTexture: { index: baseColorTextureIndex } } : {}),\n ...(metallicRoughnessTextureIndex !== undefined\n ? { metallicRoughnessTexture: { index: metallicRoughnessTextureIndex } }\n : {}),\n baseColorFactor: hexToRgba(material.color),\n metallicFactor: material.metallicFactor,\n roughnessFactor: material.roughnessFactor\n }\n });\n\n const index = materials.length - 1;\n materialIndexById.set(material.id, index);\n return index;\n}\n\nfunction ensureGltfTexture(\n uri: string,\n textures: Array<Record<string, unknown>>,\n images: Array<Record<string, unknown>>,\n imageIndexByUri: Map<string, number>,\n textureIndexByUri: Map<string, number>\n) {\n const existingTexture = textureIndexByUri.get(uri);\n\n if (existingTexture !== undefined) {\n return existingTexture;\n }\n\n const imageIndex = imageIndexByUri.get(uri) ?? images.length;\n\n if (!imageIndexByUri.has(uri)) {\n images.push({ uri });\n imageIndexByUri.set(uri, imageIndex);\n }\n\n textures.push({ sampler: 0, source: imageIndex });\n const textureIndex = textures.length - 1;\n textureIndexByUri.set(uri, textureIndex);\n return textureIndex;\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 computePrimitiveNormals(positions: number[], indices: number[]) {\n const normals = new Array<number>(positions.length).fill(0);\n\n for (let index = 0; index < indices.length; index += 3) {\n const a = indices[index] * 3;\n const b = indices[index + 1] * 3;\n const c = indices[index + 2] * 3;\n const normal = normalizeVec3(\n crossVec3(\n vec3(positions[b] - positions[a], positions[b + 1] - positions[a + 1], positions[b + 2] - positions[a + 2]),\n vec3(positions[c] - positions[a], positions[c + 1] - positions[a + 1], positions[c + 2] - positions[a + 2])\n )\n );\n\n [a, b, c].forEach((offset) => {\n normals[offset] = normal.x;\n normals[offset + 1] = normal.y;\n normals[offset + 2] = normal.z;\n });\n }\n\n return normals;\n}\n\nfunction computeCylinderUvs(positions: number[]) {\n const uvs: number[] = [];\n\n for (let index = 0; index < positions.length; index += 3) {\n const x = positions[index];\n const y = positions[index + 1];\n const z = positions[index + 2];\n const u = (Math.atan2(z, x) / (Math.PI * 2) + 1) % 1;\n const v = y > 0 ? 1 : 0;\n uvs.push(u, v);\n }\n\n return uvs;\n}\n\nfunction clamp01(value: number) {\n return Math.max(0, Math.min(1, value));\n}\n\nfunction toQuaternion(rotation: Vec3): [number, number, number, number] {\n const quaternion = new Quaternion().setFromEuler(new Euler(rotation.x, rotation.y, rotation.z, \"XYZ\"));\n return [quaternion.x, quaternion.y, quaternion.z, quaternion.w];\n}\n\nfunction createCylinderPrimitive() {\n const radius = 0.65;\n const halfHeight = 1.1;\n const segments = 12;\n const positions: number[] = [];\n const indices: number[] = [];\n\n for (let index = 0; index < segments; index += 1) {\n const angle = (index / segments) * Math.PI * 2;\n const x = Math.cos(angle) * radius;\n const z = Math.sin(angle) * radius;\n positions.push(x, -halfHeight, z, x, halfHeight, z);\n }\n\n for (let index = 0; index < segments; index += 1) {\n const next = (index + 1) % segments;\n const bottom = index * 2;\n const top = bottom + 1;\n const nextBottom = next * 2;\n const nextTop = nextBottom + 1;\n\n indices.push(bottom, nextBottom, top, top, nextBottom, nextTop);\n }\n\n return { indices, positions };\n}\n\nfunction computePositionBounds(positions: number[]) {\n const min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];\n const max = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];\n\n for (let index = 0; index < positions.length; index += 3) {\n min[0] = Math.min(min[0], positions[index]);\n min[1] = Math.min(min[1], positions[index + 1]);\n min[2] = Math.min(min[2], positions[index + 2]);\n max[0] = Math.max(max[0], positions[index]);\n max[1] = Math.max(max[1], positions[index + 1]);\n max[2] = Math.max(max[2], positions[index + 2]);\n }\n\n return { max, min };\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\nfunction hexToRgba(hex: string): [number, number, number, number] {\n const normalized = hex.replace(\"#\", \"\");\n const parsed = Number.parseInt(normalized, 16);\n return [((parsed >> 16) & 255) / 255, ((parsed >> 8) & 255) / 255, (parsed & 255) / 255, 1];\n}\n","export const workerIds = [\"geometryWorker\", \"meshWorker\", \"navWorker\", \"exportWorker\"] as const;\n\nexport type WorkerId = (typeof workerIds)[number];\n\nexport type WorkerTask =\n | { worker: \"geometryWorker\"; task: \"brush-rebuild\" | \"clip\" | \"triangulation\" }\n | { worker: \"meshWorker\"; task: \"triangulation\" | \"loop-cut\" | \"bevel\" }\n | { worker: \"navWorker\"; task: \"navmesh\" }\n | { worker: \"exportWorker\"; task: \"ai-model-generate\" | \"engine-format\" | \"gltf\" | \"usd\" | \"whmap-load\" | \"whmap-save\" };\n"],"mappings":"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","names":[]}