@hraness/slopcamera 3.3.1 → 3.3.3

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.
@@ -1,3 +0,0 @@
1
- // @bun
2
- import{SlopcameraCodeError,boundedCanonicalJsonSha256,canonicalJson,canonicalJsonSha256,createBoundedJsonSnapshot,createBoundedJsonValueSnapshot,deepFreezeJson,sha256Hex}from"./index-3cxf2c58.js";import{z}from"zod";var unit=z.number().finite().min(0).max(1);var positiveFinite=z.number().finite().min(0).max(1e6);var finiteCoordinate=z.number().finite().min(-1e6).max(1e6);var color=z.string().regex(/^#[a-fA-F0-9]{6}$/u);var SpatialMapChannelSchema=z.enum(["rgb","rgba","r","g","b","a","rg","orm","xy-normal"]);var SpatialMapColorSpaceSchema=z.enum(["srgb","linear"]);var SpatialUvTransformSchema=z.strictObject({offset:z.tuple([finiteCoordinate,finiteCoordinate]),rotation:z.number().finite().min(-Math.PI).max(Math.PI),scale:z.tuple([positiveFinite,positiveFinite])});var assetId=z.string().min(7).max(128).regex(/^asset_[a-zA-Z0-9][a-zA-Z0-9_-]*$/u);var SpatialPbrMapSchema=z.strictObject({assetId,channel:SpatialMapChannelSchema,colorSpace:SpatialMapColorSpaceSchema,uvTransform:SpatialUvTransformSchema.optional()});var SpatialPbrEmissiveSchema=z.strictObject({color,intensity:z.number().finite().min(0).max(1e5),map:SpatialPbrMapSchema.optional()});var SpatialPbrClearcoatSchema=z.strictObject({factor:unit,roughness:unit,map:SpatialPbrMapSchema.optional(),roughnessMap:SpatialPbrMapSchema.optional(),normalMap:SpatialPbrMapSchema.optional(),normalScale:z.number().finite().min(-16).max(16).optional()});var SpatialPbrTransmissionSchema=z.strictObject({factor:unit,map:SpatialPbrMapSchema.optional()});var SpatialPbrSheenSchema=z.strictObject({color,roughness:unit,colorMap:SpatialPbrMapSchema.optional(),roughnessMap:SpatialPbrMapSchema.optional()});var SpatialPbrAnisotropySchema=z.strictObject({strength:z.number().finite().min(-1).max(1),rotation:z.number().finite().min(0).max(2*Math.PI),map:SpatialPbrMapSchema.optional()});var SpatialPbrMaterialSchema=z.strictObject({kind:z.literal("pbr"),color,opacity:unit,roughness:unit,metalness:unit,baseColorMap:SpatialPbrMapSchema.optional(),normalMap:SpatialPbrMapSchema.optional(),normalScale:z.number().finite().min(-16).max(16).optional(),ormMap:SpatialPbrMapSchema.optional(),roughnessMap:SpatialPbrMapSchema.optional(),metalnessMap:SpatialPbrMapSchema.optional(),aoMap:SpatialPbrMapSchema.optional(),aoMapIntensity:unit.optional(),emissive:SpatialPbrEmissiveSchema.optional(),heightMap:SpatialPbrMapSchema.optional(),heightScale:z.number().finite().min(-10).max(10).optional(),clearcoat:SpatialPbrClearcoatSchema.optional(),transmission:SpatialPbrTransmissionSchema.optional(),sheen:SpatialPbrSheenSchema.optional(),anisotropy:SpatialPbrAnisotropySchema.optional(),ior:z.number().finite().min(1).max(5).optional(),alphaMode:z.enum(["OPAQUE","MASK","BLEND"]).optional(),alphaCutoff:unit.optional(),doubleSided:z.boolean().optional()}).superRefine((material,context)=>{const hasOrm=material.ormMap!==undefined;const hasSeparate=material.roughnessMap!==undefined||material.metalnessMap!==undefined||material.aoMap!==undefined;if(hasOrm&&hasSeparate){context.addIssue({code:"custom",message:"PBR materials must use either an ORM map or separate roughness/metalness/AO maps, never both."})}if(material.baseColorMap!==undefined&&!["rgb","rgba"].includes(material.baseColorMap.channel)){context.addIssue({code:"custom",path:["baseColorMap","channel"],message:"Base-color maps must use rgb or rgba channels."})}if(material.baseColorMap!==undefined&&material.baseColorMap.colorSpace!=="srgb"){context.addIssue({code:"custom",path:["baseColorMap","colorSpace"],message:"Base-color maps must be sRGB."})}if(material.normalMap!==undefined&&material.normalMap.channel!=="xy-normal"){context.addIssue({code:"custom",path:["normalMap","channel"],message:"Normal maps must use xy-normal channel semantics."})}if(material.normalMap!==undefined&&material.normalMap.colorSpace!=="linear"){context.addIssue({code:"custom",path:["normalMap","colorSpace"],message:"Normal maps must be linear."})}if(material.ormMap!==undefined&&material.ormMap.channel!=="orm"){context.addIssue({code:"custom",path:["ormMap","channel"],message:"ORM maps must use orm channel semantics."})}if(material.ormMap!==undefined&&material.ormMap.colorSpace!=="linear"){context.addIssue({code:"custom",path:["ormMap","colorSpace"],message:"ORM maps must be linear."})}if(material.heightMap!==undefined&&material.heightMap.channel!=="r"){context.addIssue({code:"custom",path:["heightMap","channel"],message:"Height maps must use single red channel."})}if(material.heightMap!==undefined&&material.heightMap.colorSpace!=="linear"){context.addIssue({code:"custom",path:["heightMap","colorSpace"],message:"Height maps must be linear."})}if(material.emissive?.map!==undefined&&material.emissive.map.colorSpace!=="srgb"){context.addIssue({code:"custom",path:["emissive","map","colorSpace"],message:"Emissive maps must be sRGB."})}for(const[name,map,channels]of[["roughnessMap",material.roughnessMap,["g"]],["metalnessMap",material.metalnessMap,["b"]],["aoMap",material.aoMap,["r"]],["clearcoat.map",material.clearcoat?.map,["r"]],["clearcoat.roughnessMap",material.clearcoat?.roughnessMap,["g"]],["transmission.map",material.transmission?.map,["r"]],["sheen.roughnessMap",material.sheen?.roughnessMap,["a"]]]){if(map!==undefined&&map.colorSpace!=="linear")context.addIssue({code:"custom",path:name.split("."),message:`${name} must be linear.`});if(map!==undefined&&!channels.includes(map.channel))context.addIssue({code:"custom",path:[...name.split("."),"channel"],message:`${name} has unsupported channel semantics.`})}for(const[name,map]of[["clearcoat.normalMap",material.clearcoat?.normalMap],["anisotropy.map",material.anisotropy?.map]]){if(map!==undefined&&map.colorSpace!=="linear")context.addIssue({code:"custom",path:name.split("."),message:`${name} must be linear.`})}if(material.clearcoat?.normalMap!==undefined&&material.clearcoat.normalMap.channel!=="xy-normal")context.addIssue({code:"custom",path:["clearcoat","normalMap","channel"],message:"Clearcoat normal maps must use xy-normal semantics."});if(material.emissive?.map!==undefined&&!["rgb","rgba"].includes(material.emissive.map.channel))context.addIssue({code:"custom",path:["emissive","map","channel"],message:"Emissive maps must use rgb or rgba channels."});if(material.sheen?.colorMap!==undefined&&(material.sheen.colorMap.colorSpace!=="srgb"||!["rgb","rgba"].includes(material.sheen.colorMap.channel)))context.addIssue({code:"custom",path:["sheen","colorMap"],message:"Sheen color maps must use sRGB rgb or rgba semantics."});if(material.anisotropy?.map!==undefined&&material.anisotropy.map.channel!=="rgb")context.addIssue({code:"custom",path:["anisotropy","map","channel"],message:"Anisotropy maps must use RGB direction-and-strength semantics."});if(material.normalScale!==undefined&&material.normalMap===undefined)context.addIssue({code:"custom",message:"normalScale requires a normalMap."});if(material.heightScale!==undefined!==(material.heightMap!==undefined))context.addIssue({code:"custom",message:"heightScale and heightMap must be declared together."});if(material.clearcoat?.normalScale!==undefined&&material.clearcoat.normalMap===undefined)context.addIssue({code:"custom",message:"Clearcoat normalScale requires a clearcoat normalMap."});if(material.aoMapIntensity!==undefined&&material.aoMap===undefined&&material.ormMap===undefined)context.addIssue({code:"custom",message:"aoMapIntensity requires an AO or ORM map."});if(material.alphaCutoff!==undefined&&material.alphaMode!=="MASK"){context.addIssue({code:"custom",message:"alphaCutoff is only applicable to MASK alpha mode."})}});function pbrMaterialMapAssetIds(material){const ids=new Set;const collect=(map)=>{if(map!==null&&typeof map==="object"&&map!==undefined&&"assetId"in map&&typeof map.assetId==="string")ids.add(map.assetId)};const m=material;collect(m.baseColorMap);collect(m.normalMap);collect(m.ormMap);collect(m.roughnessMap);collect(m.metalnessMap);collect(m.aoMap);collect(m.heightMap);collect(m.emissive?.map);collect(m.clearcoat?.map);collect(m.clearcoat?.roughnessMap);collect(m.clearcoat?.normalMap);collect(m.transmission?.map);collect(m.sheen?.colorMap);collect(m.sheen?.roughnessMap);collect(m.anisotropy?.map);return Object.freeze([...ids])}var SpatialDerivationMethodSchema=z.enum(["sobel-normal-from-height","average-luminance-roughness","luminance-height"]);var SpatialDerivationCandidateSchema=z.strictObject({method:SpatialDerivationMethodSchema,sourceAssetId:assetId,outputChannel:SpatialMapChannelSchema,outputColorSpace:SpatialMapColorSpaceSchema,provenance:z.literal("derived-candidate"),description:z.string().min(1).max(1024)});function pbrDerivationCandidates(material){const candidates=[];if(material.heightMap!==undefined&&material.normalMap===undefined){candidates.push({method:"sobel-normal-from-height",sourceAssetId:material.heightMap.assetId,outputChannel:"xy-normal",outputColorSpace:"linear",provenance:"derived-candidate",description:"Sobel-filter tangent-space normal derived from the authored height map. Does not equal a surface scan."})}if(material.baseColorMap!==undefined&&material.roughnessMap===undefined&&material.ormMap===undefined){candidates.push({method:"average-luminance-roughness",sourceAssetId:material.baseColorMap.assetId,outputChannel:"r",outputColorSpace:"linear",provenance:"derived-candidate",description:"Inverted luminance roughness derived from the base-color map. A heuristic approximation, not a measured surface."})}if(material.baseColorMap!==undefined&&material.heightMap===undefined){candidates.push({method:"luminance-height",sourceAssetId:material.baseColorMap.assetId,outputChannel:"r",outputColorSpace:"linear",provenance:"derived-candidate",description:"Luminance-based height derived from the base-color map. A visual approximation, not a measured displacement."})}return deepFreezeJson(candidates)}var SpatialFogSchema=z.discriminatedUnion("kind",[z.strictObject({kind:z.literal("linear"),color,near:positiveFinite,far:positiveFinite}).refine((fog)=>fog.far>fog.near,"Fog far must exceed near."),z.strictObject({kind:z.literal("height"),color,density:z.number().finite().min(0).max(100),heightFalloff:z.number().finite().min(0).max(100),baseHeight:finiteCoordinate})]);var SpatialLightingRigTypeSchema=z.enum(["portrait","product","moonlight","golden-hour","neon-noir","interior-window","volumetric-stage"]);var IDENTITY_ROTATION=[0,0,0,1];function localMinusZTowardOrigin(position){const length=Math.hypot(...position);if(length===0)return IDENTITY_ROTATION;const to=[-position[0]/length,-position[1]/length,-position[2]/length];const dot=-to[2];if(dot<-0.999999)return[0,1,0,0];const scale=Math.sqrt(2*(1+dot));return[to[1]/scale,-to[0]/scale,0,scale/2]}function rigEntity(light){const rotation=light.light==="ambient"||light.light==="point"?light.rotation:localMinusZTowardOrigin(light.position);return{entityId:light.entityId,kind:"light",name:light.name,parentId:null,transform:{position:light.position,rotation,scale:[1,1,1]},placement:{kind:"world"},origin:{kind:"authored"},visible:true,light:light.light,color:light.color,intensity:light.intensity,...light.spot===undefined?{}:{spot:light.spot},...light.shadow===undefined?{}:{shadow:light.shadow}}}var RIGS={portrait:{description:"Classic three-point portrait: warm key at 45\xB0, cool fill opposite, rim backlight. Soft ambient fill.",lights:[{entityId:"entity_rig_key",name:"Key",light:"directional",color:"#fff5e6",intensity:3.2,position:[3,4,3],rotation:IDENTITY_ROTATION,shadow:true},{entityId:"entity_rig_fill",name:"Fill",light:"directional",color:"#ccd8ff",intensity:1.2,position:[-3,2,3],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_rim",name:"Rim",light:"directional",color:"#ffffff",intensity:2,position:[0,3,-4],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_ambient",name:"Ambient",light:"ambient",color:"#e8ecf0",intensity:0.4,position:[0,0,0],rotation:IDENTITY_ROTATION}]},product:{description:"Even product lighting: overhead softbox, two symmetric side fills, warm ambient. Minimal shadows for clean presentation.",lights:[{entityId:"entity_rig_top",name:"Top",light:"directional",color:"#ffffff",intensity:3,position:[0,5,0],rotation:IDENTITY_ROTATION,shadow:true},{entityId:"entity_rig_left",name:"Left fill",light:"directional",color:"#f5f5ff",intensity:1.5,position:[-4,2,3],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_right",name:"Right fill",light:"directional",color:"#f5f5ff",intensity:1.5,position:[4,2,3],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_ambient",name:"Ambient",light:"ambient",color:"#f0ece8",intensity:0.8,position:[0,0,0],rotation:IDENTITY_ROTATION}]},moonlight:{description:"Cool blue directional moonlight with deep ambient. High contrast, strong shadows.",lights:[{entityId:"entity_rig_moon",name:"Moon",light:"directional",color:"#b4c8e8",intensity:2,position:[-2,8,-3],rotation:IDENTITY_ROTATION,shadow:true},{entityId:"entity_rig_ambient",name:"Ambient",light:"ambient",color:"#1a2040",intensity:0.15,position:[0,0,0],rotation:IDENTITY_ROTATION}]},"golden-hour":{description:"Warm low-angle sunlight with long shadows. Complementary cool sky ambient.",lights:[{entityId:"entity_rig_sun",name:"Sun",light:"directional",color:"#ffb347",intensity:4,position:[6,1.5,3],rotation:IDENTITY_ROTATION,shadow:true},{entityId:"entity_rig_sky",name:"Sky ambient",light:"ambient",color:"#8cb4d8",intensity:0.5,position:[0,0,0],rotation:IDENTITY_ROTATION}]},"neon-noir":{description:"High-contrast colored point lights simulating neon signage. Deep shadows, no ambient fill.",lights:[{entityId:"entity_rig_neon_pink",name:"Neon pink",light:"point",color:"#ff1493",intensity:8,position:[-3,2,1],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_neon_cyan",name:"Neon cyan",light:"point",color:"#00e5ff",intensity:6,position:[3,1,-2],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_neon_accent",name:"Neon accent",light:"point",color:"#7b68ee",intensity:4,position:[0,4,0],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_ambient",name:"Ambient",light:"ambient",color:"#0a0a14",intensity:0.05,position:[0,0,0],rotation:IDENTITY_ROTATION}]},"interior-window":{description:"Daylight from a single window direction. Warm interior ambient fill, exterior-facing key.",lights:[{entityId:"entity_rig_window",name:"Window",light:"directional",color:"#e8f0ff",intensity:3.5,position:[5,3,0],rotation:IDENTITY_ROTATION,shadow:true},{entityId:"entity_rig_bounce",name:"Bounce",light:"directional",color:"#fff0e0",intensity:0.8,position:[-3,1,2],rotation:IDENTITY_ROTATION},{entityId:"entity_rig_ambient",name:"Ambient",light:"ambient",color:"#f5e8d8",intensity:0.35,position:[0,0,0],rotation:IDENTITY_ROTATION}]},"volumetric-stage":{description:"Theatrical spot lights with tight cones and visible falloff. Low ambient for dramatic effect.",lights:[{entityId:"entity_rig_spot_center",name:"Center spot",light:"spot",color:"#ffffff",intensity:12,position:[0,6,0],rotation:IDENTITY_ROTATION,spot:{angle:0.5,penumbra:0.6,distance:20,decay:2},shadow:true},{entityId:"entity_rig_spot_left",name:"Left spot",light:"spot",color:"#ffccaa",intensity:8,position:[-4,5,2],rotation:IDENTITY_ROTATION,spot:{angle:0.4,penumbra:0.5,distance:15,decay:2}},{entityId:"entity_rig_spot_right",name:"Right spot",light:"spot",color:"#aaccff",intensity:8,position:[4,5,2],rotation:IDENTITY_ROTATION,spot:{angle:0.4,penumbra:0.5,distance:15,decay:2}},{entityId:"entity_rig_ambient",name:"Ambient",light:"ambient",color:"#1a1a2e",intensity:0.08,position:[0,0,0],rotation:IDENTITY_ROTATION}]}};function lightingRig(type){const rig=RIGS[type];return deepFreezeJson({description:rig.description,entities:rig.lights.map(rigEntity)})}function lightingRigDescription(type){return RIGS[type].description}var SpatialProbeGeometrySchema=z.enum(["plane","sphere","hero"]);var DEFAULT_PROBE_GEOMETRIES=Object.freeze(["plane","sphere","hero"]);var DEFAULT_PROBE_RIGS=Object.freeze(["product","golden-hour","moonlight"]);var ORIGINAL_MATERIAL_HERO_FIXTURE=deepFreezeJson({assetId:"asset_material_hero_original",manifestSha256:sha256Hex("slopcamera-original-material-hero-v1"),bounds:{min:[-0.8,-1,-0.55],max:[0.8,1,0.55]}});var DEFAULT_CAMERA_DISTANCES=Object.freeze([3,6]);function planMaterialProbeGallery(input){const material=SpatialPbrMaterialSchema.parse(input.material);const geometries=input.geometries??DEFAULT_PROBE_GEOMETRIES;const rigs=input.lightingRigs??DEFAULT_PROBE_RIGS;const distances=input.cameraDistances??DEFAULT_CAMERA_DISTANCES;const heroAsset=input.heroAsset??ORIGINAL_MATERIAL_HERO_FIXTURE;for(const geometry of geometries)SpatialProbeGeometrySchema.parse(geometry);for(const rig of rigs)SpatialLightingRigTypeSchema.parse(rig);for(const distance of distances){if(!Number.isFinite(distance)||distance<=0||distance>1e6){throw new RangeError("Camera distances must be positive finite values.")}}if(geometries.length<1||rigs.length<1||distances.length<1||geometries.length*rigs.length*distances.length>64)throw new RangeError("Material probe gallery requires 1\u201364 bounded cells.");if(geometries.includes("hero")){if(!/^[a-f0-9]{64}$/u.test(heroAsset.manifestSha256))throw new RangeError("Hero probe geometry requires an exact hero asset manifest binding.");for(let axis=0;axis<3;axis++)if(!Number.isFinite(heroAsset.bounds.min[axis])||!Number.isFinite(heroAsset.bounds.max[axis])||heroAsset.bounds.min[axis]>heroAsset.bounds.max[axis])throw new RangeError("Hero probe geometry requires finite ordered bounds.")}const extensions=[];if(material.clearcoat!==undefined)extensions.push("clearcoat");if(material.transmission!==undefined)extensions.push("transmission");if(material.sheen!==undefined)extensions.push("sheen");if(material.anisotropy!==undefined)extensions.push("anisotropy");const extensionNote=extensions.length>0?` Extensions: ${extensions.join(", ")}.`:"";const mapCount=pbrMaterialMapAssetIds(material).length;const description=`Probe gallery: ${geometries.length} geometr${geometries.length===1?"y":"ies"} \xD7 ${rigs.length} rig${rigs.length===1?"":"s"} \xD7 ${distances.length} distance${distances.length===1?"":"s"} = ${geometries.length*rigs.length*distances.length} probe${geometries.length*rigs.length*distances.length===1?"":"s"}. ${mapCount} texture map${mapCount===1?"":"s"} bound.${extensionNote}`;const materialSha256=sha256Hex(canonicalJson({domain:"slopcamera.spatial-material/v1",material}));const cells=geometries.flatMap((geometry)=>rigs.flatMap((lightingRig2)=>distances.map((cameraDistance)=>({cellId:sha256Hex(canonicalJson({domain:"slopcamera.spatial-material-probe-cell/v1",materialSha256,geometry,lightingRig:lightingRig2,cameraDistance,...geometry==="hero"?{heroAsset}:{}})),geometry,lightingRig:lightingRig2,cameraDistance}))));const body={kind:"slopcamera.spatial-material-probe-gallery",schemaVersion:1,materialSha256,material,...geometries.includes("hero")?{heroAsset}:{},geometries:[...geometries],lightingRigs:[...rigs],cameraDistances:[...distances],cells,description};return deepFreezeJson({...body,gallerySha256:sha256Hex(canonicalJson({domain:"slopcamera.spatial-material-probe-gallery/v1",body}))})}function validatePbrMaterial(material,assetLookup,pixelBudget=67108864){const errors=[];let totalPixels=0;let expectedDimensions;const countedAssets=new Set;const validateMap=(map,label)=>{if(map===undefined)return;const asset=assetLookup.get(map.assetId);if(asset===undefined){errors.push(`${label}: references missing asset ${map.assetId}.`);return}if(asset.kind!=="image"){errors.push(`${label}: asset ${map.assetId} is ${asset.kind}, not an image.`);return}if(!Number.isInteger(asset.width)||!Number.isInteger(asset.height)||asset.width<1||asset.height<1){errors.push(`${label}: asset ${map.assetId} has invalid decoded dimensions.`);return}if(expectedDimensions!==undefined&&(asset.width!==expectedDimensions[0]||asset.height!==expectedDimensions[1]))errors.push(`${label}: decoded dimensions do not match the other PBR maps.`);expectedDimensions??=[asset.width,asset.height];if(!countedAssets.has(map.assetId)){countedAssets.add(map.assetId);totalPixels+=asset.width*asset.height;if(totalPixels>pixelBudget)errors.push(`${label}: total decoded pixels (${totalPixels}) exceed budget (${pixelBudget}).`)}};validateMap(material.baseColorMap,"baseColorMap");validateMap(material.normalMap,"normalMap");validateMap(material.ormMap,"ormMap");validateMap(material.roughnessMap,"roughnessMap");validateMap(material.metalnessMap,"metalnessMap");validateMap(material.aoMap,"aoMap");validateMap(material.heightMap,"heightMap");validateMap(material.emissive?.map,"emissive.map");validateMap(material.clearcoat?.map,"clearcoat.map");validateMap(material.clearcoat?.roughnessMap,"clearcoat.roughnessMap");validateMap(material.clearcoat?.normalMap,"clearcoat.normalMap");validateMap(material.transmission?.map,"transmission.map");validateMap(material.sheen?.colorMap,"sheen.colorMap");validateMap(material.sheen?.roughnessMap,"sheen.roughnessMap");validateMap(material.anisotropy?.map,"anisotropy.map");return deepFreezeJson({valid:errors.length===0,errors})}import{z as z2}from"zod";var SPATIAL_SCENE_LIMITS=Object.freeze({sourceBytes:2097152,sourceDepth:32,sourceValues:200000,entities:4096,assets:128,cameras:64,channels:4096,keysPerChannel:4096,durationUs:3600000000,patchOperations:256});var SpatialDigestSchema=z2.string().regex(/^[a-f0-9]{64}$/u);var stableId=(prefix)=>z2.string().min(prefix.length+1).max(128).regex(new RegExp(`^${prefix}[a-zA-Z0-9][a-zA-Z0-9_-]*$`,"u"));var SpatialSceneIdSchema=stableId("scene_");var SpatialEntityIdSchema=stableId("entity_");var SpatialCameraIdSchema=stableId("camera_");var SpatialAssetIdSchema=stableId("asset_");var SpatialGeneratorIdSchema=stableId("generator_");var SpatialChannelIdSchema=stableId("channel_");var SpatialShotIdSchema=stableId("shot_");var finiteCoordinate2=z2.number().finite().min(-1e6).max(1e6);var positiveDimension=z2.number().finite().min(0.000001).max(1e6);var unit2=z2.number().finite().min(0).max(1);var SpatialTimeUsSchema=z2.number().int().safe().min(0).max(SPATIAL_SCENE_LIMITS.durationUs);var SpatialVec3Schema=z2.tuple([finiteCoordinate2,finiteCoordinate2,finiteCoordinate2]);var SpatialQuaternionSchema=z2.tuple([z2.number().finite().min(-1).max(1),z2.number().finite().min(-1).max(1),z2.number().finite().min(-1).max(1),z2.number().finite().min(-1).max(1)]).refine((value)=>Math.abs(value.reduce((sum,part)=>sum+part*part,0)-1)<=0.000001,"Rotation must be a unit quaternion in XYZW order.");var SpatialTransformSchema=z2.strictObject({position:SpatialVec3Schema,rotation:SpatialQuaternionSchema,scale:z2.tuple([positiveDimension,positiveDimension,positiveDimension])});var SpatialPoseSchema=z2.strictObject({position:SpatialVec3Schema,rotation:SpatialQuaternionSchema});var SpatialFrameRateSchema=z2.strictObject({numerator:z2.number().int().safe().min(1).max(1e6),denominator:z2.number().int().safe().min(1).max(1e6)}).refine((rate)=>rate.numerator/rate.denominator<=1000,"Frame rate exceeds 1,000 fps.");var dimensions={width:z2.number().int().min(1).max(16384),height:z2.number().int().min(1).max(16384)};var clipping={near:positiveDimension,far:positiveDimension};var SpatialProjectionSchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("perspective"),...dimensions,...clipping,fx:positiveDimension,fy:positiveDimension,cx:finiteCoordinate2,cy:finiteCoordinate2}),z2.strictObject({kind:z2.literal("orthographic"),...dimensions,...clipping,left:finiteCoordinate2,right:finiteCoordinate2,top:finiteCoordinate2,bottom:finiteCoordinate2})]).superRefine((projection,context)=>{if(projection.far<=projection.near)context.addIssue({code:"custom",message:"Far clipping must exceed near clipping."});if(projection.width*projection.height>33554432)context.addIssue({code:"custom",message:"Camera exceeds the 32-megapixel limit."});if(projection.kind==="orthographic"&&(projection.right<=projection.left||projection.top<=projection.bottom)){context.addIssue({code:"custom",message:"Orthographic extents must have positive width and height."})}});var boundedPhysical=(minimum,maximum)=>z2.number().finite().min(minimum).max(maximum);var SpatialCameraLensSchema=z2.strictObject({focalLengthMm:boundedPhysical(1,2000),sensorWidthMm:boundedPhysical(1,200),apertureFStop:boundedPhysical(0.5,128).optional(),focusDistanceM:boundedPhysical(0.001,1e6).optional(),shutterAngleDeg:boundedPhysical(0,360).optional(),exposureEv:boundedPhysical(-32,32).optional(),colorTemperatureK:boundedPhysical(1000,40000).optional()});var SpatialCameraSchema=z2.strictObject({cameraId:SpatialCameraIdSchema,name:z2.string().min(1).max(256),pose:SpatialPoseSchema,projection:SpatialProjectionSchema,lens:SpatialCameraLensSchema.optional()});var relativePath=z2.string().min(1).max(1024).refine((value)=>!value.startsWith("/")&&!/[\\\u0000-\u001f]/u.test(value)&&!/^[a-zA-Z]:/u.test(value)&&value.split("/").every((part)=>part!==""&&part!=="."&&part!==".."),"Asset paths must be contained root-relative paths.");var SpatialPayloadSchema=z2.strictObject({path:relativePath,sha256:SpatialDigestSchema,bytes:z2.number().int().safe().min(1).max(134217728)});var imageInterpretation={...dimensions,colorSpace:z2.literal("srgb"),alpha:z2.enum(["straight","opaque"])};var SpatialAssetInterpretationSchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("image"),...imageInterpretation,mimeType:z2.enum(["image/png","image/jpeg","image/svg+xml"])}),z2.strictObject({kind:z2.literal("video"),...imageInterpretation,durationUs:SpatialTimeUsSchema.refine((value)=>value>0),frameRate:SpatialFrameRateSchema}),z2.strictObject({kind:z2.literal("diagram"),schemaVersion:z2.literal(1),theme:z2.enum(["light","dark"])}),z2.strictObject({kind:z2.literal("gltf"),format:z2.enum(["glb","gltf"]),metersPerUnit:positiveDimension,sourceUp:z2.enum(["x","y","z"])}),z2.strictObject({kind:z2.literal("font"),format:z2.enum(["otf","woff2"]),family:z2.string().min(1).max(128)}),z2.strictObject({kind:z2.literal("splat"),format:z2.enum(["spz","ply"]),metersPerUnit:positiveDimension,sourceUp:z2.enum(["x","y","z"])}),z2.strictObject({kind:z2.literal("metadata"),format:z2.literal("json"),schema:z2.enum(["slopcamera.spatial-world-import","slopcamera.world-labs-provenance","slopcamera.spatial-asset-facts","slopcamera.provider-metadata"])})]);var SpatialAssetManifestSchema=z2.strictObject({assetId:SpatialAssetIdSchema,payload:SpatialPayloadSchema,interpretation:SpatialAssetInterpretationSchema,dependencies:z2.array(SpatialAssetIdSchema).max(SPATIAL_SCENE_LIMITS.assets),provenance:z2.strictObject({source:z2.enum(["authored","imported","generated","derived"]),description:z2.string().min(1).max(2048),receiptSha256:SpatialDigestSchema.optional()})});var color2=z2.string().regex(/^#[a-fA-F0-9]{6}$/u);var SpatialEmissiveSchema=z2.strictObject({color:color2,intensity:z2.number().finite().min(0).max(1e5)});var SpatialMaterialSchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("unlit"),color:color2,opacity:unit2,map:SpatialAssetIdSchema.optional()}),z2.strictObject({kind:z2.literal("standard"),color:color2,opacity:unit2,roughness:unit2,metalness:unit2,map:SpatialAssetIdSchema.optional(),emissive:SpatialEmissiveSchema.optional()}),SpatialPbrMaterialSchema]);var SpatialGeometrySchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("box"),size:z2.tuple([positiveDimension,positiveDimension,positiveDimension])}),z2.strictObject({kind:z2.literal("sphere"),radius:positiveDimension}),z2.strictObject({kind:z2.literal("plane"),width:positiveDimension,height:positiveDimension}),z2.strictObject({kind:z2.literal("cylinder"),radius:positiveDimension,height:positiveDimension}),z2.strictObject({kind:z2.literal("asset"),assetId:SpatialAssetIdSchema,nodeIndex:z2.number().int().min(0).max(65535).optional(),materialMode:z2.enum(["entity","source"]).optional(),clip:z2.strictObject({index:z2.number().int().min(0).max(255),offsetUs:SpatialTimeUsSchema,playback:z2.enum(["once","loop","freeze"])}).optional(),morphWeights:z2.array(unit2).max(16).optional()})]);var SpatialSpotLightSchema=z2.strictObject({angle:z2.number().finite().min(0.000001).max(Math.PI/2),penumbra:unit2,distance:z2.number().finite().min(0).max(1e6).optional(),decay:z2.number().finite().min(0).max(1000).optional()});var SpatialOriginSchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("authored")}),z2.strictObject({kind:z2.literal("generated"),generatorId:SpatialGeneratorIdSchema,key:z2.string().min(1).max(256)})]);var SpatialPlacementSchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("world")}),z2.strictObject({kind:z2.literal("view"),cameraId:SpatialCameraIdSchema,units:z2.enum(["pixels","normalized"]),order:z2.number().int().min(-4096).max(4096)})]);var entityBase={entityId:SpatialEntityIdSchema,name:z2.string().min(1).max(256),parentId:SpatialEntityIdSchema.nullable(),transform:SpatialTransformSchema,placement:SpatialPlacementSchema,origin:SpatialOriginSchema,visible:z2.boolean()};var surfaceBase={assetId:SpatialAssetIdSchema,width:positiveDimension,height:positiveDimension,fit:z2.enum(["contain","cover","stretch"]),opacity:unit2};var SpatialEntitySchema=z2.discriminatedUnion("kind",[z2.strictObject({...entityBase,kind:z2.literal("group")}),z2.strictObject({...entityBase,kind:z2.literal("mesh"),geometry:SpatialGeometrySchema,material:SpatialMaterialSchema,castShadow:z2.boolean().optional(),receiveShadow:z2.boolean().optional(),instances:z2.array(SpatialTransformSchema).min(1).max(SPATIAL_SCENE_LIMITS.entities).optional()}),z2.strictObject({...entityBase,...surfaceBase,kind:z2.literal("image")}),z2.strictObject({...entityBase,...surfaceBase,kind:z2.literal("diagram")}),z2.strictObject({...entityBase,...surfaceBase,kind:z2.literal("video"),sourceOffsetUs:SpatialTimeUsSchema,playback:z2.enum(["once","loop","freeze"])}),z2.strictObject({...entityBase,kind:z2.literal("text"),text:z2.string().max(16384),fontAssetId:SpatialAssetIdSchema,fontSize:positiveDimension,width:positiveDimension,color:color2,align:z2.enum(["left","center","right"])}),z2.strictObject({...entityBase,kind:z2.literal("light"),light:z2.enum(["ambient","directional","point","spot"]),color:color2,intensity:z2.number().finite().min(0).max(1e5),spot:SpatialSpotLightSchema.optional(),shadow:z2.boolean().optional()}),z2.strictObject({...entityBase,kind:z2.literal("splat"),assetId:SpatialAssetIdSchema}),z2.strictObject({...entityBase,kind:z2.literal("environment"),assetId:SpatialAssetIdSchema,role:z2.enum(["background","environment","both"]),intensity:z2.number().finite().min(0).max(16)})]).superRefine((entity,context)=>{if(entity.kind!=="light")return;if(entity.light==="spot"&&entity.spot===undefined)context.addIssue({code:"custom",path:["spot"],message:"Spot lights require their spot cone parameters."});if(entity.light!=="spot"&&entity.spot!==undefined)context.addIssue({code:"custom",path:["spot"],message:"Only spot lights may carry spot cone parameters."});if(entity.light==="ambient"&&entity.shadow!==undefined)context.addIssue({code:"custom",path:["shadow"],message:"Ambient lights cannot cast shadows; only directional, point, and spot lights may declare shadow."})});var key=(value)=>z2.strictObject({timeUs:SpatialTimeUsSchema,value});var channelBase={channelId:SpatialChannelIdSchema,targetId:z2.union([SpatialEntityIdSchema,SpatialCameraIdSchema])};var SpatialAnimationSchema=z2.discriminatedUnion("property",[z2.strictObject({...channelBase,property:z2.literal("position"),interpolation:z2.enum(["step","linear"]),keys:z2.array(key(SpatialVec3Schema)).min(1).max(SPATIAL_SCENE_LIMITS.keysPerChannel)}),z2.strictObject({...channelBase,property:z2.literal("rotation"),interpolation:z2.enum(["step","slerp"]),keys:z2.array(key(SpatialQuaternionSchema)).min(1).max(SPATIAL_SCENE_LIMITS.keysPerChannel)}),z2.strictObject({...channelBase,property:z2.literal("scale"),interpolation:z2.enum(["step","linear"]),keys:z2.array(key(z2.tuple([positiveDimension,positiveDimension,positiveDimension]))).min(1).max(SPATIAL_SCENE_LIMITS.keysPerChannel)}),z2.strictObject({...channelBase,property:z2.literal("opacity"),interpolation:z2.enum(["step","linear"]),keys:z2.array(key(unit2)).min(1).max(SPATIAL_SCENE_LIMITS.keysPerChannel)})]);var SpatialOverrideSchema=z2.discriminatedUnion("property",[z2.strictObject({entityId:SpatialEntityIdSchema,property:z2.literal("color"),value:color2}),z2.strictObject({entityId:SpatialEntityIdSchema,property:z2.literal("opacity"),value:unit2}),z2.strictObject({entityId:SpatialEntityIdSchema,property:z2.literal("transform"),value:SpatialTransformSchema})]);var SpatialGeneratorSchema=z2.strictObject({generatorId:SpatialGeneratorIdSchema,sourceSha256:SpatialDigestSchema,closureSha256:SpatialDigestSchema,parametersSha256:SpatialDigestSchema,seed:z2.number().int().safe().min(0).max(4294967295),outputSha256:SpatialDigestSchema,execution:z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("qualified"),runtimeSha256:SpatialDigestSchema}),z2.strictObject({kind:z2.literal("attempt"),attemptId:z2.string().min(1).max(128),runtimeSha256:SpatialDigestSchema})]),editableKeys:z2.array(z2.strictObject({key:z2.string().min(1).max(256),properties:z2.array(z2.enum(["color","opacity","transform"])).min(1).max(3)})).max(SPATIAL_SCENE_LIMITS.entities),assets:z2.array(SpatialAssetIdSchema).max(SPATIAL_SCENE_LIMITS.assets).optional()});var SpatialSceneV1Schema=z2.strictObject({kind:z2.literal("slopcamera.spatial-scene"),schemaVersion:z2.literal(1),sceneId:SpatialSceneIdSchema,coordinates:z2.literal("right-handed-y-up-meters"),durationUs:SpatialTimeUsSchema.refine((value)=>value>0),entities:z2.array(SpatialEntitySchema).max(SPATIAL_SCENE_LIMITS.entities),cameras:z2.array(SpatialCameraSchema).min(1).max(SPATIAL_SCENE_LIMITS.cameras),assets:z2.array(SpatialAssetManifestSchema).max(SPATIAL_SCENE_LIMITS.assets),animations:z2.array(SpatialAnimationSchema).max(SPATIAL_SCENE_LIMITS.channels),generators:z2.array(SpatialGeneratorSchema).max(128),overrides:z2.array(SpatialOverrideSchema).max(SPATIAL_SCENE_LIMITS.entities),fog:SpatialFogSchema.optional()});var SpatialPatchOperationSchema=z2.discriminatedUnion("kind",[z2.strictObject({kind:z2.literal("add-asset"),asset:SpatialAssetManifestSchema}),z2.strictObject({kind:z2.literal("replace-asset"),asset:SpatialAssetManifestSchema}),z2.strictObject({kind:z2.literal("set-mesh-geometry"),entityId:SpatialEntityIdSchema,geometry:SpatialGeometrySchema}),z2.strictObject({kind:z2.literal("set-material"),entityId:SpatialEntityIdSchema,material:SpatialMaterialSchema}),z2.strictObject({kind:z2.literal("rename-entity"),entityId:SpatialEntityIdSchema,name:z2.string().min(1).max(256)}),z2.strictObject({kind:z2.literal("reparent-entity"),entityId:SpatialEntityIdSchema,parentId:SpatialEntityIdSchema.nullable()}),z2.strictObject({kind:z2.literal("set-transform"),entityId:SpatialEntityIdSchema,transform:SpatialTransformSchema}),z2.strictObject({kind:z2.literal("set-color"),entityId:SpatialEntityIdSchema,color:color2}),z2.strictObject({kind:z2.literal("set-opacity"),entityId:SpatialEntityIdSchema,opacity:unit2}),z2.strictObject({kind:z2.literal("set-emissive"),entityId:SpatialEntityIdSchema,emissive:SpatialEmissiveSchema.nullable()}),z2.strictObject({kind:z2.literal("set-spot"),entityId:SpatialEntityIdSchema,spot:SpatialSpotLightSchema}),z2.strictObject({kind:z2.literal("set-instances"),entityId:SpatialEntityIdSchema,instances:z2.array(SpatialTransformSchema).min(1).max(SPATIAL_SCENE_LIMITS.entities).nullable()}),z2.strictObject({kind:z2.literal("set-mesh-shadow"),entityId:SpatialEntityIdSchema,castShadow:z2.boolean().nullable(),receiveShadow:z2.boolean().nullable()}),z2.strictObject({kind:z2.literal("set-light-shadow"),entityId:SpatialEntityIdSchema,shadow:z2.boolean().nullable()}),z2.strictObject({kind:z2.literal("set-camera"),camera:SpatialCameraSchema}),z2.strictObject({kind:z2.literal("set-channel"),channel:SpatialAnimationSchema}),z2.strictObject({kind:z2.literal("remove-channel"),channelId:SpatialChannelIdSchema}),z2.strictObject({kind:z2.literal("add-entity"),entity:SpatialEntitySchema}),z2.strictObject({kind:z2.literal("remove-entity"),entityId:SpatialEntityIdSchema}),z2.strictObject({kind:z2.literal("set-override"),override:SpatialOverrideSchema}),z2.strictObject({kind:z2.literal("remove-override"),entityId:SpatialEntityIdSchema,property:z2.enum(["color","opacity","transform"])}),z2.strictObject({kind:z2.literal("replace-generator-output"),generator:SpatialGeneratorSchema,entities:z2.array(SpatialEntitySchema).max(SPATIAL_SCENE_LIMITS.entities),assets:z2.array(SpatialAssetManifestSchema).max(SPATIAL_SCENE_LIMITS.assets).optional()})]);var SpatialScenePatchV1Schema=z2.strictObject({kind:z2.literal("slopcamera.spatial-scene-patch"),schemaVersion:z2.literal(1),expectedSceneSha256:SpatialDigestSchema,operations:z2.array(SpatialPatchOperationSchema).min(1).max(SPATIAL_SCENE_LIMITS.patchOperations)});var SpatialShotV1Schema=z2.strictObject({shotId:SpatialShotIdSchema,sceneSha256:SpatialDigestSchema,cameraId:SpatialCameraIdSchema,range:z2.strictObject({startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema}),sceneStartUs:SpatialTimeUsSchema,playback:z2.enum(["once","loop","freeze"]),overrides:z2.array(SpatialOverrideSchema).max(SPATIAL_SCENE_LIMITS.entities),cameraPoseOverride:SpatialPoseSchema.optional()}).refine((shot)=>shot.range.endUs>shot.range.startUs,"Shot range must be nonempty and half-open.");var matrixNumber=z2.number().finite().min(-1000000000000).max(1000000000000);var SpatialMatrixSchema=z2.tuple([matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber,matrixNumber]);var EvaluatedSpatialSceneSchema=z2.strictObject({kind:z2.literal("slopcamera.spatial-snapshot"),schemaVersion:z2.literal(1),sceneSha256:SpatialDigestSchema,stateSha256:SpatialDigestSchema,viewSha256:SpatialDigestSchema,timeUs:SpatialTimeUsSchema,camera:SpatialCameraSchema,entities:z2.array(z2.strictObject({entity:SpatialEntitySchema,worldMatrix:SpatialMatrixSchema,visible:z2.boolean(),selectionId:z2.number().int().min(1).max(SPATIAL_SCENE_LIMITS.entities)})).max(SPATIAL_SCENE_LIMITS.entities),assets:z2.array(SpatialAssetManifestSchema).max(SPATIAL_SCENE_LIMITS.assets),fog:SpatialFogSchema.optional()});class SpatialSceneError extends SlopcameraCodeError{path;constructor(code,message,path="scene"){super(code,message,{path});this.name="SpatialSceneError";this.path=path}}var limits={maximumDepth:SPATIAL_SCENE_LIMITS.sourceDepth,maximumValues:SPATIAL_SCENE_LIMITS.sourceValues};function parseSpatialValue(schema,input,name){try{const captured=createBoundedJsonValueSnapshot(input,SPATIAL_SCENE_LIMITS.sourceBytes,name,limits);const parsed=schema.safeParse(captured.value);if(!parsed.success){const issue=parsed.error.issues[0];throw new SpatialSceneError("invalid-data",issue?.message??`Invalid ${name}.`,`${name}.${issue?.path.join(".")??""}`)}return parsed.data}catch(error){if(error instanceof SpatialSceneError)throw error;throw new SpatialSceneError("invalid-data",error instanceof Error?error.message:`Invalid ${name}.`,name)}}function spatialValueSha256(input){return createBoundedJsonSnapshot(input,SPATIAL_SCENE_LIMITS.sourceBytes,"spatial identity",limits).sha256}function spatialStateValueSha256(input){return createBoundedJsonSnapshot(input,SPATIAL_SCENE_LIMITS.sourceBytes*4,"spatial state identity",{maximumDepth:SPATIAL_SCENE_LIMITS.sourceDepth+4,maximumValues:SPATIAL_SCENE_LIMITS.sourceValues+SPATIAL_SCENE_LIMITS.entities*24}).sha256}function compare(a,b){return a<b?-1:a>b?1:0}function sortSpatialBy(items,id){return[...items].sort((a,b)=>compare(id(a),id(b)))}function unique(items,id,path){const result=new Map;for(const item of items){const key2=id(item);if(result.has(key2))throw new SpatialSceneError("invalid-data",`Duplicate identity ${key2}.`,path);result.set(key2,item)}return result}function requireReference(map,id,path){const result=map.get(id);if(result===undefined)throw new SpatialSceneError("invalid-data",`Missing reference ${id}.`,path);return result}function spatialTopologicalIds(edges,name){const done=new Set;const active=new Set;const result=[];for(const id of edges.keys()){const pending=[{id,exit:false}];while(pending.length){const next=pending.pop();if(next.exit){active.delete(next.id);done.add(next.id);result.push(next.id);continue}if(done.has(next.id))continue;if(active.has(next.id))throw new SpatialSceneError("invalid-data",`Cycle at ${next.id}.`,name);const dependencies=requireReference(edges,next.id,name);active.add(next.id);pending.push({id:next.id,exit:true});for(const dependency of dependencies)pending.push({id:dependency,exit:false})}}return Object.freeze(result)}function generatedSpatialEntityId(generatorId,key2){SpatialGeneratorIdSchema.parse(generatorId);if(typeof key2!=="string"||key2.length<1||key2.length>256)throw new SpatialSceneError("invalid-data","Generator keys must contain 1\u2013256 characters.");return`entity_${spatialValueSha256({domain:"slopcamera.generated-entity.v1",generatorId,key:key2})}`}function normalizeEntity(entity){if(entity.kind==="mesh"){const material=entity.material;if(material.kind==="pbr"){const emissive2=material.emissive!==undefined?{...material.emissive,color:material.emissive.color.toLowerCase()}:undefined;const sheen=material.sheen!==undefined?{...material.sheen,color:material.sheen.color.toLowerCase()}:undefined;return{...entity,material:{...material,color:material.color.toLowerCase(),...emissive2===undefined?{}:{emissive:emissive2},...sheen===undefined?{}:{sheen}}}}const emissive=material.kind==="standard"&&material.emissive!==undefined?{...material.emissive,color:material.emissive.color.toLowerCase()}:undefined;return{...entity,material:{...material,color:material.color.toLowerCase(),...emissive===undefined?{}:{emissive}}}}if(entity.kind==="text"||entity.kind==="light")return{...entity,color:entity.color.toLowerCase()};return entity}function normalizeAsset(asset){if(asset.interpretation.kind!=="video")return asset;const rate=asset.interpretation.frameRate;let{numerator:divisor,denominator:remainder}=rate;while(remainder!==0){const next=divisor%remainder;divisor=remainder;remainder=next}return{...asset,interpretation:{...asset.interpretation,frameRate:{numerator:rate.numerator/divisor,denominator:rate.denominator/divisor}}}}function spatialGeneratorOutputSha256(input){const entities=parseSpatialValue(SpatialEntitySchema.array().max(SPATIAL_SCENE_LIMITS.entities),input,"generator output");unique(entities,(item)=>item.entityId,"generator output");return spatialValueSha256({domain:"slopcamera.generator-output.v1",entities:sortSpatialBy(entities.map(normalizeEntity),(item)=>item.entityId)})}function spatialAssetManifestSha256(input,dependencyDigests={}){const asset=normalizeAsset(parseSpatialValue(SpatialAssetManifestSchema,input,"asset manifest"));const captured=createBoundedJsonValueSnapshot(dependencyDigests,SPATIAL_SCENE_LIMITS.sourceBytes,"dependency identities",limits).value;if(captured===null||Array.isArray(captured)||typeof captured!=="object")throw new SpatialSceneError("invalid-data","Dependency digests must be an object.");unique(asset.dependencies,(item)=>item,"asset.dependencies");const dependencies=[...asset.dependencies].sort(compare).map((assetId2)=>{const sha256=captured[assetId2];if(typeof sha256!=="string"||!/^[a-f0-9]{64}$/u.test(sha256))throw new SpatialSceneError("invalid-data",`Missing dependency digest for ${assetId2}.`);return{assetId:assetId2,sha256}});return spatialValueSha256({domain:"slopcamera.asset-manifest.v1",payload:{sha256:asset.payload.sha256,bytes:asset.payload.bytes},interpretation:asset.interpretation,dependencies})}function spatialAssetClosureDigests(assets){const map=unique(assets,(asset)=>asset.assetId,"assets");const order=spatialTopologicalIds(new Map(assets.map((asset)=>[asset.assetId,asset.dependencies])),"asset dependencies");const digests=Object.create(null);for(const id of order)digests[id]=spatialAssetManifestSha256(map.get(id),digests);return Object.freeze(digests)}function spatialPropertySupported(entity,property){if((property==="color"||property==="opacity")&&entity.kind==="mesh"&&entity.geometry.kind==="asset"&&entity.geometry.materialMode==="source")return false;if(property==="opacity")return["mesh","image","video","diagram"].includes(entity.kind);if(property==="color")return["mesh","text","light"].includes(entity.kind);return true}function validateSpatialOverrides(scene,overrides){const entities=new Map(scene.entities.map((entity)=>[entity.entityId,entity]));const generators=new Map(scene.generators.map((generator)=>[generator.generatorId,generator]));unique(overrides,(override)=>`${override.entityId}:${override.property}`,"overrides");for(const override of overrides){const entity=requireReference(entities,override.entityId,"overrides");if(!spatialPropertySupported(entity,override.property))throw new SpatialSceneError("conflict",`Entity ${entity.entityId} does not support ${override.property}.`,"overrides");if(entity.origin.kind==="generated"){const origin=entity.origin;const generator=requireReference(generators,origin.generatorId,"overrides");if(!generator.editableKeys.some((item)=>item.key===origin.key&&item.properties.includes(override.property))){throw new SpatialSceneError("conflict",`Undeclared override ${origin.key}.${override.property}.`,"overrides")}}const properties=override.property==="transform"?["position","rotation","scale"]:[override.property];if(scene.animations.some((channel)=>channel.targetId===entity.entityId&&properties.includes(channel.property))){throw new SpatialSceneError("conflict",`Animation and override both write ${entity.entityId}.${override.property}.`,"overrides")}}}function parseSpatialScene(input){const parsed=parseSpatialValue(SpatialSceneV1Schema,input,"scene");const scene={...parsed,entities:sortSpatialBy(parsed.entities.map(normalizeEntity),(item)=>item.entityId),cameras:sortSpatialBy(parsed.cameras,(item)=>item.cameraId),assets:sortSpatialBy(parsed.assets.map(normalizeAsset).map((asset)=>({...asset,dependencies:[...asset.dependencies].sort(compare)})),(item)=>item.assetId),animations:sortSpatialBy(parsed.animations,(item)=>item.channelId),generators:sortSpatialBy(parsed.generators.map((generator)=>({...generator,editableKeys:sortSpatialBy(generator.editableKeys.map((item)=>({...item,properties:[...item.properties].sort(compare)})),(item)=>item.key),...generator.assets===undefined?{}:{assets:[...generator.assets].sort(compare)}})),(item)=>item.generatorId),overrides:sortSpatialBy(parsed.overrides.map((item)=>item.property==="color"?{...item,value:item.value.toLowerCase()}:item),(item)=>`${item.entityId}:${item.property}`)};const entities=unique(scene.entities,(entity)=>entity.entityId,"entities");const cameras=unique(scene.cameras,(camera)=>camera.cameraId,"cameras");const assets=unique(scene.assets,(asset)=>asset.assetId,"assets");const generators=unique(scene.generators,(generator)=>generator.generatorId,"generators");unique(scene.animations,(channel)=>channel.channelId,"animations");unique(scene.animations,(channel)=>`${channel.targetId}:${channel.property}`,"animation writers");let payloadBytes=0;for(const asset of scene.assets){unique(asset.dependencies,(id)=>id,"asset dependencies");payloadBytes+=asset.payload.bytes;if(payloadBytes>268435456)throw new SpatialSceneError("invalid-data","Asset closure exceeds 256 MiB.","assets");if((asset.interpretation.kind==="image"||asset.interpretation.kind==="video")&&asset.interpretation.width*asset.interpretation.height>33554432)throw new SpatialSceneError("invalid-data","Asset exceeds the 32-megapixel limit.","assets");if(asset.interpretation.kind==="metadata"&&asset.payload.bytes>1048576)throw new SpatialSceneError("invalid-data","Retained metadata exceeds one MiB.","assets")}spatialTopologicalIds(new Map(scene.assets.map((asset)=>[asset.assetId,asset.dependencies])),"asset dependencies");spatialTopologicalIds(new Map(scene.entities.map((entity)=>[entity.entityId,entity.parentId===null?[]:[entity.parentId]])),"entity hierarchy");const ownedAssets=new Map;for(const generator of scene.generators){unique(generator.assets??[],(id)=>id,"generator assets");for(const assetId2 of generator.assets??[]){const asset=requireReference(assets,assetId2,"generator asset");if(asset.provenance.source!=="generated"&&asset.provenance.source!=="derived")throw new SpatialSceneError("invalid-data",`Generator-owned asset ${assetId2} requires generated or derived provenance.`,"generators");const owner=ownedAssets.get(assetId2);if(owner!==undefined&&owner!==generator.generatorId)throw new SpatialSceneError("invalid-data",`Asset ${assetId2} is owned by more than one generator.`,"generators");ownedAssets.set(assetId2,generator.generatorId)}}const checkAssetOwnership=(entity,assetId2,path)=>{const owner=ownedAssets.get(assetId2);if(owner!==undefined&&(entity.origin.kind!=="generated"||entity.origin.generatorId!==owner)){throw new SpatialSceneError("invalid-data",`Entity ${entity.entityId} references an asset owned by another generator.`,path)}};const generatedKeys=new Set;for(const entity of scene.entities){if(entity.placement.kind==="view")requireReference(cameras,entity.placement.cameraId,"placement");if(entity.parentId!==null){const parent=requireReference(entities,entity.parentId,"parent");const a=parent.placement,b=entity.placement;if(a.kind!==b.kind||a.kind==="view"&&b.kind==="view"&&(a.cameraId!==b.cameraId||a.units!==b.units))throw new SpatialSceneError("invalid-data","Parent and child must share their world or view coordinate domain.","placement")}if(entity.origin.kind==="generated"){const{generatorId,key:key2}=entity.origin;requireReference(generators,generatorId,"origin");if(entity.entityId!==generatedSpatialEntityId(generatorId,key2))throw new SpatialSceneError("invalid-data","Generated entity identity must derive from its generator and stable key.","origin");const identity=`${generatorId}:${key2}`;if(generatedKeys.has(identity))throw new SpatialSceneError("invalid-data","Duplicate generator output key.","origin");generatedKeys.add(identity)}if(entity.kind==="environment"&&(entity.placement.kind!=="world"||entity.parentId!==null)){throw new SpatialSceneError("invalid-data","Environment entities must be unparented world entities.","placement")}if(entity.kind==="mesh"&&entity.material.kind!=="pbr"&&entity.material.map!==undefined){if(entity.geometry.kind==="asset")throw new SpatialSceneError("invalid-data","Material maps apply to authored procedural geometry only.","entities");checkAssetOwnership(entity,entity.material.map,"entity asset");const mapAsset=requireReference(assets,entity.material.map,"entity asset");if(mapAsset.interpretation.kind!=="image")throw new SpatialSceneError("invalid-data",`Entity ${entity.entityId} material map requires an image asset.`,"entity asset")}if(entity.kind==="mesh"&&entity.material.kind==="pbr"){if(entity.geometry.kind==="asset")throw new SpatialSceneError("invalid-data","PBR material maps apply to authored procedural geometry only.","entities");for(const mapAssetId of pbrMaterialMapAssetIds(entity.material)){const mapAsset=requireReference(assets,mapAssetId,"entity pbr map asset");if(mapAsset.interpretation.kind!=="image")throw new SpatialSceneError("invalid-data",`Entity ${entity.entityId} PBR map requires an image asset, got ${mapAsset.interpretation.kind}.`,"entity pbr map")}}const reference=entity.kind==="mesh"&&entity.geometry.kind==="asset"?{assetId:entity.geometry.assetId,kind:"gltf"}:entity.kind==="text"?{assetId:entity.fontAssetId,kind:"font"}:entity.kind==="environment"?{assetId:entity.assetId,kind:"image"}:("assetId"in entity)?{assetId:entity.assetId,kind:entity.kind}:undefined;if(reference){checkAssetOwnership(entity,reference.assetId,"entity asset");const asset=requireReference(assets,reference.assetId,"entity asset");if(asset.interpretation.kind!==reference.kind)throw new SpatialSceneError("invalid-data",`Entity ${entity.entityId} requires a ${reference.kind} asset.`,"entity asset");if(entity.kind==="video"&&asset.interpretation.kind==="video"&&entity.sourceOffsetUs>=asset.interpretation.durationUs)throw new SpatialSceneError("invalid-data","Video source offset must precede its duration.","sourceOffsetUs")}}for(const generator of scene.generators){unique(generator.editableKeys,(item)=>item.key,"generator editable keys");for(const editable of generator.editableKeys){unique(editable.properties,(item)=>item,"generator editable properties");const entity=entities.get(generatedSpatialEntityId(generator.generatorId,editable.key));if(!entity)throw new SpatialSceneError("conflict",`Orphan editable key ${editable.key}.`,"generators");if(editable.properties.some((property)=>!spatialPropertySupported(entity,property)))throw new SpatialSceneError("invalid-data",`Editable key ${editable.key} declares an unsupported property.`,"generators")}const retained=scene.entities.filter((entity)=>entity.origin.kind==="generated"&&entity.origin.generatorId===generator.generatorId);if(spatialGeneratorOutputSha256(retained)!==generator.outputSha256)throw new SpatialSceneError("conflict","Retained generator output does not match its pinned digest.","generators")}for(const channel of scene.animations){const entity=entities.get(channel.targetId);if(entity===undefined){requireReference(cameras,channel.targetId,"animation target");if(channel.property!=="position"&&channel.property!=="rotation")throw new SpatialSceneError("invalid-data","Camera animation supports only position and rotation.","animations")}else{if(!spatialPropertySupported(entity,channel.property))throw new SpatialSceneError("invalid-data",`Unsupported ${channel.property} animation.`,"animations");if(entity.origin.kind==="generated"){const origin=entity.origin;const control=channel.property==="opacity"?"opacity":"transform";if(!generators.get(origin.generatorId).editableKeys.some((item)=>item.key===origin.key&&item.properties.includes(control)))throw new SpatialSceneError("conflict",`Generated animation requires declared ${control} control.`,"animations")}}let previous=-1;for(const key2 of channel.keys){if(key2.timeUs<=previous||key2.timeUs>scene.durationUs)throw new SpatialSceneError("invalid-data","Animation keys must be strictly ordered within scene duration.","animations");previous=key2.timeUs}}validateSpatialOverrides(scene,scene.overrides);return deepFreezeJson(scene)}function spatialSceneSha256(input){return spatialValueSha256(parseSpatialScene(input))}var MAX_ABS_COMPONENT=1000000000000;var MAX_IMAGE_DIMENSION=1e6;var AFFINE_TOLERANCE=0.000000000001;var RIGID_TOLERANCE=0.00000001;var MIN_RELATIVE_DETERMINANT=0.000000000001;function number(value,label){if(!Number.isFinite(value)||Math.abs(value)>MAX_ABS_COMPONENT){throw new RangeError(`${label} must be finite with magnitude <= ${MAX_ABS_COMPONENT}`)}return value}function values(value,length,label){if(!Array.isArray(value)||value.length!==length)throw new RangeError(`${label} must have ${length} components`);for(let index=0;index<length;index++)number(value[index],`${label}[${index}]`)}function vec2(x,y){return Object.freeze([number(x,"x"),number(y,"y")])}function vec3(x,y,z3){return Object.freeze([number(x,"x"),number(y,"y"),number(z3,"z")])}function matrix(value){values(value,16,"matrix");return Object.freeze(value)}function affine(value){values(value,16,"transform");if(Math.abs(value[3])>AFFINE_TOLERANCE||Math.abs(value[7])>AFFINE_TOLERANCE||Math.abs(value[11])>AFFINE_TOLERANCE||Math.abs(value[15]-1)>AFFINE_TOLERANCE){throw new RangeError("transform must be affine with bottom row [0,0,0,1]")}}var IDENTITY_MATRIX=matrix([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]);function normalizeQuaternion(q){values(q,4,"quaternion");const length=Math.hypot(...q);if(length===0)throw new RangeError("quaternion must be nonzero");return Object.freeze([q[0]/length,q[1]/length,q[2]/length,q[3]/length])}function composeTransform(transform){values(transform.position,3,"position");values(transform.scale,3,"scale");const[x,y,z3,w]=normalizeQuaternion(transform.rotation);const[sx,sy,sz]=transform.scale;return matrix([(1-2*(y*y+z3*z3))*sx,2*(x*y+z3*w)*sx,2*(x*z3-y*w)*sx,0,2*(x*y-z3*w)*sy,(1-2*(x*x+z3*z3))*sy,2*(y*z3+x*w)*sy,0,2*(x*z3+y*w)*sz,2*(y*z3-x*w)*sz,(1-2*(x*x+y*y))*sz,0,...transform.position,1])}function multiplyTransforms(parent,local){affine(parent);affine(local);const output=new Array(16).fill(0);for(let col=0;col<4;col++){for(let row=0;row<3;row++){output[col*4+row]=parent[row]*local[col*4]+parent[4+row]*local[col*4+1]+parent[8+row]*local[col*4+2]+(col===3?parent[12+row]:0)}}output[15]=1;return matrix(output)}function invertTransform(transform){affine(transform);const scale=Math.max(...[0,1,2,4,5,6,8,9,10].map((index)=>Math.abs(transform[index])));if(scale===0)throw new RangeError("transform is singular");const[a,b,c,d,e,f,g,h,i]=[0,4,8,1,5,9,2,6,10].map((index)=>transform[index]/scale);const det=a*(e*i-f*h)-b*(d*i-f*g)+c*(d*h-e*g);if(Math.abs(det)<=MIN_RELATIVE_DETERMINANT)throw new RangeError("transform is singular or ill-conditioned");const factor=1/det/scale;const r00=(e*i-f*h)*factor,r01=(c*h-b*i)*factor,r02=(b*f-c*e)*factor;const r10=(f*g-d*i)*factor,r11=(a*i-c*g)*factor,r12=(c*d-a*f)*factor;const r20=(d*h-e*g)*factor,r21=(b*g-a*h)*factor,r22=(a*e-b*d)*factor;const[tx,ty,tz]=[transform[12],transform[13],transform[14]];return matrix([r00,r10,r20,0,r01,r11,r21,0,r02,r12,r22,0,-(r00*tx+r01*ty+r02*tz),-(r10*tx+r11*ty+r12*tz),-(r20*tx+r21*ty+r22*tz),1])}function transformPoint(transform,point){affine(transform);values(point,3,"point");return apply(transform,point,true)}function transformDirection(transform,direction){affine(transform);values(direction,3,"direction");return apply(transform,direction,false)}function apply(m,v,translate){return vec3(m[0]*v[0]+m[4]*v[1]+m[8]*v[2]+(translate?m[12]:0),m[1]*v[0]+m[5]*v[1]+m[9]*v[2]+(translate?m[13]:0),m[2]*v[0]+m[6]*v[1]+m[10]*v[2]+(translate?m[14]:0))}function slerpQuaternion(from,to,t){number(t,"t");if(t<0||t>1)throw new RangeError("t must be in [0,1]");const a=normalizeQuaternion(from);const normalizedTo=normalizeQuaternion(to);let dot=a.reduce((sum,value,index)=>sum+value*normalizedTo[index],0);const b=dot<0?normalizedTo.map((value)=>-value):normalizedTo;dot=Math.min(1,Math.max(0,Math.abs(dot)));let left=1-t,right=t;if(dot<0.9995){const angle=Math.acos(dot),sine=Math.sin(angle);left=Math.sin((1-t)*angle)/sine;right=Math.sin(t*angle)/sine}return normalizeQuaternion([left*a[0]+right*b[0],left*a[1]+right*b[1],left*a[2]+right*b[2],left*a[3]+right*b[3]])}function projection(p){for(const value of[p.width,p.height]){if(!Number.isSafeInteger(value)||value<=0||value>MAX_IMAGE_DIMENSION)throw new RangeError("image dimensions must be positive bounded integers")}number(p.near,"near");number(p.far,"far");if(p.near<=0||p.far<=p.near)throw new RangeError("clipping requires 0 < near < far");if(p.kind==="perspective"){for(const key2 of["fx","fy","cx","cy"])number(p[key2],key2);if(p.fx<=0||p.fy<=0)throw new RangeError("focal lengths in pixels must be positive")}else if(p.kind==="orthographic"){for(const key2 of["left","right","bottom","top"])number(p[key2],key2);if(p.left>=p.right||p.bottom>=p.top)throw new RangeError("orthographic extents must be ordered")}else{throw new RangeError("unsupported projection")}}function camera(camera2){projection(camera2.projection);const m=camera2.cameraToWorld;affine(m);const columns=[[m[0],m[1],m[2]],[m[4],m[5],m[6]],[m[8],m[9],m[10]]];for(let i=0;i<3;i++){for(let j=i;j<3;j++){const dot=columns[i].reduce((sum,value,index)=>sum+value*columns[j][index],0);if(Math.abs(dot-(i===j?1:0))>RIGID_TOLERANCE)throw new RangeError("camera pose must be rigid without scale or shear")}}const determinant=m[0]*(m[5]*m[10]-m[9]*m[6])-m[4]*(m[1]*m[10]-m[9]*m[2])+m[8]*(m[1]*m[6]-m[5]*m[2]);if(determinant<=0)throw new RangeError("camera pose must preserve handedness")}function prepareCameraView(view){camera(view);return Object.freeze({...view,worldToCamera:invertTransform(view.cameraToWorld)})}function projectPreparedPoint(prepared,worldPoint){values(worldPoint,3,"world point");const local=apply(prepared.worldToCamera,worldPoint,true);const depthMeters=-local[2];if(depthMeters<=0)return null;const p=prepared.projection;const pixel=p.kind==="perspective"?vec2(p.fx*local[0]/depthMeters+p.cx,p.cy-p.fy*local[1]/depthMeters):vec2((local[0]-p.left)/(p.right-p.left)*p.width,(p.top-local[1])/(p.top-p.bottom)*p.height);return Object.freeze({pixel,depthMeters,insideImage:pixel[0]>=0&&pixel[0]<p.width&&pixel[1]>=0&&pixel[1]<p.height,insideClip:depthMeters>=p.near&&depthMeters<=p.far})}function projectPoint(view,worldPoint){return projectPreparedPoint(prepareCameraView(view),worldPoint)}function unprojectPixel(view,pixel,depthMeters){camera(view);values(pixel,2,"pixel");number(depthMeters,"depth");if(depthMeters<=0)throw new RangeError("axial depth must be positive");const p=view.projection;const local=p.kind==="perspective"?[(pixel[0]-p.cx)/p.fx*depthMeters,(p.cy-pixel[1])/p.fy*depthMeters,-depthMeters]:[p.left+pixel[0]/p.width*(p.right-p.left),p.top-pixel[1]/p.height*(p.top-p.bottom),-depthMeters];values(local,3,"unprojected local point");return apply(view.cameraToWorld,local,true)}function pixelRay(view,pixel){camera(view);values(pixel,2,"pixel");const p=view.projection;const x=p.kind==="perspective"?(pixel[0]-p.cx)/p.fx:p.left+pixel[0]/p.width*(p.right-p.left);const y=p.kind==="perspective"?(p.cy-pixel[1])/p.fy:p.top-pixel[1]/p.height*(p.top-p.bottom);const length=p.kind==="perspective"?Math.hypot(x,y,1):1;const origin=apply(view.cameraToWorld,p.kind==="perspective"?[0,0,0]:vec3(x,y,0),true);const direction=apply(view.cameraToWorld,p.kind==="perspective"?vec3(x/length,y/length,-1/length):[0,0,-1],false);return Object.freeze({origin,direction,nearDistanceMeters:number(p.near*length,"near ray distance"),farDistanceMeters:number(p.far*length,"far ray distance")})}function transformBounds(transform,bounds){affine(transform);values(bounds.min,3,"bounds min");values(bounds.max,3,"bounds max");if(bounds.min.some((value,index)=>value>bounds.max[index]))throw new RangeError("bounds must have min <= max");const min=[Infinity,Infinity,Infinity],max=[-Infinity,-Infinity,-Infinity];for(let mask=0;mask<8;mask++){const point=apply(transform,[mask&1?bounds.max[0]:bounds.min[0],mask&2?bounds.max[1]:bounds.min[1],mask&4?bounds.max[2]:bounds.min[2]],true);for(let index=0;index<3;index++){min[index]=Math.min(min[index],point[index]);max[index]=Math.max(max[index],point[index])}}return Object.freeze({min:vec3(min[0],min[1],min[2]),max:vec3(max[0],max[1],max[2])})}function cameraMathView(camera2){return Object.freeze({projection:camera2.projection,cameraToWorld:composeTransform({...camera2.pose,scale:[1,1,1]})})}import{z as z3}from"zod";var SPATIAL_GLB_PROFILE="slopcamera.glb-triangles-trs-pbr-fullmaps-v1";var SPATIAL_GLB_PROFILE_V1="slopcamera.glb-triangles-trs-pbr-basecolor-v1";var SPATIAL_GLB_RIGGED_PROFILE="slopcamera.glb-rigged-morph-skin-v1";var SPATIAL_GLB_LIMITS=Object.freeze({bytes:134217728,jsonBytes:2097152,jsonValues:200000,jsonDepth:32,nodes:4096,meshes:256,primitives:256,verticesPerPrimitive:65536,triangles:1e5,decodedAccessorValues:2000000,accessors:4096,bufferViews:4096,materials:256,images:128,imageBytes:16777216,imageTotalBytes:33554432,imagePixels:67108864,clips:256,channels:4096,animationKeys:4096,durationSeconds:3600,skins:64,jointsPerSkin:256,morphTargetsPerPrimitive:16,morphTargetDeltas:2000000});var finite=z3.number().finite().min(-1e6).max(1e6);var index=z3.number().int().min(0).max(65535);var unit3=z3.number().finite().min(0).max(1);var vec32=z3.tuple([finite,finite,finite]);var signedUnit=z3.number().finite().min(-1).max(1);var quaternion=z3.tuple([signedUnit,signedUnit,signedUnit,signedUnit]);var metadata={name:z3.string().max(1024).optional(),extras:z3.unknown().optional(),extensions:z3.never().optional()};var metadataWithoutExtensions={name:z3.string().max(1024).optional(),extras:z3.unknown().optional()};var byteOffset=z3.number().int().min(0).max(SPATIAL_GLB_LIMITS.bytes);var textureTransform=z3.strictObject({offset:z3.tuple([finite,finite]).default([0,0]),rotation:z3.number().finite().min(-Math.PI).max(Math.PI).default(0),scale:z3.tuple([finite,finite]).default([1,1]),texCoord:z3.literal(0).optional()});var textureExtensions=z3.strictObject({KHR_texture_transform:textureTransform.optional()});var textureInfo=z3.strictObject({...metadataWithoutExtensions,index,texCoord:z3.literal(0).optional(),extensions:textureExtensions.optional()});var normalTextureInfo=z3.strictObject({...metadataWithoutExtensions,index,texCoord:z3.literal(0).optional(),scale:finite.optional(),extensions:textureExtensions.optional()});var occlusionTextureInfo=z3.strictObject({...metadataWithoutExtensions,index,texCoord:z3.literal(0).optional(),strength:unit3.optional(),extensions:textureExtensions.optional()});var supportedExtension=z3.enum(["KHR_texture_transform","KHR_materials_clearcoat","KHR_materials_transmission","KHR_materials_sheen","KHR_materials_anisotropy","KHR_materials_ior","KHR_materials_emissive_strength"]);var materialExtensions=z3.strictObject({KHR_materials_clearcoat:z3.strictObject({clearcoatFactor:unit3.default(0),clearcoatTexture:textureInfo.optional(),clearcoatRoughnessFactor:unit3.default(0),clearcoatRoughnessTexture:textureInfo.optional(),clearcoatNormalTexture:normalTextureInfo.optional()}).optional(),KHR_materials_transmission:z3.strictObject({transmissionFactor:unit3.default(0),transmissionTexture:textureInfo.optional()}).optional(),KHR_materials_sheen:z3.strictObject({sheenColorFactor:z3.tuple([unit3,unit3,unit3]).default([0,0,0]),sheenColorTexture:textureInfo.optional(),sheenRoughnessFactor:unit3.default(0),sheenRoughnessTexture:textureInfo.optional()}).optional(),KHR_materials_anisotropy:z3.strictObject({anisotropyStrength:unit3.default(0),anisotropyRotation:z3.number().finite().min(0).max(2*Math.PI).default(0),anisotropyTexture:textureInfo.optional()}).optional(),KHR_materials_ior:z3.strictObject({ior:z3.number().finite().min(1).max(5).default(1.5)}).optional(),KHR_materials_emissive_strength:z3.strictObject({emissiveStrength:z3.number().finite().min(0).max(1e5).default(1)}).optional()});var samplerSchema=z3.strictObject({...metadata,magFilter:z3.union([z3.literal(9728),z3.literal(9729)]).optional(),minFilter:z3.union([z3.literal(9728),z3.literal(9729),z3.literal(9984),z3.literal(9985),z3.literal(9986),z3.literal(9987)]).optional(),wrapS:z3.union([z3.literal(33071),z3.literal(33648),z3.literal(10497)]).default(10497),wrapT:z3.union([z3.literal(33071),z3.literal(33648),z3.literal(10497)]).default(10497)});var nodeSchema=z3.strictObject({...metadata,children:z3.array(index).max(SPATIAL_GLB_LIMITS.nodes).default([]),mesh:index.optional(),skin:index.optional(),translation:vec32.optional(),rotation:quaternion.optional(),scale:vec32.optional(),matrix:z3.array(finite).length(16).optional()});var accessorSchema=z3.strictObject({...metadata,bufferView:index,byteOffset:byteOffset.default(0),componentType:z3.union([z3.literal(5121),z3.literal(5123),z3.literal(5125),z3.literal(5126)]),normalized:z3.boolean().default(false),count:z3.number().int().min(1).max(SPATIAL_GLB_LIMITS.triangles*3),type:z3.enum(["SCALAR","VEC2","VEC3","VEC4","MAT4"]),min:z3.array(finite).min(1).max(4).optional(),max:z3.array(finite).min(1).max(4).optional()});var gltfSchema=z3.strictObject({...metadata,asset:z3.strictObject({version:z3.literal("2.0"),minVersion:z3.literal("2.0").optional(),generator:z3.string().max(1024).optional(),copyright:z3.string().max(4096).optional(),extras:z3.unknown().optional(),extensions:z3.never().optional()}),extensionsUsed:z3.array(supportedExtension).max(7).optional(),extensionsRequired:z3.array(supportedExtension).max(7).optional(),buffers:z3.array(z3.strictObject({...metadata,byteLength:z3.number().int().min(1).max(SPATIAL_GLB_LIMITS.bytes)})).length(1),bufferViews:z3.array(z3.strictObject({...metadata,buffer:z3.literal(0),byteOffset:byteOffset.default(0),byteLength:z3.number().int().min(1).max(SPATIAL_GLB_LIMITS.bytes),byteStride:z3.number().int().min(4).max(252).optional(),target:z3.union([z3.literal(34962),z3.literal(34963)]).optional()})).max(SPATIAL_GLB_LIMITS.bufferViews),accessors:z3.array(accessorSchema).max(SPATIAL_GLB_LIMITS.accessors),scene:index.optional(),scenes:z3.array(z3.strictObject({...metadata,nodes:z3.array(index).min(1).max(SPATIAL_GLB_LIMITS.nodes)})).min(1).max(128),nodes:z3.array(nodeSchema).min(1).max(SPATIAL_GLB_LIMITS.nodes),meshes:z3.array(z3.strictObject({...metadata,primitives:z3.array(z3.strictObject({...metadata,attributes:z3.strictObject({POSITION:index,NORMAL:index.optional(),TEXCOORD_0:index.optional(),JOINTS_0:index.optional(),WEIGHTS_0:index.optional()}),indices:index.optional(),material:index.optional(),mode:z3.literal(4).default(4),targets:z3.array(z3.strictObject({...metadata,POSITION:index.optional(),NORMAL:index.optional()})).max(SPATIAL_GLB_LIMITS.morphTargetsPerPrimitive).optional()})).min(1).max(SPATIAL_GLB_LIMITS.primitives),weights:z3.array(unit3).max(SPATIAL_GLB_LIMITS.morphTargetsPerPrimitive).optional()})).min(1).max(SPATIAL_GLB_LIMITS.meshes),skins:z3.array(z3.strictObject({...metadata,inverseBindMatrices:index,joints:z3.array(index).min(1).max(SPATIAL_GLB_LIMITS.jointsPerSkin),skeleton:index.optional()})).max(SPATIAL_GLB_LIMITS.skins).optional(),materials:z3.array(z3.strictObject({...metadataWithoutExtensions,extensions:materialExtensions.optional(),pbrMetallicRoughness:z3.strictObject({...metadata,baseColorFactor:z3.tuple([unit3,unit3,unit3,unit3]).default([1,1,1,1]),metallicFactor:unit3.default(1),roughnessFactor:unit3.default(1),baseColorTexture:textureInfo.optional(),metallicRoughnessTexture:textureInfo.optional()}).optional(),normalTexture:normalTextureInfo.optional(),occlusionTexture:occlusionTextureInfo.optional(),emissiveTexture:textureInfo.optional(),alphaMode:z3.enum(["OPAQUE","MASK","BLEND"]).default("OPAQUE"),alphaCutoff:unit3.default(0.5),doubleSided:z3.boolean().default(false),emissiveFactor:z3.tuple([unit3,unit3,unit3]).optional()})).max(SPATIAL_GLB_LIMITS.materials).default([]),images:z3.array(z3.strictObject({...metadata,bufferView:index,mimeType:z3.enum(["image/png","image/jpeg"])})).max(SPATIAL_GLB_LIMITS.images).default([]),textures:z3.array(z3.strictObject({...metadata,source:index,sampler:index.optional()})).max(SPATIAL_GLB_LIMITS.images).default([]),samplers:z3.array(samplerSchema).max(SPATIAL_GLB_LIMITS.images).default([]),animations:z3.array(z3.strictObject({...metadata,samplers:z3.array(z3.strictObject({...metadata,input:index,output:index,interpolation:z3.enum(["STEP","LINEAR"]).default("LINEAR")})).min(1).max(SPATIAL_GLB_LIMITS.channels),channels:z3.array(z3.strictObject({...metadata,sampler:index,target:z3.strictObject({...metadata,node:index,path:z3.enum(["translation","rotation","scale","weights"])})})).min(1).max(SPATIAL_GLB_LIMITS.channels)})).max(SPATIAL_GLB_LIMITS.clips).default([])});var optionsSchema=z3.strictObject({metersPerUnit:z3.number().finite().min(0.000001).max(1e6),sourceUp:z3.enum(["x","y","z"]),nodeIndex:index.optional(),materialMode:z3.enum(["source","entity"]).default("entity"),timeUs:z3.number().int().min(0).max(3600000000),clip:z3.strictObject({index,offsetUs:z3.number().int().min(0).max(3600000000),playback:z3.enum(["once","loop","freeze"])}).optional(),morphWeights:z3.array(unit3).max(SPATIAL_GLB_LIMITS.morphTargetsPerPrimitive).optional()});function fail(message,path="glb"){throw new SpatialSceneError("invalid-data",`${SPATIAL_GLB_PROFILE}: ${message}`,path)}function at(array,index2,path){return array[index2]??fail(`Missing index ${index2}.`,path)}function schemaValue(schema,input,name){const captured=createBoundedJsonValueSnapshot(input,SPATIAL_GLB_LIMITS.jsonBytes,name,{maximumDepth:SPATIAL_GLB_LIMITS.jsonDepth,maximumValues:SPATIAL_GLB_LIMITS.jsonValues});const result=schema.safeParse(captured.value);if(!result.success){const issue=result.error.issues[0];return fail(`Unsupported or invalid field: ${issue?.message??"invalid data"}.`,`${name}.${issue?.path.join(".")??""}`)}return result.data}function normalizedRotation(value,path){if(value.length!==4||Math.abs(Math.hypot(...value)-1)>0.00001)fail("Rotation must be a unit XYZW quaternion.",path);return normalizeQuaternion(value)}function safeMatrix(value,path){try{invertTransform(value)}catch{fail("Node transform must be an invertible affine matrix.",path)}return value}function nodeTransform(node,path){if(node.matrix){if(node.translation||node.rotation||node.scale)fail("Node matrix and TRS cannot be combined.",path);const matrix2=safeMatrix(Object.freeze([...node.matrix]),path);const axes=[[matrix2[0],matrix2[1],matrix2[2]],[matrix2[4],matrix2[5],matrix2[6]],[matrix2[8],matrix2[9],matrix2[10]]];for(let a=0;a<3;a++)for(let b=a+1;b<3;b++){const left=axes[a],right=axes[b];const dot=left.reduce((sum,value,i)=>sum+value*right[i],0);if(Math.abs(dot)>Math.hypot(...left)*Math.hypot(...right)*0.000001)fail("Node matrix contains unsupported shear.",path)}return matrix2}const rotation=normalizedRotation(node.rotation??[0,0,0,1],path);return safeMatrix(composeTransform({position:node.translation??[0,0,0],rotation,scale:node.scale??[1,1,1]}),path)}function imageHeader(bytes,mimeType){const data=new DataView(bytes.buffer,bytes.byteOffset,bytes.byteLength);let width=0,height=0;if(mimeType==="image/png"){if(bytes.length<45||[137,80,78,71,13,10,26,10].some((value,i)=>bytes[i]!==value))fail("Embedded image MIME does not match a PNG signature.");let cursor=8,chunks=0,hasData=false,ended=false;while(cursor<bytes.length){if(++chunks>65536||cursor+12>bytes.length)fail("Malformed PNG chunk envelope.");const length=data.getUint32(cursor),type=data.getUint32(cursor+4);if(length>bytes.length-cursor-12)fail("PNG chunk exceeds its image view.");if(cursor===8){if(type!==1229472850||length!==13)fail("PNG must begin with IHDR.");width=data.getUint32(cursor+8);height=data.getUint32(cursor+12)}else if(type===1229472850)fail("Duplicate PNG IHDR.");if(type===1633899596)fail("Animated PNG textures are unsupported.");if(type===1229209940)hasData=true;cursor+=12+length;if(type===1229278788){if(length!==0||cursor!==bytes.length)fail("PNG IEND must end its image view.");ended=true;break}}if(!hasData||!ended)fail("PNG requires IDAT and IEND chunks.")}else{if(bytes.length<10||bytes[0]!==255||bytes[1]!==216||bytes.at(-2)!==255||bytes.at(-1)!==217)fail("Embedded image MIME does not match a complete JPEG envelope.");let cursor=2,segments=0;while(cursor+4<=bytes.length){if(++segments>65536||bytes[cursor++]!==255)fail("Malformed JPEG marker.");while(bytes[cursor]===255)cursor++;const marker=bytes[cursor++];if(marker===218||marker===217)break;if(marker===0||marker===216||marker>=208&&marker<=215)fail("Unexpected JPEG standalone marker.");if(cursor+2>bytes.length)fail("Truncated JPEG segment.");const length=data.getUint16(cursor);if(length<2||cursor+length>bytes.length)fail("JPEG segment exceeds its image view.");if([192,193,194].includes(marker)){if(width!==0||length<8||bytes[cursor+2]!==8||![1,3].includes(bytes[cursor+7]))fail("JPEG requires one 8-bit grayscale or RGB frame.");height=data.getUint16(cursor+3);width=data.getUint16(cursor+5)}else if(marker>=192&&marker<=207&&![196,200,204].includes(marker))fail("JPEG frame encoding is unsupported.");cursor+=length}}if(width<1||height<1||width>8192||height>8192||width*height>SPATIAL_GLB_LIMITS.imagePixels)fail("Embedded image dimensions exceed the decoded pixel profile.");return{width,height}}function readAccessors(document,binary){let totalValues=0;const data=new DataView(binary.buffer,binary.byteOffset,binary.byteLength);for(const[index2,view]of document.bufferViews.entries()){if(view.byteOffset+view.byteLength>document.buffers[0].byteLength)fail("Buffer view exceeds the declared BIN payload.",`bufferViews.${index2}`);if(view.byteStride!==undefined&&view.byteStride%4!==0)fail("Vertex stride must be a multiple of four.",`bufferViews.${index2}`)}return Object.freeze(document.accessors.map((accessor,index2)=>{const path=`accessors.${index2}`;const view=at(document.bufferViews,accessor.bufferView,path);const bytes=accessor.componentType===5121?1:accessor.componentType===5123?2:4;const components=accessor.type==="SCALAR"?1:accessor.type==="MAT4"?16:Number(accessor.type.slice(3));const stride=view.byteStride??components*bytes;if(accessor.byteOffset%bytes!==0||(view.byteOffset+accessor.byteOffset)%bytes!==0||stride<components*bytes||stride%bytes!==0)fail("Accessor alignment or stride is invalid.",path);if(accessor.byteOffset+(accessor.count-1)*stride+components*bytes>view.byteLength)fail("Accessor exceeds its buffer view.",path);if(accessor.normalized&&(accessor.componentType===5125||accessor.componentType===5126))fail("Only unsigned byte/short UVs support normalized storage in this profile.",path);totalValues+=accessor.count*components;if(totalValues>SPATIAL_GLB_LIMITS.decodedAccessorValues)fail("Decoded accessor budget exceeded.",path);const values2=[];const low=new Array(components).fill(Infinity),high=new Array(components).fill(-Infinity);for(let element=0;element<accessor.count;element++)for(let component=0;component<components;component++){const offset=view.byteOffset+accessor.byteOffset+element*stride+component*bytes;const raw=accessor.componentType===5121?data.getUint8(offset):accessor.componentType===5123?data.getUint16(offset,true):accessor.componentType===5125?data.getUint32(offset,true):data.getFloat32(offset,true);if(!Number.isFinite(raw))fail("Accessor contains nonfinite data.",path);low[component]=Math.min(low[component],raw);high[component]=Math.max(high[component],raw);values2.push(accessor.normalized?raw/(accessor.componentType===5121?255:65535):raw)}for(const[declared,computed,label]of[[accessor.min,low,"min"],[accessor.max,high,"max"]]){if(declared!==undefined&&(declared.length!==components||declared.some((value,component)=>Math.abs(value-computed[component])>0.000001*Math.max(1,Math.abs(value)))))fail(`Accessor ${label} does not match decoded values.`,path)}return Object.freeze({source:accessor,components,values:Object.freeze(values2)})}))}function validateViewRoles(document){const roles=new Map,vertexAccessors=new Map;const assign=(viewIndex,role)=>{const previous=roles.get(viewIndex);if(previous!==undefined&&previous!==role)fail(`Buffer view mixes ${previous} and ${role} data.`,`bufferViews.${viewIndex}`);roles.set(viewIndex,role)};const accessor=(index2,role)=>{const source=at(document.accessors,index2,"accessors");assign(source.bufferView,role);if(role==="vertex"){const ids=vertexAccessors.get(source.bufferView)??new Set;ids.add(index2);vertexAccessors.set(source.bufferView,ids)}};for(const mesh of document.meshes)for(const primitive of mesh.primitives){for(const index2 of Object.values(primitive.attributes))if(index2!==undefined)accessor(index2,"vertex");if(primitive.indices!==undefined)accessor(primitive.indices,"index");if(primitive.targets!==undefined)for(const target of primitive.targets){if(target.POSITION!==undefined)accessor(target.POSITION,"vertex");if(target.NORMAL!==undefined)accessor(target.NORMAL,"vertex")}}if(document.skins!==undefined)for(const skin of document.skins)accessor(skin.inverseBindMatrices,"skin");for(const clip of document.animations)for(const sampler of clip.samplers){accessor(sampler.input,"animation");accessor(sampler.output,"animation")}for(const image of document.images)assign(image.bufferView,"image");for(const[viewIndex,ids]of vertexAccessors)if(ids.size>1&&at(document.bufferViews,viewIndex,"bufferViews").byteStride===undefined)fail("Shared vertex-attribute views require an explicit stride.",`bufferViews.${viewIndex}`)}function validateExtensions(document){const used=document.extensionsUsed??[],required=document.extensionsRequired??[];if(new Set(used).size!==used.length||new Set(required).size!==required.length)fail("Extension declarations must be unique.","extensionsUsed");for(const extension of required)if(!used.includes(extension))fail("Every required extension must also be listed in extensionsUsed.","extensionsRequired");const present=new Set;const texture=(info)=>{if(info?.extensions?.KHR_texture_transform!==undefined)present.add("KHR_texture_transform")};for(const material of document.materials){for(const name of Object.keys(material.extensions??{}))present.add(name);texture(material.pbrMetallicRoughness?.baseColorTexture);texture(material.pbrMetallicRoughness?.metallicRoughnessTexture);texture(material.normalTexture);texture(material.occlusionTexture);texture(material.emissiveTexture);const extensions=material.extensions;texture(extensions?.KHR_materials_clearcoat?.clearcoatTexture);texture(extensions?.KHR_materials_clearcoat?.clearcoatRoughnessTexture);texture(extensions?.KHR_materials_clearcoat?.clearcoatNormalTexture);texture(extensions?.KHR_materials_transmission?.transmissionTexture);texture(extensions?.KHR_materials_sheen?.sheenColorTexture);texture(extensions?.KHR_materials_sheen?.sheenRoughnessTexture);texture(extensions?.KHR_materials_anisotropy?.anisotropyTexture)}for(const extension of present)if(!used.includes(extension))fail(`Used extension ${extension} is not declared.`,"extensionsUsed")}function cleanSampler(sampler){return Object.freeze({wrapS:sampler?.wrapS??10497,wrapT:sampler?.wrapT??10497,...sampler?.magFilter===undefined?{}:{magFilter:sampler.magFilter},...sampler?.minFilter===undefined?{}:{minFilter:sampler.minFilter}})}function materials(document){for(const texture of document.textures){at(document.images,texture.source,"textures.source");if(texture.sampler!==undefined)at(document.samplers,texture.sampler,"textures.sampler")}const textureRef=(info,path)=>{if(info===undefined)return;const texture=at(document.textures,info.index,path),transform=info.extensions?.KHR_texture_transform;return{imageIndex:texture.source,sampler:cleanSampler(texture.sampler===undefined?undefined:document.samplers[texture.sampler]),...transform===undefined?{}:{transform:{offset:transform.offset,rotation:transform.rotation,scale:transform.scale}}}};return deepFreezeJson(document.materials.map((material)=>{const{pbrMetallicRoughness:pbr,extensions}=material;const clearcoat=extensions?.KHR_materials_clearcoat,transmission=extensions?.KHR_materials_transmission;const sheen=extensions?.KHR_materials_sheen,anisotropy=extensions?.KHR_materials_anisotropy;const baseColor=textureRef(pbr?.baseColorTexture,"baseColorTexture"),metallicRoughness=textureRef(pbr?.metallicRoughnessTexture,"metallicRoughnessTexture");const normal=textureRef(material.normalTexture,"normalTexture"),occlusion=textureRef(material.occlusionTexture,"occlusionTexture"),emissive=textureRef(material.emissiveTexture,"emissiveTexture");const clearcoatTexture=textureRef(clearcoat?.clearcoatTexture,"clearcoatTexture"),clearcoatRoughnessTexture=textureRef(clearcoat?.clearcoatRoughnessTexture,"clearcoatRoughnessTexture"),clearcoatNormal=textureRef(clearcoat?.clearcoatNormalTexture,"clearcoatNormalTexture");const transmissionTexture=textureRef(transmission?.transmissionTexture,"transmissionTexture"),sheenColorTexture=textureRef(sheen?.sheenColorTexture,"sheenColorTexture"),sheenRoughnessTexture=textureRef(sheen?.sheenRoughnessTexture,"sheenRoughnessTexture"),anisotropyTexture=textureRef(anisotropy?.anisotropyTexture,"anisotropyTexture");return{baseColorLinear:pbr?.baseColorFactor??[1,1,1,1],metalness:pbr?.metallicFactor??1,roughness:pbr?.roughnessFactor??1,alphaMode:material.alphaMode,alphaCutoff:material.alphaCutoff,doubleSided:material.doubleSided,...baseColor===undefined?{}:{baseColorTexture:baseColor},...metallicRoughness===undefined?{}:{metallicRoughnessTexture:metallicRoughness},...normal===undefined?{}:{normalTexture:{...normal,...material.normalTexture.scale===undefined?{}:{scale:material.normalTexture.scale}}},...occlusion===undefined?{}:{occlusionTexture:{...occlusion,...material.occlusionTexture.strength===undefined?{}:{strength:material.occlusionTexture.strength}}},...emissive===undefined?{}:{emissiveTexture:emissive},...material.emissiveFactor===undefined?{}:{emissiveLinear:material.emissiveFactor},...extensions?.KHR_materials_emissive_strength===undefined?{}:{emissiveStrength:extensions.KHR_materials_emissive_strength.emissiveStrength},...clearcoat===undefined?{}:{clearcoat:{factor:clearcoat.clearcoatFactor,roughness:clearcoat.clearcoatRoughnessFactor,...clearcoatTexture===undefined?{}:{texture:clearcoatTexture},...clearcoatRoughnessTexture===undefined?{}:{roughnessTexture:clearcoatRoughnessTexture},...clearcoatNormal===undefined?{}:{normalTexture:{...clearcoatNormal,...clearcoat.clearcoatNormalTexture?.scale===undefined?{}:{scale:clearcoat.clearcoatNormalTexture.scale}}}}},...transmission===undefined?{}:{transmission:{factor:transmission.transmissionFactor,...transmissionTexture===undefined?{}:{texture:transmissionTexture}}},...sheen===undefined?{}:{sheen:{colorLinear:sheen.sheenColorFactor,roughness:sheen.sheenRoughnessFactor,...sheenColorTexture===undefined?{}:{colorTexture:sheenColorTexture},...sheenRoughnessTexture===undefined?{}:{roughnessTexture:sheenRoughnessTexture}}},...anisotropy===undefined?{}:{anisotropy:{strength:anisotropy.anisotropyStrength,rotation:anisotropy.anisotropyRotation,...anisotropyTexture===undefined?{}:{texture:anisotropyTexture}}},...extensions?.KHR_materials_ior===undefined?{}:{ior:extensions.KHR_materials_ior.ior}}}))}function materialFacts(document,sources){return deepFreezeJson(document.materials.map((material,index2)=>{const resolved=sources[index2];const slots=[["baseColor",resolved.baseColorTexture],["metallicRoughness",resolved.metallicRoughnessTexture],["normal",resolved.normalTexture],["occlusion",resolved.occlusionTexture],["emissive",resolved.emissiveTexture],["clearcoat",resolved.clearcoat?.texture],["clearcoatRoughness",resolved.clearcoat?.roughnessTexture],["clearcoatNormal",resolved.clearcoat?.normalTexture],["transmission",resolved.transmission?.texture],["sheenColor",resolved.sheen?.colorTexture],["sheenRoughness",resolved.sheen?.roughnessTexture],["anisotropy",resolved.anisotropy?.texture]];const maps=slots.filter((entry)=>entry[1]!==undefined).map((entry)=>entry[0]);const textureTransforms=slots.flatMap(([map,texture])=>texture?.transform===undefined?[]:[{map,...texture.transform}]);return{...material.name===undefined?{}:{name:material.name},alphaMode:resolved.alphaMode,doubleSided:resolved.doubleSided,maps,textureTransforms,...resolved.emissiveLinear===undefined?{}:{emissiveLinear:resolved.emissiveLinear},...resolved.emissiveStrength===undefined?{}:{emissiveStrength:resolved.emissiveStrength},...resolved.clearcoat===undefined?{}:{clearcoat:{factor:resolved.clearcoat.factor,roughness:resolved.clearcoat.roughness}},...resolved.transmission===undefined?{}:{transmission:{factor:resolved.transmission.factor}},...resolved.sheen===undefined?{}:{sheen:{colorLinear:resolved.sheen.colorLinear,roughness:resolved.sheen.roughness}},...resolved.anisotropy===undefined?{}:{anisotropy:{strength:resolved.anisotropy.strength,rotation:resolved.anisotropy.rotation}},...resolved.ior===undefined?{}:{ior:resolved.ior}}}))}function allMaterialTextures(material){return[material.baseColorTexture,material.metallicRoughnessTexture,material.normalTexture,material.occlusionTexture,material.emissiveTexture,material.clearcoat?.texture,material.clearcoat?.roughnessTexture,material.clearcoat?.normalTexture,material.transmission?.texture,material.sheen?.colorTexture,material.sheen?.roughnessTexture,material.anisotropy?.texture]}function readMeshes(document,accessors,sources){const defaultMaterial={baseColorLinear:[1,1,1,1],metalness:1,roughness:1,alphaMode:"OPAQUE",alphaCutoff:0.5,doubleSided:false};let primitiveCount=0,triangles=0,morphTargetDeltaCount=0;return deepFreezeJson(document.meshes.map((mesh,meshIndex)=>{const targetCount=primitiveTargetCount(mesh,meshIndex);if(mesh.weights!==undefined&&mesh.weights.length!==targetCount)fail("Mesh weights count must match its morph target count.",`meshes.${meshIndex}.weights`);const weights=mesh.weights??(targetCount>0?Object.freeze(new Array(targetCount).fill(0)):Object.freeze([]));return mesh.primitives.map((primitive,primitiveIndex)=>{const path=`meshes.${meshIndex}.primitives.${primitiveIndex}`;if(++primitiveCount>SPATIAL_GLB_LIMITS.primitives)fail("Source primitive count exceeds this profile.",path);if(primitive.targets!==undefined&&primitive.targets.length!==targetCount)fail("Every primitive in a mesh must declare the same number of morph targets.",path);const positions=at(accessors,primitive.attributes.POSITION,path);const normals=primitive.attributes.NORMAL===undefined?undefined:at(accessors,primitive.attributes.NORMAL,path);const uvs=primitive.attributes.TEXCOORD_0===undefined?undefined:at(accessors,primitive.attributes.TEXCOORD_0,path);const jointsAttr=primitive.attributes.JOINTS_0===undefined?undefined:at(accessors,primitive.attributes.JOINTS_0,path);const weightsAttr=primitive.attributes.WEIGHTS_0===undefined?undefined:at(accessors,primitive.attributes.WEIGHTS_0,path);const indices=primitive.indices===undefined?undefined:at(accessors,primitive.indices,path);if(positions.source.type!=="VEC3"||positions.source.componentType!==5126||positions.source.normalized||positions.source.min===undefined||positions.source.max===undefined||positions.source.count>SPATIAL_GLB_LIMITS.verticesPerPrimitive)fail("POSITION requires bounded float32 VEC3 with declared min/max.",path);for(const attribute of[positions,normals,uvs])if(attribute!==undefined){const view=document.bufferViews[attribute.source.bufferView];if((view.byteOffset+attribute.source.byteOffset)%4!==0||attribute.source.byteOffset%4!==0||view.target!==undefined&&view.target!==34962)fail("Vertex attributes require four-byte alignment and ARRAY_BUFFER target.",path);const componentBytes=attribute.source.componentType===5121?1:attribute.source.componentType===5123?2:4;if((view.byteStride??attribute.components*componentBytes)%4!==0)fail("Every vertex attribute element must remain four-byte aligned.",path);if(attribute.source.count!==positions.source.count||attribute.values.some((value)=>Math.abs(value)>1e6))fail("Vertex attributes require matching counts and bounded coordinates.",path)}if(normals){if(normals.source.type!=="VEC3"||normals.source.componentType!==5126||normals.source.normalized)fail("NORMAL requires float32 VEC3.",path);for(let i=0;i<normals.values.length;i+=3)if(Math.abs(Math.hypot(...normals.values.slice(i,i+3))-1)>0.0001)fail("Normals must be unit vectors.",path)}if(uvs&&(uvs.source.type!=="VEC2"||uvs.source.componentType!==5126&&!([5121,5123].includes(uvs.source.componentType)&&uvs.source.normalized)))fail("TEXCOORD_0 requires float32 or normalized unsigned byte/short VEC2.",path);for(const attribute of[jointsAttr,weightsAttr]){if(attribute===undefined)continue;const view=document.bufferViews[attribute.source.bufferView];if((view.byteOffset+attribute.source.byteOffset)%4!==0||attribute.source.byteOffset%4!==0||view.target!==undefined&&view.target!==34962)fail("Skinning attributes require four-byte alignment and ARRAY_BUFFER target.",path);const componentBytes=attribute.source.componentType===5121?1:attribute.source.componentType===5123?2:4;if((view.byteStride??attribute.components*componentBytes)%4!==0)fail("Skinning attribute elements must remain four-byte aligned.",path);if(attribute.source.count!==positions.source.count||attribute.values.some((value)=>Math.abs(value)>1e6))fail("Skinning attributes require matching counts and bounded values.",path)}let jointIndices;let jointWeights;if(jointsAttr!==undefined!==(weightsAttr!==undefined))fail("JOINTS_0 and WEIGHTS_0 must appear together.",path);if(jointsAttr!==undefined){if(jointsAttr.source.type!=="VEC4"||![5121,5123].includes(jointsAttr.source.componentType)||jointsAttr.source.normalized||jointsAttr.source.count!==positions.source.count)fail("JOINTS_0 requires unsigned byte/short VEC4 matching POSITION count.",path);if(weightsAttr.source.type!=="VEC4"||weightsAttr.source.count!==positions.source.count)fail("WEIGHTS_0 requires VEC4 matching POSITION count.",path);const normalized=weightsAttr.source.normalized;const weightComponent=weightsAttr.source.componentType;if(!(weightComponent===5126||(weightComponent===5121||weightComponent===5123)&&normalized))fail("WEIGHTS_0 requires float32 or normalized unsigned byte/short.",path);jointIndices=Object.freeze(jointsAttr.values.map((value)=>{const joint=Math.round(value);if(joint<0||joint>=SPATIAL_GLB_LIMITS.jointsPerSkin||!Number.isFinite(joint)||Math.abs(joint-value)>0.000001)fail("JOINTS_0 index must be an integer in skin joint range.",path);return joint}));const normalizedWeights=[];for(let vertex=0;vertex<weightsAttr.source.count;vertex++){const values2=weightsAttr.values.slice(vertex*4,vertex*4+4);const sum=values2.reduce((total,value)=>total+value,0);if(values2.some((value)=>value<0||value>1)||Math.abs(sum-1)>0.0001)fail("Vertex skinning weights must be in [0,1] and sum to one.",path);normalizedWeights.push(...values2.map((value)=>value/sum))}jointWeights=Object.freeze(normalizedWeights)}if(indices){const view=document.bufferViews[indices.source.bufferView];if(indices.source.type!=="SCALAR"||![5121,5123,5125].includes(indices.source.componentType)||indices.source.normalized||view.byteStride!==undefined||view.target!==undefined&&view.target!==34963)fail("Triangle indices require tightly packed unsigned scalar storage.",path);const restart=indices.source.componentType===5121?255:indices.source.componentType===5123?65535:4294967295;if(indices.values.some((value)=>value>=positions.source.count||value===restart))fail("Triangle index is out of range or reserved for primitive restart.",path)}const vertices=indices?.values.length??positions.source.count;if(vertices%3!==0)fail("TRIANGLES require complete index or vertex triples.",path);triangles+=vertices/3;if(triangles>SPATIAL_GLB_LIMITS.triangles)fail("Source triangle budget exceeded.",path);const material=primitive.material===undefined?defaultMaterial:at(sources,primitive.material,path);if(uvs===undefined&&allMaterialTextures(material).some((texture)=>texture!==undefined)){fail("Material textures require TEXCOORD_0.",path)}const morphTargets=[];if(primitive.targets!==undefined)for(const[targetIndex,target]of primitive.targets.entries()){const targetPath=`${path}.targets.${targetIndex}`;const positionDeltas=target.POSITION===undefined?undefined:at(accessors,target.POSITION,targetPath);const normalDeltas=target.NORMAL===undefined?undefined:at(accessors,target.NORMAL,targetPath);if(positionDeltas===undefined&&normalDeltas===undefined)fail("Morph target must declare POSITION or NORMAL deltas.",targetPath);if(positionDeltas!==undefined){if(positionDeltas.source.type!=="VEC3"||positionDeltas.source.componentType!==5126||positionDeltas.source.normalized||positionDeltas.source.count!==positions.source.count)fail("Morph POSITION deltas require float32 VEC3 matching POSITION count.",targetPath);morphTargetDeltaCount+=positionDeltas.values.length}if(normalDeltas!==undefined){if(normalDeltas.source.type!=="VEC3"||normalDeltas.source.componentType!==5126||normalDeltas.source.normalized||normalDeltas.source.count!==positions.source.count)fail("Morph NORMAL deltas require float32 VEC3 matching POSITION count.",targetPath);morphTargetDeltaCount+=normalDeltas.values.length}for(const attribute of[positionDeltas,normalDeltas]){if(attribute===undefined)continue;const view=document.bufferViews[attribute.source.bufferView];if((view.byteOffset+attribute.source.byteOffset)%4!==0||attribute.source.byteOffset%4!==0||view.target!==undefined&&view.target!==34962)fail("Morph target attributes require four-byte alignment and ARRAY_BUFFER target.",targetPath);if((view.byteStride??attribute.components*4)%4!==0)fail("Morph target attribute elements must remain four-byte aligned.",targetPath);if(attribute.values.some((value)=>Math.abs(value)>1e6))fail("Morph target deltas must be bounded finite values.",targetPath)}if(morphTargetDeltaCount>SPATIAL_GLB_LIMITS.morphTargetDeltas)fail("Morph target delta budget exceeded.",targetPath);morphTargets.push(Object.freeze({...positionDeltas===undefined?{}:{positionDeltas:positionDeltas.values},...normalDeltas===undefined?{}:{normalDeltas:normalDeltas.values}}))}return Object.freeze({positions:positions.values,...normals===undefined?{}:{normals:normals.values},...uvs===undefined?{}:{uvs:uvs.values},...indices===undefined?{}:{indices:indices.values},...jointIndices===undefined?{}:{jointIndices,jointWeights},material,morphTargets:Object.freeze(morphTargets),weights})})}))}function primitiveTargetCount(mesh,meshIndex){const count=mesh.primitives[0]?.targets?.length??0;for(const[primitiveIndex,primitive]of mesh.primitives.entries()){if((primitive.targets?.length??0)!==count)fail("Every primitive in a mesh must declare the same number of morph targets.",`meshes.${meshIndex}.primitives.${primitiveIndex}`)}return count}function readSkins(document,accessors){if(document.skins===undefined)return Object.freeze([]);return Object.freeze(document.skins.map((skin,skinIndex)=>{const path=`skins.${skinIndex}`;const inverseBindMatrices=at(accessors,skin.inverseBindMatrices,path);if(inverseBindMatrices.source.type!=="MAT4"||inverseBindMatrices.source.componentType!==5126||inverseBindMatrices.source.normalized||inverseBindMatrices.source.count!==skin.joints.length)fail("Inverse bind matrices require a float32 MAT4 accessor with one matrix per joint.",path);const view=document.bufferViews[inverseBindMatrices.source.bufferView];if(view.byteStride!==undefined||view.target!==undefined)fail("Skin inverse bind matrices must be tightly packed without a GPU buffer target.",path);for(let index2=0;index2<skin.joints.length;index2++){const matrix2=inverseBindMatrices.values.slice(index2*16,(index2+1)*16);safeMatrix(matrix2,`${path}.inverseBindMatrices[${index2}]`)}if(new Set(skin.joints).size!==skin.joints.length)fail("Skin joints must be unique.",`${path}.joints`);for(const joint of skin.joints)at(document.nodes,joint,`${path}.joints`);if(skin.skeleton!==undefined)at(document.nodes,skin.skeleton,`${path}.skeleton`);const matrixIndexByJointNode=new Map;for(const[matrixIndex,jointNode]of skin.joints.entries())matrixIndexByJointNode.set(jointNode,matrixIndex);return Object.freeze({joints:Object.freeze([...skin.joints]),inverseBindMatrices:Object.freeze([...inverseBindMatrices.values]),sourceAccessorIndex:skin.inverseBindMatrices,matrixIndexByJointNode:Object.freeze(matrixIndexByJointNode)})}))}function rigFacts(document,skins,clipDurations){const skinSources=document.skins;const morphTargets=[];for(const[meshIndex,mesh]of document.meshes.entries()){const meshFacts=[];const targetNames=meshTargetNames(mesh,meshIndex);for(const primitive of mesh.primitives){const primitiveFacts=[];if(primitive.targets!==undefined)for(const[targetIndex,target]of primitive.targets.entries()){primitiveFacts.push({name:targetNames[targetIndex]??`target${targetIndex}`,hasPosition:target.POSITION!==undefined,hasNormal:target.NORMAL!==undefined})}meshFacts.push(primitiveFacts)}morphTargets.push(meshFacts)}return deepFreezeJson({profile:SPATIAL_GLB_RIGGED_PROFILE,skins:skins.map((skin,index2)=>({...skinSources[index2].name===undefined?{}:{name:skinSources[index2].name},jointNodeIndices:skin.joints,inverseBindMatricesAccessor:skin.sourceAccessorIndex})),morphTargets,clips:document.animations.map((clip,index2)=>({...clip.name===undefined?{}:{name:clip.name},durationSeconds:clipDurations[index2],channels:clip.channels.map((channel)=>({nodeIndex:channel.target.node,path:channel.target.path}))}))})}function meshTargetNames(mesh,_meshIndex){const extras=mesh.extras;const list=extras!==null&&typeof extras==="object"&&"targetNames"in extras&&Array.isArray(extras.targetNames)?extras.targetNames:undefined;if(list===undefined)return[];return Object.freeze(list.map((value,index2)=>typeof value==="string"&&value.length>0?value:`target${index2}`))}function detectRigProfile(document){if(document.skins!==undefined&&document.skins.length>0)return true;if(document.nodes.some((node)=>node.skin!==undefined))return true;if(document.meshes.some((mesh)=>mesh.weights!==undefined||mesh.primitives.some((primitive)=>primitive.targets!==undefined&&primitive.targets.length>0||primitive.attributes.JOINTS_0!==undefined||primitive.attributes.WEIGHTS_0!==undefined)))return true;if(document.animations.some((clip)=>clip.channels.some((channel)=>channel.target.path==="weights")))return true;return false}function rejectStaticRigFields(document,hasRig){if(hasRig)return;if(document.skins!==undefined)fail("Static GLB profile does not support skins.","skins");if(document.nodes.some((node)=>node.skin!==undefined))fail("Static GLB profile does not support skinned nodes.","nodes");if(document.meshes.some((mesh)=>mesh.weights!==undefined||mesh.primitives.some((primitive)=>primitive.targets!==undefined||primitive.attributes.JOINTS_0!==undefined||primitive.attributes.WEIGHTS_0!==undefined)))fail("Static GLB profile does not support morph targets or skinning attributes.","meshes");if(document.animations.some((clip)=>clip.channels.some((channel)=>channel.target.path==="weights")))fail("Static GLB profile does not support weights animation.","animations")}function hierarchy(document){const parents=document.nodes.map(()=>null);for(const[index2,node]of document.nodes.entries()){nodeTransform(node,`nodes.${index2}`);if(node.mesh!==undefined)at(document.meshes,node.mesh,`nodes.${index2}.mesh`);if(node.skin!==undefined){if(node.mesh===undefined)fail("Skin reference requires a mesh on the same node.",`nodes.${index2}.skin`);if(document.skins===undefined)fail("Skin reference requires a declared skins array.",`nodes.${index2}.skin`);const skin=at(document.skins,node.skin,`nodes.${index2}.skin`);for(const joint of skin.joints)at(document.nodes,joint,`skins.${node.skin}.joints`)}const seen2=new Set;for(const child of node.children){at(document.nodes,child,`nodes.${index2}.children`);if(seen2.has(child)||parents[child]!==null)fail("Nodes may have only one parent and unique child references.",`nodes.${index2}`);seen2.add(child);parents[child]=index2}}const roots=document.nodes.map((_,index2)=>index2).filter((index2)=>parents[index2]===null);const order=[],seen=new Set,pending=[...roots];while(pending.length){const index2=pending.pop();if(seen.has(index2))fail("Node hierarchy contains a cycle.");seen.add(index2);order.push(index2);pending.push(...document.nodes[index2].children)}if(seen.size!==document.nodes.length)fail("Node hierarchy contains a cycle.");for(const scene2 of document.scenes){const unique2=new Set;for(const index2 of scene2.nodes){at(document.nodes,index2,"scenes.nodes");if(parents[index2]!==null||unique2.has(index2))fail("Scene roots must be unique nodes without parents.");unique2.add(index2)}}if(document.scene===undefined&&document.scenes.length!==1)fail("Multiple scenes require an explicit glTF default scene.");const scene=at(document.scenes,document.scene??0,"scene");const reachable=new Set,visit=[...scene.nodes];while(visit.length){const index2=visit.pop();reachable.add(index2);visit.push(...document.nodes[index2].children)}return{parents:Object.freeze(parents),order:Object.freeze(order),reachable}}function validateSkinHierarchy(document,parents,reachable){for(const[skinIndex,skin]of(document.skins??[]).entries()){for(const joint of skin.joints){if(!reachable.has(joint))fail("Every skin joint must belong to the selected default scene.",`skins.${skinIndex}.joints`);if(skin.skeleton===undefined)continue;let current=joint;while(current!==null&&current!==skin.skeleton)current=parents[current];if(current===null)fail("The declared skeleton must be an ancestor of every skin joint.",`skins.${skinIndex}.skeleton`)}}}function validateSkinBindings(document,meshPrimitives,skins){if(detectRigProfile(document)&&skins.length===0)fail("The rigged GLB profile requires at least one declared skin.","skins");for(const[nodeIndex,node]of document.nodes.entries()){if(node.mesh===undefined){if(node.skin!==undefined)fail("A skinned node must reference a mesh.",`nodes.${nodeIndex}.skin`);continue}const mesh=meshPrimitives[node.mesh];if(node.skin===undefined){if(mesh.some((primitive)=>primitive.jointIndices!==undefined))fail("Skinning attributes require an explicit skin on every mesh instance.",`nodes.${nodeIndex}.mesh`);continue}const skin=skins[node.skin];if(skin===undefined)fail("Skinned node references a missing skin.",`nodes.${nodeIndex}.skin`);for(const[primitiveIndex,primitive]of mesh.entries()){const path=`nodes.${nodeIndex}.mesh.primitives.${primitiveIndex}`;if(primitive.jointIndices===undefined||primitive.jointWeights===undefined)fail("Skinned mesh primitives must declare JOINTS_0 and WEIGHTS_0.",path);for(const joint of primitive.jointIndices)if(joint<0||joint>=skin.joints.length)fail("JOINTS_0 index exceeds the skin joint count.",path)}}}function animationDurations(document,accessors){let totalChannels=0;return Object.freeze(document.animations.map((clip,clipIndex)=>{totalChannels+=clip.channels.length;if(totalChannels>SPATIAL_GLB_LIMITS.channels)fail("Animation channel budget exceeded.");let duration=0;for(const sampler of clip.samplers){const input=at(accessors,sampler.input,"animation input"),output=at(accessors,sampler.output,"animation output");if(input.source.type!=="SCALAR"||input.source.componentType!==5126||input.source.normalized||input.source.count>SPATIAL_GLB_LIMITS.animationKeys||input.source.min===undefined||input.source.max===undefined)fail("Animation input requires bounded float32 scalar seconds with min/max.");if(output.source.componentType!==5126||output.source.normalized)fail("Animation output must be float32.");for(const accessor of[input,output]){const view=document.bufferViews[accessor.source.bufferView];if(view.byteStride!==undefined||view.target!==undefined)fail("Animation data must be tightly packed without a GPU buffer target.")}let previous=-1;for(const time of input.values){if(time<0||time<=previous||time>SPATIAL_GLB_LIMITS.durationSeconds)fail("Animation times must be strictly ordered nonnegative seconds within the duration profile.");previous=time}duration=Math.max(duration,previous)}const writers=new Set;for(const channel of clip.channels){const node=at(document.nodes,channel.target.node,"animation target");if(node.matrix)fail("Animated nodes must use TRS, never a matrix.");const key2=`${channel.target.node}:${channel.target.path}`;if(writers.has(key2))fail("Animation has multiple writers for one node property.",`animations.${clipIndex}`);writers.add(key2);const sampler=at(clip.samplers,channel.sampler,"animation sampler");const input=accessors[sampler.input],output=accessors[sampler.output];if(channel.target.path==="weights"){const meshIndex=node.mesh??fail("Weights animation requires a mesh node target.",`animations.${clipIndex}.channels`);const targetCount=primitiveTargetCount(document.meshes[meshIndex],meshIndex);if(targetCount===0)fail("Weights animation requires morph targets.",`animations.${clipIndex}.channels`);if(output.source.type!=="SCALAR"||output.source.count!==input.source.count*targetCount)fail("Weights animation output must be scalar with input.count * morphTargetCount values.",`animations.${clipIndex}.channels`);if(output.values.some((value)=>value<0||value>1||!Number.isFinite(value)))fail("Morph weights must be unit values.",`animations.${clipIndex}.channels`)}else{if(output.source.type!==(channel.target.path==="rotation"?"VEC4":"VEC3")||output.source.count!==input.source.count)fail("Animation output arity does not match its target property.");if(channel.target.path==="rotation")for(let i=0;i<output.values.length;i+=4)normalizedRotation(output.values.slice(i,i+4),"animation rotation");else if(output.values.some((value)=>Math.abs(value)>1e6||channel.target.path==="scale"&&value===0))fail("Animation transform values are unbounded or singular.");if(channel.target.path==="scale"&&sampler.interpolation==="LINEAR"){for(let i=3;i<output.values.length;i++)if(Math.sign(output.values[i])!==Math.sign(output.values[i-3]))fail("Linear scale animation crosses a singular transform.")}}}return duration}))}class SpatialGlbModel{profile;nodeCount;clipDurationsSeconds;materialFacts;rigFacts;#state;constructor(state){this.#state=state;this.profile=state.profile;this.nodeCount=state.document.nodes.length;this.clipDurationsSeconds=state.clipDurations;this.materialFacts=state.materialFacts;this.rigFacts=state.rigFacts;Object.freeze(this)}static parse(input){if(!(input instanceof Uint8Array)||input.byteLength<28||input.byteLength>SPATIAL_GLB_LIMITS.bytes||input.buffer instanceof SharedArrayBuffer)fail("Expected bounded, non-shared GLB bytes.");const bytes=Uint8Array.from(input);const header=new DataView(bytes.buffer);if(header.getUint32(0,true)!==1179937895||header.getUint32(4,true)!==2||header.getUint32(8,true)!==bytes.length)fail("Invalid GLB 2.0 header or total length.");const jsonLength=header.getUint32(12,true);if(header.getUint32(16,true)!==1313821514||jsonLength%4!==0||jsonLength<4||jsonLength>SPATIAL_GLB_LIMITS.jsonBytes||20+jsonLength+8>bytes.length)fail("Expected bounded first JSON chunk and following BIN chunk.");const binHeader=20+jsonLength,binLength=header.getUint32(binHeader,true);if(header.getUint32(binHeader+4,true)!==5130562||binLength%4!==0||binHeader+8+binLength!==bytes.length)fail("Expected exactly one BIN chunk and no trailing chunks.");let json;try{json=JSON.parse(new TextDecoder("utf-8",{fatal:true}).decode(bytes.subarray(20,binHeader)))}catch{return fail("GLB JSON must be valid UTF-8 JSON.")}const document=schemaValue(gltfSchema,json,"gltf");validateExtensions(document);const payloadLength=document.buffers[0].byteLength;if(payloadLength>binLength||binLength-payloadLength>3)fail("Declared BIN length does not match its padding.");const binary=bytes.subarray(binHeader+8);if(binary.subarray(payloadLength).some((byte)=>byte!==0))fail("BIN padding must contain zero bytes.");const hasRig=detectRigProfile(document);rejectStaticRigFields(document,hasRig);validateViewRoles(document);const accessors=readAccessors(document,binary);const sources=materials(document);const meshPrimitives=readMeshes(document,accessors,sources);const skins=readSkins(document,accessors);validateSkinBindings(document,meshPrimitives,skins);const graph=hierarchy(document);validateSkinHierarchy(document,graph.parents,graph.reachable);const clipDurations=animationDurations(document,accessors);let totalImageBytes=0,totalPixels=0;const images=document.images.map((image,imageIndex)=>{const view=at(document.bufferViews,image.bufferView,"images.bufferView");if(view.byteStride!==undefined||view.target!==undefined||view.byteLength>SPATIAL_GLB_LIMITS.imageBytes)fail("Embedded images require bounded untargeted byte views.");totalImageBytes+=view.byteLength;if(totalImageBytes>SPATIAL_GLB_LIMITS.imageTotalBytes)fail("Embedded image byte budget exceeded.");const imageBytes=binary.slice(view.byteOffset,view.byteOffset+view.byteLength);const dimensions2=imageHeader(imageBytes,image.mimeType);totalPixels+=dimensions2.width*dimensions2.height;if(totalPixels>SPATIAL_GLB_LIMITS.imagePixels)fail("Embedded decoded image pixel budget exceeded.");return Object.freeze({imageIndex,mimeType:image.mimeType,...dimensions2,bytes:imageBytes})});const profile=hasRig?SPATIAL_GLB_RIGGED_PROFILE:SPATIAL_GLB_PROFILE;const rigFactsValue=hasRig?rigFacts(document,skins,clipDurations):undefined;return new SpatialGlbModel({document:deepFreezeJson(document),accessors,meshPrimitives,materialFacts:materialFacts(document,sources),images:Object.freeze(images),...graph,clipDurations,profile,skins,rigFacts:rigFactsValue})}evaluate(input){const options=schemaValue(optionsSchema,input,"glb evaluation");const state=this.#state,document=state.document;if(options.nodeIndex!==undefined&&!state.reachable.has(options.nodeIndex))fail("Selected node is absent from the default scene.","nodeIndex");let sourceTimeSeconds=null;const animated=new Map;const animatedWeights=new Map;if(options.clip!==undefined){const clip=at(document.animations,options.clip.index,"clip.index");const duration=state.clipDurations[options.clip.index];const requested=(options.timeUs+options.clip.offsetUs)/1e6;if(options.clip.offsetUs/1e6>duration)fail("Clip source offset exceeds its duration.");if(options.clip.playback==="once"&&requested>duration)fail("Once clip playback exceeds its duration.");sourceTimeSeconds=options.clip.playback==="loop"?duration===0?0:requested%duration:Math.min(requested,duration);for(const channel of clip.channels){const sampler=clip.samplers[channel.sampler],times=state.accessors[sampler.input].values,output=state.accessors[sampler.output];let lower=0,upper=times.length-1;if(sourceTimeSeconds<=times[0])upper=0;else if(sourceTimeSeconds>=times[upper])lower=upper;else while(upper-lower>1){const middle=Math.floor((lower+upper)/2);if(times[middle]<=sourceTimeSeconds)lower=middle;else upper=middle}const left=output.values.slice(lower*output.components,(lower+1)*output.components);let value=left;if(sampler.interpolation==="LINEAR"&&upper!==lower){const right=output.values.slice(upper*output.components,(upper+1)*output.components);const t=(sourceTimeSeconds-times[lower])/(times[upper]-times[lower]);value=channel.target.path==="rotation"?slerpQuaternion(left,right,t):left.map((part,index2)=>part+(right[index2]-part)*t)}if(channel.target.path==="weights"){animatedWeights.set(channel.target.node,Object.freeze(value.map((value2)=>Math.max(0,Math.min(1,value2)))))}else{const pose=animated.get(channel.target.node)??{};if(channel.target.path==="rotation")pose.rotation=normalizedRotation(value,"evaluated clip rotation");else pose[channel.target.path]=value;animated.set(channel.target.node,pose)}}}const rotation=options.sourceUp==="x"?[0,0,Math.SQRT1_2,Math.SQRT1_2]:options.sourceUp==="z"?[-Math.SQRT1_2,0,0,Math.SQRT1_2]:[0,0,0,1];const conversion=composeTransform({position:[0,0,0],rotation,scale:[options.metersPerUnit,options.metersPerUnit,options.metersPerUnit]});const matrices=new Map;for(const index2 of state.order){const node=document.nodes[index2],overrides=animated.get(index2);const local=overrides?nodeTransform({...node,...overrides},`nodes.${index2}`):nodeTransform(node,`nodes.${index2}`);const parent=state.parents[index2];matrices.set(index2,multiplyTransforms(parent===null?conversion:matrices.get(parent),local))}const selected=new Set;if(options.nodeIndex===undefined)for(const index2 of state.reachable)selected.add(index2);else{const pending=[options.nodeIndex];while(pending.length){const index2=pending.pop();selected.add(index2);pending.push(...document.nodes[index2].children)}}const primitives=[],imageIds=new Set;let triangles=0;for(const sourceNodeIndex of[...selected].sort((a,b)=>a-b)){const node=document.nodes[sourceNodeIndex];if(node.mesh===undefined)continue;const nodeWorld=safeMatrix(matrices.get(sourceNodeIndex),`nodes.${sourceNodeIndex}`);for(const[sourcePrimitiveIndex,primitive]of state.meshPrimitives[node.mesh].entries()){if(primitives.length>=SPATIAL_GLB_LIMITS.primitives)fail("Instanced primitive budget exceeded.");triangles+=(primitive.indices?.length??primitive.positions.length/3)/3;if(triangles>SPATIAL_GLB_LIMITS.triangles)fail("Instanced triangle budget exceeded.");const morphWeights=options.morphWeights??animatedWeights.get(sourceNodeIndex)??primitive.weights;const skin=node.skin!==undefined?state.skins[node.skin]:undefined;const deformed=deformPrimitive(primitive,morphWeights,skin,nodeWorld,matrices);const{material,positions:_positions,normals:_normals,morphTargets:_morphTargets,weights:_weights,jointIndices:_jointIndices,jointWeights:_jointWeights,...geometry}=primitive;if(options.materialMode==="source"){for(const texture of allMaterialTextures(material)){if(texture!==undefined)imageIds.add(texture.imageIndex)}}primitives.push(Object.freeze({...geometry,positions:deformed.positions,...deformed.normals===undefined?{}:{normals:deformed.normals},matrix:nodeWorld,bounds:deformed.bounds,sourceNodeIndex,sourcePrimitiveIndex,...options.materialMode==="source"?{material}:{}}))}}if(primitives.length===0)fail("Selected scene or subtree contains no triangle geometry.");const bounds=combineBounds(primitives.map((primitive)=>primitive.bounds));const images=[...imageIds].sort((a,b)=>a-b).map((index2)=>{const image=state.images[index2];return Object.freeze({...image,bytes:image.bytes.slice()})});const profile=state.profile;return Object.freeze({profile,primitives:deepFreezeJson(primitives),images:Object.freeze(images),bounds,sourceTimeSeconds})}jointWorldMatrix(input,jointNodeIndex){const options=schemaValue(optionsSchema,input,"glb evaluation");if(jointNodeIndex<0||jointNodeIndex>=this.nodeCount)fail("Joint node index is out of range.","jointNodeIndex");const state=this.#state,document=state.document;const animated=new Map;let sourceTimeSeconds=null;if(options.clip!==undefined){const clip=at(document.animations,options.clip.index,"clip.index");const duration=state.clipDurations[options.clip.index];const requested=(options.timeUs+options.clip.offsetUs)/1e6;if(options.clip.offsetUs/1e6>duration)fail("Clip source offset exceeds its duration.");if(options.clip.playback==="once"&&requested>duration)fail("Once clip playback exceeds its duration.");sourceTimeSeconds=options.clip.playback==="loop"?duration===0?0:requested%duration:Math.min(requested,duration);for(const channel of clip.channels){if(channel.target.path==="weights")continue;const sampler=clip.samplers[channel.sampler],times=state.accessors[sampler.input].values,output=state.accessors[sampler.output];let lower=0,upper=times.length-1;if(sourceTimeSeconds<=times[0])upper=0;else if(sourceTimeSeconds>=times[upper])lower=upper;else while(upper-lower>1){const middle=Math.floor((lower+upper)/2);if(times[middle]<=sourceTimeSeconds)lower=middle;else upper=middle}const left=output.values.slice(lower*output.components,(lower+1)*output.components);let value=left;if(sampler.interpolation==="LINEAR"&&upper!==lower){const right=output.values.slice(upper*output.components,(upper+1)*output.components);const t=(sourceTimeSeconds-times[lower])/(times[upper]-times[lower]);value=channel.target.path==="rotation"?slerpQuaternion(left,right,t):left.map((part,index2)=>part+(right[index2]-part)*t)}const pose=animated.get(channel.target.node)??{};if(channel.target.path==="rotation")pose.rotation=normalizedRotation(value,"evaluated clip rotation");else pose[channel.target.path]=value;animated.set(channel.target.node,pose)}}const rotation=options.sourceUp==="x"?[0,0,Math.SQRT1_2,Math.SQRT1_2]:options.sourceUp==="z"?[-Math.SQRT1_2,0,0,Math.SQRT1_2]:[0,0,0,1];const conversion=composeTransform({position:[0,0,0],rotation,scale:[options.metersPerUnit,options.metersPerUnit,options.metersPerUnit]});const matrices=new Map;for(const index2 of state.order){const node=document.nodes[index2],overrides=animated.get(index2);const local=overrides?nodeTransform({...node,...overrides},`nodes.${index2}`):nodeTransform(node,`nodes.${index2}`);const parent=state.parents[index2];matrices.set(index2,multiplyTransforms(parent===null?conversion:matrices.get(parent),local))}return safeMatrix(matrices.get(jointNodeIndex),"jointWorldMatrix")}}function combineBounds(bounds){const min=[Infinity,Infinity,Infinity],max=[-Infinity,-Infinity,-Infinity];for(const bound of bounds)for(let axis=0;axis<3;axis++){min[axis]=Math.min(min[axis],bound.min[axis]);max[axis]=Math.max(max[axis],bound.max[axis])}return deepFreezeJson({min,max})}function deformPrimitive(primitive,morphWeights,skin,nodeWorld,nodeMatrices){const positions=applyMorphWeights(primitive.positions,primitive.morphTargets.map((target)=>target.positionDeltas),morphWeights);let normals;if(primitive.normals!==undefined){const morphed=applyMorphWeights(primitive.normals,primitive.morphTargets.map((target)=>target.normalDeltas),morphWeights);normals=normalizeVectors(morphed)}if(skin===undefined){const bounds2=transformVertexBounds(positions,primitive.indices,nodeWorld);return normals===undefined?{positions,bounds:bounds2}:{positions,normals,bounds:bounds2}}const deformedPositions=[],deformedNormals=[];const hasNormals=normals!==undefined,meshInverse=invertTransform(nodeWorld);for(let vertex=0;vertex<positions.length/3;vertex++){const skinMatrix=computeSkinMatrix(vertex,primitive,skin,nodeMatrices,meshInverse);const position=transformPoint(skinMatrix,[positions[vertex*3],positions[vertex*3+1],positions[vertex*3+2]]);deformedPositions.push(position[0],position[1],position[2]);if(hasNormals){const n=transformNormal(skinMatrix,[normals[vertex*3],normals[vertex*3+1],normals[vertex*3+2]]);const len=Math.hypot(n[0],n[1],n[2]);deformedNormals.push(len===0?0:n[0]/len,len===0?0:n[1]/len,len===0?0:n[2]/len)}}const frozenPositions=Object.freeze(deformedPositions),bounds=transformVertexBounds(frozenPositions,primitive.indices,nodeWorld);return hasNormals?{positions:frozenPositions,normals:Object.freeze(deformedNormals),bounds}:{positions:frozenPositions,bounds}}function applyMorphWeights(base,deltas,weights){if(deltas.length===0||weights.length===0)return base;const out=base.slice();for(let target=0;target<deltas.length;target++){const weight=weights[target]??0;if(weight===0||deltas[target]===undefined)continue;const delta=deltas[target];for(let index2=0;index2<out.length;index2++)out[index2]=out[index2]+weight*(delta[index2]??0)}return Object.freeze(out)}function normalizeVectors(values2){const out=[];for(let index2=0;index2<values2.length;index2+=3){const len=Math.hypot(values2[index2],values2[index2+1],values2[index2+2]);out.push(len===0?0:values2[index2]/len,len===0?0:values2[index2+1]/len,len===0?0:values2[index2+2]/len)}return Object.freeze(out)}function transformNormal(matrix2,normal){const inverse=invertTransform(matrix2);return[inverse[0]*normal[0]+inverse[1]*normal[1]+inverse[2]*normal[2],inverse[4]*normal[0]+inverse[5]*normal[1]+inverse[6]*normal[2],inverse[8]*normal[0]+inverse[9]*normal[1]+inverse[10]*normal[2]]}function transformVertexBounds(positions,indices,matrix2){const low=[Infinity,Infinity,Infinity],high=[-Infinity,-Infinity,-Infinity];const count=indices?.length??positions.length/3;for(let index2=0;index2<count;index2++){const offset=(indices?.[index2]??index2)*3;const point=transformPoint(matrix2,[positions[offset],positions[offset+1],positions[offset+2]]);for(let axis=0;axis<3;axis++){low[axis]=Math.min(low[axis],point[axis]);high[axis]=Math.max(high[axis],point[axis])}}return deepFreezeJson({min:low,max:high})}function computeSkinMatrix(vertex,primitive,skin,nodeMatrices,meshInverse){const jointIndices=primitive.jointIndices;const jointWeights=primitive.jointWeights;const entries=new Array(16).fill(0);for(let influence=0;influence<4;influence++){const weight=jointWeights[vertex*4+influence];if(weight===0)continue;const jointNode=skin.joints[jointIndices[vertex*4+influence]];const jointWorld=nodeMatrices.get(jointNode);if(jointWorld===undefined)fail(`Joint node ${jointNode} missing from hierarchy.`,"skin");const matrixIndex=skin.matrixIndexByJointNode.get(jointNode);if(matrixIndex===undefined)fail(`Joint node ${jointNode} is not in skin joints.`,"skin");const inverseBindMatrix=skin.inverseBindMatrices.slice(matrixIndex*16,matrixIndex*16+16);const jointMatrix=multiplyTransforms(meshInverse,multiplyTransforms(jointWorld,inverseBindMatrix));for(let entry=0;entry<16;entry++)entries[entry]=entries[entry]+weight*jointMatrix[entry]}entries[15]=1;return Object.freeze(entries)}function parseSpatialGlb(bytes){return SpatialGlbModel.parse(bytes)}function evaluateSpatialGlb(model,options){if(!(model instanceof SpatialGlbModel))fail("Evaluation requires a parsed GLB model.");return model.evaluate(options)}function spatialGlbBounds(model){return evaluateSpatialGlb(model,{metersPerUnit:1,sourceUp:"y",timeUs:0}).bounds}import{z as z4}from"zod";var SPATIAL_GEOMETRY_LIMITS=Object.freeze({nodes:128,depth:32,profilePoints:512,pathPoints:256,mergeInputs:64,arrayCount:512,arcSegments:256,booleanPlanes:64,booleanInputTriangles:4096,vertices:65536,triangles:1e5,materialSlots:16,outputBytes:33554432,coordinate:1e6});var SPATIAL_GEOMETRY_GRAPH_KIND="slopcamera.spatial-geometry-graph";var SPATIAL_GEOMETRY_PROFILE="slopcamera.parametric-geometry-v1";var finite2=z4.number().finite().min(-SPATIAL_GEOMETRY_LIMITS.coordinate).max(SPATIAL_GEOMETRY_LIMITS.coordinate);var positive=z4.number().finite().min(0.000000001).max(SPATIAL_GEOMETRY_LIMITS.coordinate);var segments=z4.number().int().min(3).max(SPATIAL_GEOMETRY_LIMITS.arcSegments);var vec22=z4.tuple([finite2,finite2]);var vec33=z4.tuple([finite2,finite2,finite2]);var nodeId=z4.string().min(1).max(64).regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/u,"Geometry node ids must be safe identifiers.");var materialSlot=z4.number().int().min(0).max(SPATIAL_GEOMETRY_LIMITS.materialSlots-1);var axis=z4.enum(["x","y","z"]);var SpatialGeometryNodeSchema=z4.discriminatedUnion("kind",[z4.strictObject({id:nodeId,kind:z4.literal("profile"),points:z4.array(vec22).min(3).max(SPATIAL_GEOMETRY_LIMITS.profilePoints)}),z4.strictObject({id:nodeId,kind:z4.literal("rect"),width:positive,height:positive}),z4.strictObject({id:nodeId,kind:z4.literal("ellipse"),radiusX:positive,radiusY:positive,segments}),z4.strictObject({id:nodeId,kind:z4.literal("inset"),input:nodeId,distance:positive}),z4.strictObject({id:nodeId,kind:z4.literal("bevel"),input:nodeId,radius:positive,segments:z4.number().int().min(1).max(64)}),z4.strictObject({id:nodeId,kind:z4.literal("box"),size:z4.tuple([positive,positive,positive])}),z4.strictObject({id:nodeId,kind:z4.literal("cylinder"),radius:positive,height:positive,segments}),z4.strictObject({id:nodeId,kind:z4.literal("sphere"),radius:positive,segments:z4.number().int().min(4).max(SPATIAL_GEOMETRY_LIMITS.arcSegments)}),z4.strictObject({id:nodeId,kind:z4.literal("extrude"),profile:nodeId,depth:positive,sideSlot:materialSlot.optional(),capSlot:materialSlot.optional()}),z4.strictObject({id:nodeId,kind:z4.literal("revolve"),profile:nodeId,segments,capSlot:materialSlot.optional()}),z4.strictObject({id:nodeId,kind:z4.literal("sweep"),profile:nodeId,path:z4.array(vec33).min(2).max(SPATIAL_GEOMETRY_LIMITS.pathPoints)}),z4.strictObject({id:nodeId,kind:z4.literal("loft"),bottom:nodeId,top:nodeId,height:positive}),z4.strictObject({id:nodeId,kind:z4.literal("transform"),input:nodeId,transform:SpatialTransformSchema}),z4.strictObject({id:nodeId,kind:z4.literal("mirror"),input:nodeId,axis,offset:finite2}),z4.strictObject({id:nodeId,kind:z4.literal("array"),input:nodeId,count:z4.number().int().min(1).max(SPATIAL_GEOMETRY_LIMITS.arrayCount),step:vec33}),z4.strictObject({id:nodeId,kind:z4.literal("merge"),inputs:z4.array(nodeId).min(2).max(SPATIAL_GEOMETRY_LIMITS.mergeInputs)}),z4.discriminatedUnion("operation",[z4.strictObject({id:nodeId,kind:z4.literal("boolean"),operation:z4.literal("difference"),a:nodeId,cutters:z4.array(nodeId).min(1).max(16)}),z4.strictObject({id:nodeId,kind:z4.literal("boolean"),operation:z4.enum(["union","intersection"]),a:nodeId,b:nodeId})]),z4.strictObject({id:nodeId,kind:z4.literal("material-slot"),input:nodeId,slot:materialSlot}),z4.strictObject({id:nodeId,kind:z4.literal("uv-project"),input:nodeId,projection:z4.discriminatedUnion("mode",[z4.strictObject({mode:z4.literal("box"),scale:positive}),z4.strictObject({mode:z4.literal("planar"),axis,scale:positive,offset:vec22.optional()}),z4.strictObject({mode:z4.literal("cylindrical"),axis,scale:positive})])})]);var SpatialGeometryGraphSchema=z4.strictObject({kind:z4.literal(SPATIAL_GEOMETRY_GRAPH_KIND),schemaVersion:z4.literal(1),nodes:z4.array(SpatialGeometryNodeSchema).min(1).max(SPATIAL_GEOMETRY_LIMITS.nodes),output:nodeId});function fail2(message,path="geometry"){throw new SpatialSceneError("invalid-data",`${SPATIAL_GEOMETRY_PROFILE}: ${message}`,path)}function polygonArea(points){let area=0;for(let index2=0;index2<points.length;index2++){const a=points[index2],b=points[(index2+1)%points.length];area+=a[0]*b[1]-b[0]*a[1]}return area/2}function segmentsCross(a1,a2,b1,b2){const cross=(o,p,q)=>(p[0]-o[0])*(q[1]-o[1])-(p[1]-o[1])*(q[0]-o[0]);const d1=cross(b1,b2,a1),d2=cross(b1,b2,a2),d3=cross(a1,a2,b1),d4=cross(a1,a2,b2);return(d1>0&&d2<0||d1<0&&d2>0)&&(d3>0&&d4<0||d3<0&&d4>0)}function pointOnSegment(p,a,b){const cross=(b[0]-a[0])*(p[1]-a[1])-(b[1]-a[1])*(p[0]-a[0]);const scale=Math.hypot(b[0]-a[0],b[1]-a[1])+0.000000000001;if(Math.abs(cross)>0.000000001*scale)return false;return(p[0]-a[0])*(b[0]-a[0])+(p[1]-a[1])*(b[1]-a[1])>=-0.000000000001&&(p[0]-b[0])*(a[0]-b[0])+(p[1]-b[1])*(a[1]-b[1])>=-0.000000000001}function polygonIsSimple(points){const count=points.length;for(let edge=0;edge<count;edge++){const a1=points[edge],a2=points[(edge+1)%count];for(let other=edge+1;other<count;other++){if(other===edge||(other+1)%count===edge||(edge+1)%count===other)continue;const b1=points[other],b2=points[(other+1)%count];if(segmentsCross(a1,a2,b1,b2))return false;if(pointOnSegment(a1,b1,b2)||pointOnSegment(a2,b1,b2)||pointOnSegment(b1,a1,a2))return false}}return true}function checkedProfile(points,path){if(points.length<3||points.length>SPATIAL_GEOMETRY_LIMITS.profilePoints)fail2("Profile requires 3\u2013512 points.",path);const area=polygonArea(points);if(!Number.isFinite(area)||Math.abs(area)<0.000000000001)fail2("Profile polygon is degenerate or collinear.",path);const ccw=area>0?[...points]:[...points].reverse();if(!polygonIsSimple(ccw))fail2("Profile polygon must be simple (no self-intersections).",path);return Object.freeze(ccw)}function unit22(x,y){const length=Math.hypot(x,y);return length===0?[0,0]:[x/length,y/length]}function insetProfile(points,distance,path){const count=points.length;const out=[];for(let index2=0;index2<count;index2++){const prev=points[(index2-1+count)%count],vertex=points[index2],next=points[(index2+1)%count];const e1=unit22(vertex[0]-prev[0],vertex[1]-prev[1]);const e2=unit22(next[0]-vertex[0],next[1]-vertex[1]);const n1=[-e1[1],e1[0]],n2=[-e2[1],e2[0]];const a1=[prev[0]+n1[0]*distance,prev[1]+n1[1]*distance];const b1=[vertex[0]+n2[0]*distance,vertex[1]+n2[1]*distance];const denominator=e1[0]*e2[1]-e1[1]*e2[0];if(Math.abs(denominator)<0.000000000001){out.push([vertex[0]+(n1[0]+n2[0])/2*distance,vertex[1]+(n1[1]+n2[1])/2*distance]);continue}const t=((b1[0]-a1[0])*e2[1]-(b1[1]-a1[1])*e2[0])/denominator;out.push([a1[0]+e1[0]*t,a1[1]+e1[1]*t])}return checkedProfile(out,path)}function bevelProfile(points,radius,arcSegments,path){const count=points.length;const out=[];for(let index2=0;index2<count;index2++){const prev=points[(index2-1+count)%count],vertex=points[index2],next=points[(index2+1)%count];const u=unit22(vertex[0]-prev[0],vertex[1]-prev[1]);const v=unit22(next[0]-vertex[0],next[1]-vertex[1]);const turn=u[0]*v[1]-u[1]*v[0];if(turn<=0.000000000001){out.push(vertex);continue}const cosInterior=Math.min(1,Math.max(-1,-(u[0]*v[0]+u[1]*v[1])));const interior=Math.PI-Math.acos(cosInterior);if(interior<=0.000000001){out.push(vertex);continue}const half=interior/2;const lenPrev=Math.hypot(vertex[0]-prev[0],vertex[1]-prev[1]);const lenNext=Math.hypot(next[0]-vertex[0],next[1]-vertex[1]);const tangent=Math.min(radius/Math.tan(half),lenPrev/2,lenNext/2);const effectiveRadius=tangent*Math.tan(half);const bisector=unit22(v[0]-u[0],v[1]-u[1]);const center=[vertex[0]+bisector[0]*effectiveRadius/Math.sin(half),vertex[1]+bisector[1]*effectiveRadius/Math.sin(half)];const touchA=[vertex[0]-u[0]*tangent,vertex[1]-u[1]*tangent];const touchB=[vertex[0]+v[0]*tangent,vertex[1]+v[1]*tangent];const start=Math.atan2(touchA[1]-center[1],touchA[0]-center[0]);let end=Math.atan2(touchB[1]-center[1],touchB[0]-center[0]);while(end<=start)end+=2*Math.PI;out.push(touchA);for(let step=1;step<=arcSegments;step++){const angle=start+(end-start)*step/arcSegments;out.push([center[0]+effectiveRadius*Math.cos(angle),center[1]+effectiveRadius*Math.sin(angle)])}}if(out.length>SPATIAL_GEOMETRY_LIMITS.profilePoints)fail2("Bevel expands the profile beyond the point budget.",path);return checkedProfile(out,path)}function builder(){return{positions:[],normals:[],uvs:[],indices:[],slots:[],uvsSet:false}}function vertex(b,position,normal,uv=[0,0]){const index2=b.positions.length/3;b.positions.push(position[0],position[1],position[2]);b.normals.push(normal[0],normal[1],normal[2]);b.uvs.push(uv[0],uv[1]);return index2}var DEGENERATE_AREA2=0.00000000000000000001;function triangle(b,a,c,d,slot){const pa=a*3,pb=c*3,pc=d*3;const ux=b.positions[pb]-b.positions[pa],uy=b.positions[pb+1]-b.positions[pa+1],uz=b.positions[pb+2]-b.positions[pa+2];const vx=b.positions[pc]-b.positions[pa],vy=b.positions[pc+1]-b.positions[pa+1],vz=b.positions[pc+2]-b.positions[pa+2];const cx=uy*vz-uz*vy,cy=uz*vx-ux*vz,cz=ux*vy-uy*vx;if(cx*cx+cy*cy+cz*cz<DEGENERATE_AREA2)return;b.indices.push(a,c,d);b.slots.push(slot)}function triangulate(points,path){const remaining=points.map((_,index2)=>index2);const indices=[];let guard=0;while(remaining.length>3&&++guard<=points.length*points.length){let clipped=false;for(let index2=0;index2<remaining.length;index2++){const ia=remaining[(index2-1+remaining.length)%remaining.length];const ib=remaining[index2];const ic=remaining[(index2+1)%remaining.length];const a=points[ia],b=points[ib],c=points[ic];const cross=(b[0]-a[0])*(c[1]-a[1])-(b[1]-a[1])*(c[0]-a[0]);if(cross<=0.00000000000001)continue;let empty=true;for(const other of remaining){if(other===ia||other===ib||other===ic)continue;const p=points[other];const d1=(b[0]-a[0])*(p[1]-a[1])-(b[1]-a[1])*(p[0]-a[0]);const d2=(c[0]-b[0])*(p[1]-b[1])-(c[1]-b[1])*(p[0]-b[0]);const d3=(a[0]-c[0])*(p[1]-c[1])-(a[1]-c[1])*(p[0]-c[0]);if(d1>=-0.00000000000001&&d2>=-0.00000000000001&&d3>=-0.00000000000001){empty=false;break}}if(empty){indices.push(ia,ib,ic);remaining.splice(index2,1);clipped=true;break}}if(!clipped)fail2("Profile triangulation failed; polygon must be simple.",path)}if(remaining.length===3)indices.push(remaining[0],remaining[1],remaining[2]);return indices}function signedVolume(b){let volume=0;for(let index2=0;index2<b.indices.length;index2+=3){const a=b.indices[index2]*3,c=b.indices[index2+1]*3,d=b.indices[index2+2]*3;const ax=b.positions[a],ay=b.positions[a+1],az=b.positions[a+2];const bx=b.positions[c],by=b.positions[c+1],bz=b.positions[c+2];const cx=b.positions[d],cy=b.positions[d+1],cz=b.positions[d+2];volume+=(ax*(by*cz-bz*cy)+ay*(bz*cx-bx*cz)+az*(bx*cy-by*cx))/6}return volume}function orientOutward(b){if(b.indices.length===0||signedVolume(b)>=0)return;for(let index2=0;index2<b.indices.length;index2+=3){const swap=b.indices[index2+1];b.indices[index2+1]=b.indices[index2+2];b.indices[index2+2]=swap}for(let index2=0;index2<b.normals.length;index2++)b.normals[index2]=-b.normals[index2]}function freezeMesh(b){const low=[Infinity,Infinity,Infinity],high=[-Infinity,-Infinity,-Infinity];for(let index2=0;index2<b.positions.length;index2+=3){for(let axisIndex=0;axisIndex<3;axisIndex++){const value=b.positions[index2+axisIndex];if(!Number.isFinite(value)||Math.abs(value)>SPATIAL_GEOMETRY_LIMITS.coordinate)fail2("Evaluated geometry exceeds the coordinate bound.");low[axisIndex]=Math.min(low[axisIndex],value);high[axisIndex]=Math.max(high[axisIndex],value)}}if(b.positions.length===0)fail2("Evaluated geometry produced no vertices.");const triangles=b.indices.length/3;return deepFreezeJson({positions:Object.freeze(b.positions),normals:Object.freeze(b.normals),uvs:Object.freeze(b.uvs),indices:Object.freeze(b.indices),slots:Object.freeze(b.slots),bounds:{min:Object.freeze(low),max:Object.freeze(high)},vertices:b.positions.length/3,triangles,uvsProjected:b.uvsSet})}function boxMesh(size){const b=builder();const[hx,hy,hz]=[size[0]/2,size[1]/2,size[2]/2];const faces=[[[1,0,0],[hx,-hy,-hz],[hx,hy,-hz],[hx,hy,hz],[hx,-hy,hz]],[[-1,0,0],[-hx,-hy,hz],[-hx,hy,hz],[-hx,hy,-hz],[-hx,-hy,-hz]],[[0,1,0],[-hx,hy,-hz],[-hx,hy,hz],[hx,hy,hz],[hx,hy,-hz]],[[0,-1,0],[-hx,-hy,hz],[-hx,-hy,-hz],[hx,-hy,-hz],[hx,-hy,hz]],[[0,0,1],[-hx,-hy,hz],[hx,-hy,hz],[hx,hy,hz],[-hx,hy,hz]],[[0,0,-1],[hx,-hy,-hz],[-hx,-hy,-hz],[-hx,hy,-hz],[hx,hy,-hz]]];for(const[normal,...corners]of faces){const uv=[[0,0],[1,0],[1,1],[0,1]];const base=corners.map((corner,index2)=>vertex(b,corner,normal,uv[index2]));triangle(b,base[0],base[1],base[2],0);triangle(b,base[0],base[2],base[3],0)}return b}function cylinderMesh(radius,height,seg){const b=builder(),half=height/2;for(let index2=0;index2<=seg;index2++){const angle=2*Math.PI*index2/seg,c=Math.cos(angle),s=Math.sin(angle);vertex(b,[radius*c,-half,radius*s],[c,0,s],[index2/seg,0]);vertex(b,[radius*c,half,radius*s],[c,0,s],[index2/seg,1])}for(let index2=0;index2<seg;index2++){const a=index2*2,c=index2*2+2;triangle(b,a,a+1,c+1,0);triangle(b,a,c+1,c,0)}for(const[y,normal]of[[half,1],[-half,-1]]){const center=vertex(b,[0,y,0],[0,normal,0],[0.5,0.5]);const ring=[];for(let index2=0;index2<=seg;index2++){const angle=2*Math.PI*index2/seg;ring.push(vertex(b,[radius*Math.cos(angle),y,radius*Math.sin(angle)],[0,normal,0],[0.5+0.5*Math.cos(angle),0.5+0.5*Math.sin(angle)]))}for(let index2=0;index2<seg;index2++){if(normal===1)triangle(b,center,ring[index2+1],ring[index2],0);else triangle(b,center,ring[index2],ring[index2+1],0)}}return b}function sphereMesh(radius,seg){const b=builder(),latitudes=Math.max(2,Math.floor(seg/2));const top=vertex(b,[0,radius,0],[0,1,0],[0.5,1]);const rings=[];for(let lat=1;lat<latitudes;lat++){const phi=Math.PI/2-Math.PI*lat/latitudes,y=radius*Math.sin(phi),ringRadius=radius*Math.cos(phi);const ring=[];for(let index2=0;index2<=seg;index2++){const angle=2*Math.PI*index2/seg;const position=[ringRadius*Math.cos(angle),y,ringRadius*Math.sin(angle)];ring.push(vertex(b,position,[position[0]/radius,position[1]/radius,position[2]/radius],[index2/seg,lat/latitudes]))}rings.push(ring)}const bottom=vertex(b,[0,-radius,0],[0,-1,0],[0.5,0]);for(let index2=0;index2<seg;index2++){triangle(b,top,rings[0][index2+1],rings[0][index2],0);triangle(b,bottom,rings[rings.length-1][index2],rings[rings.length-1][index2+1],0)}for(let lat=0;lat+1<rings.length;lat++){for(let index2=0;index2<seg;index2++){const a=rings[lat][index2],c=rings[lat][index2+1],d=rings[lat+1][index2],e=rings[lat+1][index2+1];triangle(b,a,c,e,0);triangle(b,a,e,d,0)}}return b}function extrudeMesh(profile,depth,sideSlot,capSlot,path){const b=builder(),half=depth/2,count=profile.length;const tris=triangulate(profile,path);const front=profile.map(([x,y])=>vertex(b,[x,y,half],[0,0,1],[x,y]));const back=profile.map(([x,y])=>vertex(b,[x,y,-half],[0,0,-1],[x,y]));for(let index2=0;index2<tris.length;index2+=3){triangle(b,front[tris[index2]],front[tris[index2+1]],front[tris[index2+2]],capSlot);triangle(b,back[tris[index2]],back[tris[index2+2]],back[tris[index2+1]],capSlot)}let perimeter=0;const lengths=profile.map((point,index2)=>{const next=profile[(index2+1)%count];const length=Math.hypot(next[0]-point[0],next[1]-point[1]);perimeter+=length;return length});let distance=0;for(let index2=0;index2<count;index2++){const a=profile[index2],c=profile[(index2+1)%count];const edge=unit22(c[0]-a[0],c[1]-a[1]);const normal=[edge[1],-edge[0],0];const u0=perimeter===0?0:distance/perimeter;distance+=lengths[index2];const u1=perimeter===0?0:distance/perimeter;const v0=vertex(b,[a[0],a[1],-half],normal,[u0,0]);const v1=vertex(b,[c[0],c[1],-half],normal,[u1,0]);const v2=vertex(b,[c[0],c[1],half],normal,[u1,1]);const v3=vertex(b,[a[0],a[1],half],normal,[u0,1]);triangle(b,v0,v1,v2,sideSlot);triangle(b,v0,v2,v3,sideSlot)}orientOutward(b);return b}function revolveMesh(profile,seg,capSlot,path){const b=builder(),count=profile.length;if(profile.some(([r])=>r<-0.000000000001))fail2("Revolve profiles must stay at nonnegative radius.",path);const rings=[];for(let point=0;point<count;point++){const[r,y]=profile[point];const prev=profile[(point-1+count)%count],next=profile[(point+1)%count];const tangent=unit22(next[0]-prev[0],next[1]-prev[1]);const outward=unit22(tangent[1],-tangent[0]);const ring=[];for(let index2=0;index2<=seg;index2++){const angle=2*Math.PI*index2/seg,c=Math.cos(angle),s=Math.sin(angle);ring.push(vertex(b,[r*c,y,r*s],[outward[0]*c,outward[1],outward[0]*s],[index2/seg,point/(count-1)]))}rings.push(ring)}for(let point=0;point<count;point++){const next=(point+1)%count;for(let index2=0;index2<seg;index2++){const a=rings[point][index2],c=rings[point][index2+1],d=rings[next][index2],e=rings[next][index2+1];triangle(b,a,d,e,capSlot);triangle(b,a,e,c,capSlot)}}orientOutward(b);return b}function sweepMesh(profile,path,slotPath){const b=builder(),count=profile.length;const points=path.map((point)=>[point[0],point[1],point[2]]);for(let index2=0;index2+1<points.length;index2++){const a=points[index2],c=points[index2+1];if(Math.hypot(c[0]-a[0],c[1]-a[1],c[2]-a[2])<0.000000001)fail2("Sweep path requires distinct consecutive points.",slotPath)}const tangents=points.map((_,index2)=>{const a=points[Math.max(0,index2-1)],c=points[Math.min(points.length-1,index2+1)];const length=Math.hypot(c[0]-a[0],c[1]-a[1],c[2]-a[2]);return[(c[0]-a[0])/length,(c[1]-a[1])/length,(c[2]-a[2])/length]});let normal=Math.abs(tangents[0][1])<0.9?[0,1,0]:[1,0,0];const rings=[];for(let station=0;station<points.length;station++){const t=tangents[station];const projected=[normal[0]-t[0]*(normal[0]*t[0]+normal[1]*t[1]+normal[2]*t[2]),normal[1]-t[1]*(normal[0]*t[0]+normal[1]*t[1]+normal[2]*t[2]),normal[2]-t[2]*(normal[0]*t[0]+normal[1]*t[1]+normal[2]*t[2])];const nLength=Math.hypot(...projected);if(nLength<0.000000001)fail2("Sweep path curvature degenerates the transport frame.",slotPath);normal=[projected[0]/nLength,projected[1]/nLength,projected[2]/nLength];const binormal=[t[1]*normal[2]-t[2]*normal[1],t[2]*normal[0]-t[0]*normal[2],t[0]*normal[1]-t[1]*normal[0]];const ring=[];const center=points[station];for(let point=0;point<count;point++){const prev=profile[(point-1+count)%count],next=profile[(point+1)%count];const tangent2=unit22(next[0]-prev[0],next[1]-prev[1]);const outward=unit22(tangent2[1],-tangent2[0]);const[px,py]=profile[point];ring.push(vertex(b,[center[0]+normal[0]*px+binormal[0]*py,center[1]+normal[1]*px+binormal[1]*py,center[2]+normal[2]*px+binormal[2]*py],[normal[0]*outward[0]+binormal[0]*outward[1],normal[1]*outward[0]+binormal[1]*outward[1],normal[2]*outward[0]+binormal[2]*outward[1]],[point/count,station/(points.length-1)]))}rings.push(ring)}for(let station=0;station+1<rings.length;station++){for(let point=0;point<count;point++){const next=(point+1)%count;const a=rings[station][point],c=rings[station][next],d=rings[station+1][point],e=rings[station+1][next];triangle(b,a,c,e,0);triangle(b,a,e,d,0)}}const tris=triangulate(profile,slotPath);for(const[station,direction]of[[0,-1],[points.length-1,1]]){const t=tangents[station];const capNormal=[t[0]*direction,t[1]*direction,t[2]*direction];const positions=rings[station].map((index2)=>b.positions.slice(index2*3,index2*3+3));const cap=positions.map((position)=>vertex(b,position,capNormal));const pa=positions[tris[0]],pb=positions[tris[1]],pc=positions[tris[2]];const cx=(pb[1]-pa[1])*(pc[2]-pa[2])-(pb[2]-pa[2])*(pc[1]-pa[1]);const cy=(pb[2]-pa[2])*(pc[0]-pa[0])-(pb[0]-pa[0])*(pc[2]-pa[2]);const cz=(pb[0]-pa[0])*(pc[1]-pa[1])-(pb[1]-pa[1])*(pc[0]-pa[0]);const flip=cx*capNormal[0]+cy*capNormal[1]+cz*capNormal[2]<0;for(let index2=0;index2<tris.length;index2+=3){if(flip)triangle(b,cap[tris[index2]],cap[tris[index2+2]],cap[tris[index2+1]],0);else triangle(b,cap[tris[index2]],cap[tris[index2+1]],cap[tris[index2+2]],0)}}orientOutward(b);return b}function loftMesh(bottom,top,height,path){const b=builder(),count=bottom.length;if(top.length!==count)fail2("Loft profiles must share one point count.",path);const lower=bottom.map(([x,y])=>vertex(b,[x,0,y],[0,-1,0],[x,y]));const upper=top.map(([x,y])=>vertex(b,[x,height,y],[0,1,0],[x,y]));for(const[tris,ring,flip]of[[triangulate(bottom,path),lower,true],[triangulate(top,path),upper,false]]){for(let index2=0;index2<tris.length;index2+=3){if(flip)triangle(b,ring[tris[index2]],ring[tris[index2+2]],ring[tris[index2+1]],0);else triangle(b,ring[tris[index2]],ring[tris[index2+1]],ring[tris[index2+2]],0)}}const centroid=bottom.reduce((acc,point)=>[acc[0]+point[0]/count,acc[1]+point[1]/count],[0,0]);for(let index2=0;index2<count;index2++){const next=(index2+1)%count;const a=bottom[index2],c=bottom[next],d=top[index2],e=top[next];const ux=c[0]-a[0],uz=c[1]-a[1];const wx=d[0]-a[0],wy=height,wz=d[1]-a[1];let nx=-(uz*wy),ny=uz*wx-ux*wz,nz=ux*wy;const midX=(a[0]+c[0]+d[0]+e[0])/4-centroid[0],midZ=(a[1]+c[1]+d[1]+e[1])/4-centroid[1];const inward=nx*midX+nz*midZ<0;if(inward){nx=-nx;ny=-ny;nz=-nz}const nLength=Math.hypot(nx,ny,nz)||1;const normal=[nx/nLength,ny/nLength,nz/nLength];const v0=vertex(b,[a[0],0,a[1]],normal),v1=vertex(b,[c[0],0,c[1]],normal);const v2=vertex(b,[e[0],height,e[1]],normal),v3=vertex(b,[d[0],height,d[1]],normal);if(inward){triangle(b,v0,v3,v2,0);triangle(b,v0,v2,v1,0)}else{triangle(b,v0,v1,v2,0);triangle(b,v0,v2,v3,0)}}orientOutward(b);return b}function transformMesh(input,transform){const b=builder();const matrix2=composeTransform(transform);const inverse=invertTransform(matrix2);for(let index2=0;index2<input.positions.length;index2+=3){const position=transformPoint(matrix2,[input.positions[index2],input.positions[index2+1],input.positions[index2+2]]);const n0=input.normals[index2],n1=input.normals[index2+1],n2=input.normals[index2+2];const normal=[inverse[0]*n0+inverse[1]*n1+inverse[2]*n2,inverse[4]*n0+inverse[5]*n1+inverse[6]*n2,inverse[8]*n0+inverse[9]*n1+inverse[10]*n2];const length=Math.hypot(normal[0],normal[1],normal[2])||1;vertex(b,position,[normal[0]/length,normal[1]/length,normal[2]/length],[input.uvs[index2/3*2],input.uvs[index2/3*2+1]])}b.indices.push(...input.indices);b.slots.push(...input.slots);b.uvsSet=input.uvsSet;return b}function mirrorMesh(input,axisIndex,offset){const b=builder();for(let index2=0;index2<input.positions.length;index2+=3){const position=[input.positions[index2],input.positions[index2+1],input.positions[index2+2]];const normal=[input.normals[index2],input.normals[index2+1],input.normals[index2+2]];position[axisIndex]=2*offset-position[axisIndex];normal[axisIndex]=-normal[axisIndex];vertex(b,position,normal,[input.uvs[index2/3*2],input.uvs[index2/3*2+1]])}for(let index2=0;index2<input.indices.length;index2+=3){triangle(b,input.indices[index2],input.indices[index2+2],input.indices[index2+1],input.slots[index2/3])}b.uvsSet=input.uvsSet;return b}function arrayMesh(input,count,step){const b=builder(),vertices=input.positions.length/3;for(let copy=0;copy<count;copy++){const offset=[copy*step[0],copy*step[1],copy*step[2]];for(let index2=0;index2<input.positions.length;index2+=3){vertex(b,[input.positions[index2]+offset[0],input.positions[index2+1]+offset[1],input.positions[index2+2]+offset[2]],[input.normals[index2],input.normals[index2+1],input.normals[index2+2]],[input.uvs[index2/3*2],input.uvs[index2/3*2+1]])}for(let index2=0;index2<input.indices.length;index2+=3){triangle(b,input.indices[index2]+copy*vertices,input.indices[index2+1]+copy*vertices,input.indices[index2+2]+copy*vertices,input.slots[index2/3])}}b.uvsSet=input.uvsSet;return b}function mergeMeshes(inputs){const b=builder();for(const input of inputs){const base=input.positions.length===0?0:b.positions.length/3;for(let index2=0;index2<input.positions.length;index2+=3){vertex(b,[input.positions[index2],input.positions[index2+1],input.positions[index2+2]],[input.normals[index2],input.normals[index2+1],input.normals[index2+2]],[input.uvs[index2/3*2],input.uvs[index2/3*2+1]])}for(let index2=0;index2<input.indices.length;index2+=3){b.indices.push(input.indices[index2]+base,input.indices[index2+1]+base,input.indices[index2+2]+base);b.slots.push(input.slots[index2/3])}b.uvsSet=b.uvsSet||input.uvsSet}return b}var PLANE_EPS=0.000000001;function trianglePlane(b,index2){const a=b.indices[index2]*3,c=b.indices[index2+1]*3,d=b.indices[index2+2]*3;const ux=b.positions[c]-b.positions[a],uy=b.positions[c+1]-b.positions[a+1],uz=b.positions[c+2]-b.positions[a+2];const vx=b.positions[d]-b.positions[a],vy=b.positions[d+1]-b.positions[a+1],vz=b.positions[d+2]-b.positions[a+2];const nx=uy*vz-uz*vy,ny=uz*vx-ux*vz,nz=ux*vy-uy*vx;const length=Math.hypot(nx,ny,nz);if(length<0.000000000001)return null;const normal=[nx/length,ny/length,nz/length];return{normal,d:normal[0]*b.positions[a]+normal[1]*b.positions[a+1]+normal[2]*b.positions[a+2]}}function uniquePlanes(b,path){const planes=[];for(let index2=0;index2<b.indices.length;index2+=3){const plane=trianglePlane(b,index2);if(plane===null)continue;if(!planes.some((other)=>Math.abs(other.d-plane.d)<0.0000001&&Math.abs(other.normal[0]-plane.normal[0])<0.0000001&&Math.abs(other.normal[1]-plane.normal[1])<0.0000001&&Math.abs(other.normal[2]-plane.normal[2])<0.0000001))planes.push(plane);if(planes.length>SPATIAL_GEOMETRY_LIMITS.booleanPlanes)fail2("Hull boolean inputs may carry at most 64 support planes.",path)}return Object.freeze(planes)}function assertHull(b,planes,path){let extent=1;for(let index2=0;index2<b.positions.length;index2++)extent=Math.max(extent,Math.abs(b.positions[index2]));const epsilon=0.0000001*extent;for(const plane of planes){for(let index2=0;index2<b.positions.length;index2+=3){const signed=plane.normal[0]*b.positions[index2]+plane.normal[1]*b.positions[index2+1]+plane.normal[2]*b.positions[index2+2]-plane.d;if(signed>epsilon)fail2("Boolean inputs must be closed hull meshes; a vertex lies outside a support plane.",path)}}}function clipFragment(fragment,plane,keepInside){const output=[],uvOut=[];const signed=fragment.positions.map((position)=>plane.normal[0]*position[0]+plane.normal[1]*position[1]+plane.normal[2]*position[2]-plane.d);const inside=signed.map((value)=>keepInside?value<=PLANE_EPS:value>=-PLANE_EPS);for(let index2=0;index2<fragment.positions.length;index2++){const next=(index2+1)%fragment.positions.length;const a=fragment.positions[index2],c=fragment.positions[next];if(inside[index2]){output.push(a);uvOut.push(fragment.uvs[index2])}if(inside[index2]!==inside[next]){const t=signed[index2]/(signed[index2]-signed[next]);output.push([a[0]+(c[0]-a[0])*t,a[1]+(c[1]-a[1])*t,a[2]+(c[2]-a[2])*t]);uvOut.push([fragment.uvs[index2][0]+(fragment.uvs[next][0]-fragment.uvs[index2][0])*t,fragment.uvs[index2][1]+(fragment.uvs[next][1]-fragment.uvs[index2][1])*t])}}return output.length>=3?{positions:output,uvs:uvOut,slot:fragment.slot}:null}function partitionTriangles(input,planes){const result=[];for(let index2=0;index2<input.indices.length;index2+=3){const positions=[0,1,2].map((part)=>input.positions.slice(input.indices[index2+part]*3,input.indices[index2+part]*3+3));const uvs=[0,1,2].map((part)=>[input.uvs[input.indices[index2+part]*2],input.uvs[input.indices[index2+part]*2+1]]);let fragments=[{positions,uvs,slot:input.slots[index2/3]}];for(const plane of planes){const next=[];for(const fragment of fragments){const inner=clipFragment(fragment,plane,true);const outer=clipFragment(fragment,plane,false);if(inner!==null)next.push(inner);if(outer!==null)next.push(outer)}fragments=next}result.push(...fragments)}return result}function fragmentInside(planes,fragment){const count=fragment.positions.length;const centroid=[fragment.positions.reduce((sum,p)=>sum+p[0],0)/count,fragment.positions.reduce((sum,p)=>sum+p[1],0)/count,fragment.positions.reduce((sum,p)=>sum+p[2],0)/count];return planes.every((plane)=>plane.normal[0]*centroid[0]+plane.normal[1]*centroid[1]+plane.normal[2]*centroid[2]-plane.d<=PLANE_EPS)}function emitFragments(b,fragments,flip){for(const fragment of fragments){let z5=0;for(let index2=0;index2<fragment.positions.length;index2++){const a=fragment.positions[index2],c=fragment.positions[(index2+1)%fragment.positions.length];z5+=a[0]*c[1]-a[1]*c[0]}const unit4=z5<0?[0,0,-1]:[0,0,1];const oriented=flip?[-unit4[0],-unit4[1],-unit4[2]]:unit4;const indices=fragment.positions.map((position,index2)=>vertex(b,position,oriented,fragment.uvs[index2]));for(let index2=1;index2+1<indices.length;index2++){if(flip)triangle(b,indices[0],indices[index2+1],indices[index2],fragment.slot);else triangle(b,indices[0],indices[index2],indices[index2+1],fragment.slot)}}}function booleanMesh(input,meshes,path){const a=meshes.get(input.a);const cutters=input.operation==="difference"?input.cutters.map((id)=>meshes.get(id)):[meshes.get(input.b)];for(const[index2,mesh]of[a,...cutters].entries()){if(mesh.indices.length/3>SPATIAL_GEOMETRY_LIMITS.booleanInputTriangles){fail2("Boolean inputs exceed the bounded simple-input triangle budget.",`${path}.${index2}`)}}const planesA=uniquePlanes(a,path);const planesC=cutters.map((cutter)=>uniquePlanes(cutter,path));assertHull(a,planesA,path);cutters.forEach((cutter,index2)=>assertHull(cutter,planesC[index2],path));const output=builder();if(input.operation==="difference"){const allCutterPlanes=planesC.flat();const kept=partitionTriangles(a,allCutterPlanes).filter((piece)=>!planesC.some((planes)=>fragmentInside(planes,piece)));emitFragments(output,kept,false);for(const[index2,cutter]of cutters.entries()){const caps=partitionTriangles(cutter,planesA).filter((piece)=>fragmentInside(planesA,piece)&&!planesC.some((other,otherIndex)=>otherIndex!==index2&&fragmentInside(other,piece)));emitFragments(output,caps,true)}}else{const planesB=planesC[0],b=cutters[0];const piecesA=partitionTriangles(a,planesB),piecesB=partitionTriangles(b,planesA);if(input.operation==="intersection"){emitFragments(output,piecesA.filter((piece)=>fragmentInside(planesB,piece)),false);emitFragments(output,piecesB.filter((piece)=>fragmentInside(planesA,piece)),false)}else{emitFragments(output,piecesA.filter((piece)=>!fragmentInside(planesB,piece)),false);emitFragments(output,piecesB.filter((piece)=>!fragmentInside(planesA,piece)),false)}}output.uvsSet=[a,...cutters].some((mesh)=>mesh.uvsSet);if(output.indices.length===0)fail2("Boolean result is empty; the inputs do not overlap as the operation requires.",path);orientOutward(output);return output}var AXIS_INDEX={x:0,y:1,z:2};function projectUvs(input,projection2){const b=builder();b.positions.push(...input.positions);b.normals.push(...input.normals);b.indices.push(...input.indices);b.slots.push(...input.slots);for(let index2=0;index2<input.positions.length;index2+=3){const p=[input.positions[index2],input.positions[index2+1],input.positions[index2+2]];const n=[input.normals[index2],input.normals[index2+1],input.normals[index2+2]];let uv;if(projection2.mode==="box"){const axisIndex=Math.abs(n[0])>=Math.abs(n[1])&&Math.abs(n[0])>=Math.abs(n[2])?0:Math.abs(n[1])>=Math.abs(n[2])?1:2;const pair=[0,1,2].filter((part)=>part!==axisIndex);uv=[p[pair[0]]*projection2.scale,p[pair[1]]*projection2.scale]}else if(projection2.mode==="planar"){const pair=[0,1,2].filter((part)=>part!==AXIS_INDEX[projection2.axis]);uv=[p[pair[0]]*projection2.scale+(projection2.offset?.[0]??0),p[pair[1]]*projection2.scale+(projection2.offset?.[1]??0)]}else{const axisIndex=AXIS_INDEX[projection2.axis];const pair=[0,1,2].filter((part)=>part!==axisIndex);uv=[Math.atan2(p[pair[1]],p[pair[0]])/(2*Math.PI)+0.5,p[axisIndex]*projection2.scale]}b.uvs.push(uv[0],uv[1])}b.uvsSet=true;return b}var PROFILE_KINDS=new Set(["profile","rect","ellipse","inset","bevel"]);function nodeDependencies(node){switch(node.kind){case"inset":case"bevel":case"transform":case"mirror":case"array":case"material-slot":case"uv-project":return[node.input];case"extrude":case"revolve":case"sweep":return[node.profile];case"loft":return[node.bottom,node.top];case"merge":return node.inputs;case"boolean":return node.operation==="difference"?[node.a,...node.cutters]:[node.a,node.b];default:return[]}}function parseSpatialGeometryGraph(input){const graph=parseSpatialValue(SpatialGeometryGraphSchema,input,"geometry graph");const nodesById=new Map;for(const node of graph.nodes){if(nodesById.has(node.id))fail2(`Duplicate geometry node ${node.id}.`,"geometry.nodes");nodesById.set(node.id,node)}for(const node of graph.nodes){for(const dependency of nodeDependencies(node)){const target=nodesById.get(dependency);if(target===undefined)fail2(`Geometry node ${node.id} references missing ${dependency}.`,`geometry.nodes.${node.id}`);const expectsProfile=node.kind==="inset"||node.kind==="bevel"||node.kind==="extrude"||node.kind==="revolve"||node.kind==="sweep"||node.kind==="loft";if(expectsProfile!==PROFILE_KINDS.has(target.kind)){fail2(`Geometry node ${node.id} wires a ${expectsProfile?"mesh":"profile"} output into a ${expectsProfile?"profile":"mesh"} input.`,`geometry.nodes.${node.id}`)}}}const order=spatialTopologicalIds(new Map(graph.nodes.map((node)=>[node.id,nodeDependencies(node)])),"geometry graph");const depth=new Map;for(const id of order){const node=nodesById.get(id);const value=1+Math.max(0,...nodeDependencies(node).map((dependency)=>depth.get(dependency)));if(value>SPATIAL_GEOMETRY_LIMITS.depth)fail2(`Geometry graph exceeds the ${SPATIAL_GEOMETRY_LIMITS.depth}-node evaluation depth bound.`,`geometry.nodes.${id}`);depth.set(id,value)}if(!nodesById.has(graph.output))fail2("Geometry output names a missing node.","geometry.output");if(PROFILE_KINDS.has(nodesById.get(graph.output).kind))fail2("Geometry output must evaluate to a mesh, not a profile.","geometry.output");return deepFreezeJson(graph)}function profileBounds(points){const xs=points.map((point)=>point[0]),ys=points.map((point)=>point[1]);return{min:[Math.min(...xs),Math.min(...ys),0],max:[Math.max(...xs),Math.max(...ys),0]}}function boundsUnion(a,b){return{min:[Math.min(a.min[0],b.min[0]),Math.min(a.min[1],b.min[1]),Math.min(a.min[2],b.min[2])],max:[Math.max(a.max[0],b.max[0]),Math.max(a.max[1],b.max[1]),Math.max(a.max[2],b.max[2])]}}function boundsOffset(bounds,delta){return{min:[bounds.min[0]+delta[0],bounds.min[1]+delta[1],bounds.min[2]+delta[2]],max:[bounds.max[0]+delta[0],bounds.max[1]+delta[1],bounds.max[2]+delta[2]]}}function inflateBounds(bounds,radius){return{min:[bounds.min[0]-radius,bounds.min[1]-radius,bounds.min[2]-radius],max:[bounds.max[0]+radius,bounds.max[1]+radius,bounds.max[2]+radius]}}function estimateNode(node,meshEstimates,profileEstimates,_path){const mesh=(id)=>meshEstimates.get(id);const profile=(id)=>profileEstimates.get(id);switch(node.kind){case"profile":return{points:node.points.length,bounds:profileBounds(node.points)};case"rect":return{points:4,bounds:{min:[-node.width/2,-node.height/2,0],max:[node.width/2,node.height/2,0]}};case"ellipse":return{points:node.segments,bounds:{min:[-node.radiusX,-node.radiusY,0],max:[node.radiusX,node.radiusY,0]}};case"inset":return{points:profile(node.input).points,bounds:profile(node.input).bounds};case"bevel":{const source=profile(node.input);return{points:source.points*(node.segments+1),bounds:source.bounds}}case"box":{const[x,y,z5]=[node.size[0]/2,node.size[1]/2,node.size[2]/2];return{vertices:24,triangles:12,planes:6,bounds:{min:[-x,-y,-z5],max:[x,y,z5]}}}case"cylinder":return{vertices:4*node.segments+6,triangles:4*node.segments,planes:node.segments+2,bounds:{min:[-node.radius,-node.height/2,-node.radius],max:[node.radius,node.height/2,node.radius]}};case"sphere":{const latitudes=Math.max(2,Math.floor(node.segments/2));return{vertices:(node.segments+1)*(latitudes-1)+2,triangles:2*node.segments*latitudes,planes:node.segments*latitudes,bounds:{min:[-node.radius,-node.radius,-node.radius],max:[node.radius,node.radius,node.radius]}}}case"extrude":{const p=profile(node.profile),count=p.points;return{vertices:6*count,triangles:4*count,planes:count+2,bounds:{min:[p.bounds.min[0],p.bounds.min[1],-node.depth/2],max:[p.bounds.max[0],p.bounds.max[1],node.depth/2]}}}case"revolve":{const p=profile(node.profile);const radius=Math.max(Math.abs(p.bounds.min[0]),Math.abs(p.bounds.max[0]));return{vertices:p.points*(node.segments+1),triangles:4*p.points*node.segments,planes:p.points*node.segments+p.points,bounds:{min:[-radius,p.bounds.min[1],-radius],max:[radius,p.bounds.max[1],radius]}}}case"sweep":{const p=profile(node.profile);const radius=Math.hypot(Math.max(Math.abs(p.bounds.min[0]),Math.abs(p.bounds.max[0])),Math.max(Math.abs(p.bounds.min[1]),Math.abs(p.bounds.max[1])));const pathBounds=node.path.reduce((acc,point)=>boundsUnion(acc,{min:point,max:point}),{min:node.path[0],max:node.path[0]});const count=node.path.length;return{vertices:p.points*count+2*p.points,triangles:4*p.points*count,planes:p.points*count+2,bounds:inflateBounds(pathBounds,radius)}}case"loft":{const a=profile(node.bottom),c=profile(node.top),count=a.points+c.points;const bounds=boundsUnion({min:[a.bounds.min[0],0,a.bounds.min[1]],max:[a.bounds.max[0],0,a.bounds.max[1]]},{min:[c.bounds.min[0],node.height,c.bounds.min[1]],max:[c.bounds.max[0],node.height,c.bounds.max[1]]});return{vertices:7*count,triangles:4*count,planes:count+2,bounds}}case"transform":{const source=mesh(node.input);return{...source,bounds:transformBounds(composeTransform(node.transform),source.bounds)}}case"mirror":{const source=mesh(node.input),index2=AXIS_INDEX[node.axis];const bounds={min:[...source.bounds.min],max:[...source.bounds.max]};const low=2*node.offset-bounds.max[index2],high=2*node.offset-bounds.min[index2];bounds.min[index2]=low;bounds.max[index2]=high;return{...source,bounds}}case"array":{const source=mesh(node.input);let bounds=source.bounds;for(let copy=1;copy<node.count;copy++)bounds=boundsUnion(bounds,boundsOffset(source.bounds,[copy*node.step[0],copy*node.step[1],copy*node.step[2]]));return{vertices:source.vertices*node.count,triangles:source.triangles*node.count,planes:source.planes*node.count,bounds}}case"merge":{const inputs=node.inputs.map(mesh);return{vertices:inputs.reduce((sum,item)=>sum+item.vertices,0),triangles:inputs.reduce((sum,item)=>sum+item.triangles,0),planes:inputs.reduce((sum,item)=>sum+item.planes,0),bounds:inputs.map((input)=>input.bounds).reduce(boundsUnion)}}case"boolean":{const a=mesh(node.a);const cutters=node.operation==="difference"?node.cutters.map(mesh):[mesh(node.b)];const triangles=a.triangles*(1+cutters.reduce((sum,cutter)=>sum+cutter.planes,0))+cutters.reduce((sum,cutter)=>sum+cutter.triangles*(a.planes+1),0);const other=cutters[0];const bounds=node.operation==="intersection"?{min:[Math.max(a.bounds.min[0],other.bounds.min[0]),Math.max(a.bounds.min[1],other.bounds.min[1]),Math.max(a.bounds.min[2],other.bounds.min[2])],max:[Math.min(a.bounds.max[0],other.bounds.max[0]),Math.min(a.bounds.max[1],other.bounds.max[1]),Math.min(a.bounds.max[2],other.bounds.max[2])]}:node.operation==="union"?boundsUnion(a.bounds,other.bounds):a.bounds;return{vertices:3*triangles,triangles,planes:a.planes+cutters.reduce((sum,cutter)=>sum+cutter.planes,0),bounds}}case"material-slot":case"uv-project":return mesh(node.input)}}function estimateSpatialGeometryGraph(input){const graph=parseSpatialGeometryGraph(input);const nodesById=new Map(graph.nodes.map((node)=>[node.id,node]));const order=spatialTopologicalIds(new Map(graph.nodes.map((node)=>[node.id,nodeDependencies(node)])),"geometry graph");const meshEstimates=new Map,profileEstimates=new Map;let depth=0;const depthOf=new Map;for(const id of order){const node=nodesById.get(id);depthOf.set(id,1+Math.max(0,...nodeDependencies(node).map((dependency)=>depthOf.get(dependency))));depth=Math.max(depth,depthOf.get(id));const estimate=estimateNode(node,meshEstimates,profileEstimates,`geometry.nodes.${id}`);if(PROFILE_KINDS.has(node.kind)){const candidate=estimate;if(candidate.points>SPATIAL_GEOMETRY_LIMITS.profilePoints)fail2(`Profile node ${id} exceeds the point budget before evaluation.`,`geometry.nodes.${id}`);profileEstimates.set(id,candidate)}else{const candidate=estimate;if(candidate.vertices>SPATIAL_GEOMETRY_LIMITS.vertices||candidate.triangles>SPATIAL_GEOMETRY_LIMITS.triangles){fail2(`Geometry node ${id} exceeds the vertex/triangle budget before evaluation.`,`geometry.nodes.${id}`)}meshEstimates.set(id,candidate)}}const output=meshEstimates.get(graph.output);const bytes=output.vertices*32+output.triangles*16;if(bytes>SPATIAL_GEOMETRY_LIMITS.outputBytes)fail2("Geometry output exceeds the byte budget before evaluation.","geometry.output");return deepFreezeJson({nodes:graph.nodes.length,depth,vertices:output.vertices,triangles:output.triangles,bytes,bounds:output.bounds})}function evaluateSpatialGeometry(input){const graph=parseSpatialGeometryGraph(input);const estimate=estimateSpatialGeometryGraph(graph);const nodesById=new Map(graph.nodes.map((node)=>[node.id,node]));const order=spatialTopologicalIds(new Map(graph.nodes.map((node)=>[node.id,nodeDependencies(node)])),"geometry graph");const profiles=new Map,meshes=new Map;for(const id of order){const node=nodesById.get(id),path=`geometry.nodes.${id}`;const profile=(key2)=>profiles.get(key2);const mesh2=(key2)=>meshes.get(key2);switch(node.kind){case"profile":profiles.set(id,checkedProfile(node.points,path));break;case"rect":profiles.set(id,checkedProfile([[-node.width/2,-node.height/2],[node.width/2,-node.height/2],[node.width/2,node.height/2],[-node.width/2,node.height/2]],path));break;case"ellipse":profiles.set(id,checkedProfile(Array.from({length:node.segments},(_,index2)=>{const angle=2*Math.PI*index2/node.segments;return[node.radiusX*Math.cos(angle),node.radiusY*Math.sin(angle)]}),path));break;case"inset":profiles.set(id,insetProfile(profile(node.input),node.distance,path));break;case"bevel":profiles.set(id,bevelProfile(profile(node.input),node.radius,node.segments,path));break;case"box":meshes.set(id,boxMesh(node.size));break;case"cylinder":meshes.set(id,cylinderMesh(node.radius,node.height,node.segments));break;case"sphere":meshes.set(id,sphereMesh(node.radius,node.segments));break;case"extrude":meshes.set(id,extrudeMesh(profile(node.profile),node.depth,node.sideSlot??0,node.capSlot??node.sideSlot??0,path));break;case"revolve":meshes.set(id,revolveMesh(profile(node.profile),node.segments,node.capSlot??0,path));break;case"sweep":meshes.set(id,sweepMesh(profile(node.profile),node.path,path));break;case"loft":meshes.set(id,loftMesh(profile(node.bottom),profile(node.top),node.height,path));break;case"transform":meshes.set(id,transformMesh(mesh2(node.input),node.transform));break;case"mirror":meshes.set(id,mirrorMesh(mesh2(node.input),AXIS_INDEX[node.axis],node.offset));break;case"array":meshes.set(id,arrayMesh(mesh2(node.input),node.count,node.step));break;case"merge":meshes.set(id,mergeMeshes(node.inputs.map(mesh2)));break;case"boolean":meshes.set(id,booleanMesh(node,meshes,path));break;case"material-slot":{const source=mesh2(node.input),copy=builder();copy.positions.push(...source.positions);copy.normals.push(...source.normals);copy.uvs.push(...source.uvs);copy.indices.push(...source.indices);copy.slots.push(...source.slots.map(()=>node.slot));copy.uvsSet=source.uvsSet;meshes.set(id,copy);break}case"uv-project":meshes.set(id,projectUvs(mesh2(node.input),node.projection));break}}const mesh=freezeMesh(meshes.get(graph.output));if(mesh.vertices>estimate.vertices||mesh.triangles>estimate.triangles){fail2("Evaluated mesh exceeded its static budget estimate.","geometry.output")}return deepFreezeJson({mesh,estimate,graphSha256:spatialValueSha256({domain:"slopcamera.spatial-geometry-graph.v1",graph})})}var srgbToLinear=(value)=>value<=0.04045?value/12.92:Math.pow((value+0.055)/1.055,2.4);function materialToGlb(material){const rgb=[1,3,5].map((index2)=>srgbToLinear(Number.parseInt(material.color.slice(index2,index2+2),16)/255));const baseColorLinear=[rgb[0],rgb[1],rgb[2],material.opacity];const alphaMode=material.opacity<1?"BLEND":"OPAQUE";if(material.kind==="unlit"){return{baseColorLinear,metallic:0,roughness:1,alphaMode,emissiveLinear:[rgb[0],rgb[1],rgb[2]]}}const emissiveLinear=material.emissive===undefined?undefined:(()=>{const factor=Math.min(1,material.emissive.intensity);const e=[1,3,5].map((index2)=>srgbToLinear(Number.parseInt(material.emissive.color.slice(index2,index2+2),16)/255)*factor);return e.every((value)=>value===0)?undefined:[e[0],e[1],e[2]]})();return{baseColorLinear,metallic:material.metalness,roughness:material.roughness,alphaMode,...emissiveLinear===undefined?{}:{emissiveLinear}}}function emitSpatialGeometryGlb(mesh,materials2){if(materials2.length<1||materials2.length>SPATIAL_GEOMETRY_LIMITS.materialSlots)fail2("GLB emission requires 1\u201316 material slots.");for(const material of materials2)parseSpatialValue(SpatialMaterialSchema,material,"geometry material");const slotTriangles=new Map;for(let index2=0;index2<mesh.triangles;index2++){const slot=mesh.slots[index2];if(slot>=materials2.length)fail2(`Material slot ${slot} has no declared material.`);const list=slotTriangles.get(slot)??[];list.push(mesh.indices[index2*3],mesh.indices[index2*3+1],mesh.indices[index2*3+2]);slotTriangles.set(slot,list)}const slots=[...slotTriangles.keys()].sort((a,b)=>a-b);const vertices=mesh.vertices;const indexComponent=vertices<=65535?5123:5125;const indexBytes=indexComponent===5123?2:4;const hasUvs=mesh.uvsProjected;const positionBytes=vertices*12,normalBytes=vertices*12,uvBytes=hasUvs?vertices*8:0;const indexRanges=[];let binLength=positionBytes+normalBytes+uvBytes;for(const slot of slots){const count=slotTriangles.get(slot).length;indexRanges.push({slot,byteOffset:binLength,byteLength:count*indexBytes,count});binLength+=count*indexBytes;binLength=Math.ceil(binLength/4)*4}const bin=new Uint8Array(binLength),data=new DataView(bin.buffer);for(let index2=0;index2<mesh.positions.length;index2++)data.setFloat32(index2*4,mesh.positions[index2],true);for(let index2=0;index2<mesh.normals.length;index2++)data.setFloat32(positionBytes+index2*4,mesh.normals[index2],true);if(hasUvs)for(let index2=0;index2<mesh.uvs.length;index2++)data.setFloat32(positionBytes+normalBytes+index2*4,mesh.uvs[index2],true);for(const range of indexRanges){const indices=slotTriangles.get(range.slot);for(let index2=0;index2<indices.length;index2++){if(indexComponent===5123)data.setUint16(range.byteOffset+index2*2,indices[index2],true);else data.setUint32(range.byteOffset+index2*4,indices[index2],true)}}const positions32=new Float32Array(mesh.positions);const low=[Infinity,Infinity,Infinity],high=[-Infinity,-Infinity,-Infinity];for(let index2=0;index2<positions32.length;index2+=3){for(let axisIndex=0;axisIndex<3;axisIndex++){low[axisIndex]=Math.min(low[axisIndex],positions32[index2+axisIndex]);high[axisIndex]=Math.max(high[axisIndex],positions32[index2+axisIndex])}}const bufferViews=[{buffer:0,byteOffset:0,byteLength:positionBytes,target:34962},{buffer:0,byteOffset:positionBytes,byteLength:normalBytes,target:34962},...hasUvs?[{buffer:0,byteOffset:positionBytes+normalBytes,byteLength:uvBytes,target:34962}]:[],...indexRanges.map((range)=>({buffer:0,byteOffset:range.byteOffset,byteLength:range.byteLength,target:34963}))];const accessors=[{bufferView:0,componentType:5126,count:vertices,type:"VEC3",min:low,max:high},{bufferView:1,componentType:5126,count:vertices,type:"VEC3"},...hasUvs?[{bufferView:2,componentType:5126,count:vertices,type:"VEC2"}]:[],...indexRanges.map((range,index2)=>({bufferView:(hasUvs?3:2)+index2,componentType:indexComponent,count:range.count,type:"SCALAR"}))];const glbMaterials=slots.map((slot)=>{const resolved=materialToGlb(materials2[slot]);return{pbrMetallicRoughness:{baseColorFactor:resolved.baseColorLinear,metallicFactor:resolved.metallic,roughnessFactor:resolved.roughness},alphaMode:resolved.alphaMode,doubleSided:false,...resolved.emissiveLinear===undefined?{}:{emissiveFactor:resolved.emissiveLinear}}});const document={asset:{version:"2.0",generator:SPATIAL_GEOMETRY_PROFILE},buffers:[{byteLength:binLength}],bufferViews,accessors,scene:0,scenes:[{nodes:[0]}],nodes:[{mesh:0}],meshes:[{primitives:slots.map((_slot,index2)=>({attributes:{POSITION:0,NORMAL:1,...hasUvs?{TEXCOORD_0:2}:{}},indices:(hasUvs?3:2)+index2,material:index2,mode:4}))}],materials:glbMaterials};const rawJson=new TextEncoder().encode(JSON.stringify(document));const json=new Uint8Array(Math.ceil(rawJson.length/4)*4).fill(32);json.set(rawJson);const bytes=new Uint8Array(28+json.length+bin.length),view=new DataView(bytes.buffer);view.setUint32(0,1179937895,true);view.setUint32(4,2,true);view.setUint32(8,bytes.length,true);view.setUint32(12,json.length,true);view.setUint32(16,1313821514,true);bytes.set(json,20);view.setUint32(20+json.length,bin.length,true);view.setUint32(24+json.length,5130562,true);bytes.set(bin,28+json.length);return bytes}import{z as z5}from"zod";var boundsComponent=z5.number().finite().min(-1000000000000000000).max(1000000000000000000);var boundsVector=z5.tuple([boundsComponent,boundsComponent,boundsComponent]);var SpatialBoundsSchema=z5.strictObject({min:boundsVector,max:boundsVector}).refine((value)=>value.min.every((component,index2)=>component<=value.max[index2]),"Bounds min must not exceed max.");var factsUnit=z5.number().finite().min(0).max(1);var SpatialAssetMaterialFactSchema=z5.strictObject({name:z5.string().max(1024).optional(),alphaMode:z5.enum(["OPAQUE","MASK","BLEND"]),doubleSided:z5.boolean(),maps:z5.array(z5.enum(["baseColor","metallicRoughness","normal","occlusion","emissive","clearcoat","clearcoatRoughness","clearcoatNormal","transmission","sheenColor","sheenRoughness","anisotropy"])).max(12),textureTransforms:z5.array(z5.strictObject({map:z5.string().min(1).max(64),offset:z5.tuple([z5.number().finite(),z5.number().finite()]),rotation:z5.number().finite().min(-Math.PI).max(Math.PI),scale:z5.tuple([z5.number().finite(),z5.number().finite()])})).max(12).default([]),emissiveLinear:z5.tuple([factsUnit,factsUnit,factsUnit]).optional(),emissiveStrength:z5.number().finite().min(0).max(1e5).optional(),clearcoat:z5.strictObject({factor:factsUnit,roughness:factsUnit}).optional(),transmission:z5.strictObject({factor:factsUnit}).optional(),sheen:z5.strictObject({colorLinear:z5.tuple([factsUnit,factsUnit,factsUnit]),roughness:factsUnit}).optional(),anisotropy:z5.strictObject({strength:z5.number().finite().min(-1).max(1),rotation:z5.number().finite().min(0).max(2*Math.PI)}).optional(),ior:z5.number().finite().min(1).max(5).optional()});var SpatialAssetRigFactsSchema=z5.strictObject({profile:z5.literal(SPATIAL_GLB_RIGGED_PROFILE),skins:z5.array(z5.strictObject({name:z5.string().max(1024).optional(),jointNodeIndices:z5.array(z5.number().int().min(0).max(SPATIAL_GLB_LIMITS.nodes-1)).min(1).max(SPATIAL_GLB_LIMITS.jointsPerSkin),inverseBindMatricesAccessor:z5.number().int().min(0).max(SPATIAL_GLB_LIMITS.accessors-1)})).min(1).max(SPATIAL_GLB_LIMITS.skins),morphTargets:z5.array(z5.array(z5.array(z5.strictObject({name:z5.string().min(1).max(1024),hasPosition:z5.boolean(),hasNormal:z5.boolean()})).max(SPATIAL_GLB_LIMITS.morphTargetsPerPrimitive)).max(SPATIAL_GLB_LIMITS.primitives)).max(SPATIAL_GLB_LIMITS.meshes),clips:z5.array(z5.strictObject({name:z5.string().max(1024).optional(),durationSeconds:z5.number().finite().min(0).max(SPATIAL_GLB_LIMITS.durationSeconds),channels:z5.array(z5.strictObject({nodeIndex:z5.number().int().min(0).max(SPATIAL_GLB_LIMITS.nodes-1),path:z5.enum(["translation","rotation","scale","weights"])})).max(SPATIAL_GLB_LIMITS.channels)})).max(SPATIAL_GLB_LIMITS.clips)});var meterBound=z5.number().finite().min(0).max(1e6);var lodCoordinate=z5.number().finite().min(-1e6).max(1e6);var lodVector=z5.tuple([lodCoordinate,lodCoordinate,lodCoordinate]);var SpatialAssetLodSchema=z5.strictObject({level:z5.number().int().min(0).max(7),assetId:SpatialAssetIdSchema,sha256:SpatialDigestSchema,switchDistanceM:meterBound});var SpatialCollisionProxySchema=z5.discriminatedUnion("kind",[z5.strictObject({kind:z5.literal("box"),center:lodVector,halfExtents:z5.tuple([meterBound,meterBound,meterBound]).refine((v)=>v.every((c)=>c>0),"Box half extents must be positive.")}),z5.strictObject({kind:z5.literal("sphere"),center:lodVector,radius:meterBound.refine((v)=>v>0,"Sphere radius must be positive.")}),z5.strictObject({kind:z5.literal("capsule"),center:lodVector,axis:z5.enum(["x","y","z"]),radius:meterBound.refine((v)=>v>0,"Capsule radius must be positive."),halfLength:meterBound}),z5.strictObject({kind:z5.literal("hull-hull"),artifactSha256:SpatialDigestSchema})]);var SpatialRetainedArtifactSchema=z5.strictObject({operation:z5.enum(["mesh-repair","complex-csg","uv-atlas","decimation","hull-decomposition","glb-emission"]),requestSha256:SpatialDigestSchema,receiptSha256:SpatialDigestSchema,outputs:z5.array(z5.strictObject({sha256:SpatialDigestSchema,bytes:z5.number().int().safe().min(1).max(SPATIAL_GLB_LIMITS.bytes)})).min(1).max(16)});var SpatialAssetGeneratorFactsSchema=z5.strictObject({generatorId:SpatialGeneratorIdSchema,parametricKind:z5.string().min(1).max(64),specSha256:SpatialDigestSchema,parametersSha256:SpatialDigestSchema,lods:z5.array(SpatialAssetLodSchema).min(1).max(8),collision:z5.array(SpatialCollisionProxySchema).max(16),retainedArtifacts:z5.array(SpatialRetainedArtifactSchema).max(8).optional()});var SpatialAssetFactsV1Schema=z5.strictObject({kind:z5.literal("slopcamera.spatial-asset-facts"),schemaVersion:z5.literal(1),subject:SpatialPayloadSchema,subjectManifestSha256:SpatialDigestSchema,profile:z5.enum([SPATIAL_GLB_PROFILE,SPATIAL_GLB_PROFILE_V1,SPATIAL_GLB_RIGGED_PROFILE,SPATIAL_GEOMETRY_PROFILE]),nodeCount:z5.number().int().min(1).max(SPATIAL_GLB_LIMITS.nodes),clipDurationsSeconds:z5.array(z5.number().finite().min(0).max(SPATIAL_GLB_LIMITS.durationSeconds)).max(SPATIAL_GLB_LIMITS.clips),bounds:z5.strictObject({modelSpace:SpatialBoundsSchema,sceneSpace:SpatialBoundsSchema}),materials:z5.array(SpatialAssetMaterialFactSchema).max(SPATIAL_GLB_LIMITS.materials).optional(),rig:SpatialAssetRigFactsSchema.optional(),generator:SpatialAssetGeneratorFactsSchema.optional()}).superRefine((facts,context)=>{if(facts.profile===SPATIAL_GLB_RIGGED_PROFILE!==(facts.rig!==undefined))context.addIssue({code:"custom",path:["rig"],message:"Rig facts must be present exactly for the rigged GLB profile."});if(facts.profile===SPATIAL_GEOMETRY_PROFILE!==(facts.generator!==undefined))context.addIssue({code:"custom",path:["generator"],message:"Generator facts must be present exactly for the parametric geometry profile."});if(facts.generator!==undefined){const levels=new Set(facts.generator.lods.map((lod)=>lod.level));if(levels.size!==facts.generator.lods.length||!levels.has(0))context.addIssue({code:"custom",path:["generator","lods"],message:"LOD levels must be unique and include level 0."});const distances=facts.generator.lods.map((lod)=>lod.switchDistanceM);if(distances.some((value,index2)=>index2>0&&value<=distances[index2-1]))context.addIssue({code:"custom",path:["generator","lods"],message:"LOD switch distances must strictly increase."});const hulls=facts.generator.collision.filter((proxy)=>proxy.kind==="hull-hull");for(const hull of hulls){const bound=facts.generator.retainedArtifacts?.some((artifact)=>artifact.outputs.some((output)=>output.sha256===hull.artifactSha256))??false;if(!bound)context.addIssue({code:"custom",path:["generator","collision"],message:"Hull-hull proxies must reference a retained artifact output."})}}});var SpatialPublishedArtifactSchema=z5.strictObject({path:z5.string().min(1).max(1024),sha256:SpatialDigestSchema,bytes:z5.number().int().safe().min(1).max(SPATIAL_GLB_LIMITS.bytes),disposition:z5.enum(["created","exists"])});var SpatialAssetAdmissionV1Schema=z5.strictObject({kind:z5.literal("slopcamera.spatial-asset-admission"),schemaVersion:z5.literal(1),manifest:SpatialAssetManifestSchema,factsManifest:SpatialAssetManifestSchema,facts:SpatialAssetFactsV1Schema,bounds:z5.strictObject({modelSpace:SpatialBoundsSchema,sceneSpace:SpatialBoundsSchema}),entity:SpatialEntitySchema,artifacts:z5.strictObject({payload:SpatialPublishedArtifactSchema,facts:SpatialPublishedArtifactSchema}),operations:z5.array(SpatialPatchOperationSchema).min(2).max(SPATIAL_SCENE_LIMITS.patchOperations)});import{z as z6}from"zod";var EvaluatedOptionsSchema=z6.strictObject({timeUs:SpatialTimeUsSchema,cameraId:SpatialCameraIdSchema,overrides:z6.array(SpatialOverrideSchema).max(SPATIAL_SCENE_LIMITS.entities).optional(),cameraPoseOverride:SpatialPoseSchema.optional()});function mergeSpatialOverrides(sceneOverrides,shotOverrides){const effective=new Map(sceneOverrides.map((override)=>[`${override.entityId}:${override.property}`,override]));const seen=new Set;for(const override of shotOverrides){const key2=`${override.entityId}:${override.property}`;if(seen.has(key2))throw new SpatialSceneError("conflict",`Duplicate shot override ${key2}.`,"shot.overrides");seen.add(key2);effective.set(key2,override)}return deepFreezeJson(sortSpatialBy([...effective.values()],(item)=>`${item.entityId}:${item.property}`))}function applySpatialEntityOverride(entity,override){if(!spatialPropertySupported(entity,override.property))throw new SpatialSceneError("conflict",`Unsupported override ${entity.entityId}.${override.property}.`);if(override.property==="transform")return{...entity,transform:override.value};if(override.property==="color"){const color3=override.value.toLowerCase();if(entity.kind==="mesh")return{...entity,material:{...entity.material,color:color3}};if(entity.kind==="text"||entity.kind==="light")return{...entity,color:color3}}if(override.property==="opacity"){if(entity.kind==="mesh")return{...entity,material:{...entity.material,opacity:override.value}};if(entity.kind==="image"||entity.kind==="diagram"||entity.kind==="video")return{...entity,opacity:override.value}}throw new SpatialSceneError("conflict",`Unsupported override ${entity.entityId}.${override.property}.`)}function sampleChannel(channel,timeUs){const keys=channel.keys;if(timeUs<=keys[0].timeUs)return keys[0].value;if(timeUs>=keys[keys.length-1].timeUs)return keys[keys.length-1].value;let lower=0,upper=keys.length-1;while(upper-lower>1){const middle=Math.floor((lower+upper)/2);if(keys[middle].timeUs<=timeUs)lower=middle;else upper=middle}const a=keys[lower],b=keys[upper];if(channel.interpolation==="step")return a.value;const t=(timeUs-a.timeUs)/(b.timeUs-a.timeUs);if(channel.property==="rotation"){return slerpQuaternion(channel.keys[lower].value,channel.keys[upper].value,t)}if(typeof a.value==="number"&&typeof b.value==="number")return a.value+(b.value-a.value)*t;const av=a.value,bv=b.value;return av.map((value,index2)=>value+(bv[index2]-value)*t)}function validateSpatialShot(sceneInput,shotInput){const context=createSpatialEvaluationContext(sceneInput);const scene=context.scene;const shot=parseSpatialValue(SpatialShotV1Schema,shotInput,"shot");if(shot.sceneSha256!==context.sceneSha256)throw new SpatialSceneError("conflict","Shot pins another scene revision.","shot.sceneSha256");if(!context.camerasById.has(shot.cameraId))throw new SpatialSceneError("invalid-data","Shot camera is absent from its scene.","shot.cameraId");if(shot.sceneStartUs>=scene.durationUs)throw new SpatialSceneError("invalid-data","Shot scene start must precede scene duration.","shot.sceneStartUs");if(shot.playback==="once"&&shot.sceneStartUs+shot.range.endUs-shot.range.startUs>scene.durationUs)throw new SpatialSceneError("invalid-data","Once playback exceeds scene duration.","shot.range");validateSpatialOverrides(scene,mergeSpatialOverrides(scene.overrides,shot.overrides));if(shot.cameraPoseOverride&&context.cameraChannelsById.has(shot.cameraId))throw new SpatialSceneError("conflict","Camera animation and shot pose override both own camera pose.","shot.cameraPoseOverride");return deepFreezeJson(shot)}function createSpatialEvaluationContext(sceneInput){const scene=parseSpatialScene(sceneInput);const entitiesById=new Map(scene.entities.map((entity)=>[entity.entityId,entity]));const camerasById=new Map(scene.cameras.map((camera2)=>[camera2.cameraId,camera2]));const entityOrder=spatialTopologicalIds(new Map(scene.entities.map((entity)=>[entity.entityId,entity.parentId===null?[]:[entity.parentId]])),"entity hierarchy");const visibilityById=new Map;for(const id of entityOrder){const entity=entitiesById.get(id);visibilityById.set(id,entity.visible&&(entity.parentId===null||visibilityById.get(entity.parentId)===true))}const entityChannels=[];const cameraChannelsById=new Map;for(const channel of scene.animations){if(entitiesById.has(channel.targetId))entityChannels.push(channel);else{const list=cameraChannelsById.get(channel.targetId)??[];list.push(channel);cameraChannelsById.set(channel.targetId,list)}}return Object.freeze({scene,sceneSha256:spatialValueSha256(scene),entitiesById,camerasById,entityOrder,visibilityById,entityChannels,cameraChannelsById,baseOverrides:mergeSpatialOverrides(scene.overrides,[]),assetDigests:spatialAssetClosureDigests(scene.assets)})}function evaluateSpatialSceneInContext(context,options){const scene=context.scene;const capturedOptions=parseSpatialValue(EvaluatedOptionsSchema,options,"evaluation options");const timeUs=capturedOptions.timeUs;if(timeUs>scene.durationUs)throw new SpatialSceneError("invalid-data","Evaluation time exceeds scene duration.","timeUs");let camera2=context.camerasById.get(capturedOptions.cameraId);if(!camera2)throw new SpatialSceneError("not-found",`Unknown camera ${capturedOptions.cameraId}.`,"cameraId");const overrides=capturedOptions.overrides===undefined?context.baseOverrides:mergeSpatialOverrides(scene.overrides,capturedOptions.overrides);if(capturedOptions.overrides!==undefined)validateSpatialOverrides(scene,overrides);if(capturedOptions.cameraPoseOverride&&context.cameraChannelsById.has(camera2.cameraId))throw new SpatialSceneError("conflict","Camera animation conflicts with camera pose override.","cameraPoseOverride");const entities=new Map(context.entitiesById);for(const channel of context.entityChannels){const value=sampleChannel(channel,timeUs);const entity=entities.get(channel.targetId);if(channel.property==="opacity")entities.set(entity.entityId,applySpatialEntityOverride(entity,{entityId:entity.entityId,property:"opacity",value}));else entities.set(entity.entityId,{...entity,transform:{...entity.transform,[channel.property]:value}})}for(const channel of context.cameraChannelsById.get(camera2.cameraId)??[]){const value=sampleChannel(channel,timeUs);camera2={...camera2,pose:{...camera2.pose,[channel.property]:value}}}for(const override of overrides)entities.set(override.entityId,applySpatialEntityOverride(entities.get(override.entityId),override));if(capturedOptions.cameraPoseOverride)camera2={...camera2,pose:capturedOptions.cameraPoseOverride};const matrices=new Map;for(const id of context.entityOrder){const entity=entities.get(id);try{const local=composeTransform(entity.transform);matrices.set(id,entity.parentId===null?local:multiplyTransforms(matrices.get(entity.parentId),local))}catch(error){throw new SpatialSceneError("invalid-data",error instanceof Error?error.message:"Invalid evaluated transform.",`entities.${id}.transform`)}}const evaluated=scene.entities.map((source,index2)=>({entity:entities.get(source.entityId),worldMatrix:matrices.get(source.entityId),visible:context.visibilityById.get(source.entityId),selectionId:index2+1}));const stateSha256=spatialStateValueSha256({domain:"slopcamera.spatial-state.v1",timeUs,entities:evaluated,assetDigests:context.assetDigests});const viewSha256=spatialValueSha256({domain:"slopcamera.spatial-view.v1",stateSha256,camera:camera2});const result=EvaluatedSpatialSceneSchema.parse({kind:"slopcamera.spatial-snapshot",schemaVersion:1,sceneSha256:context.sceneSha256,stateSha256,viewSha256,timeUs,camera:camera2,entities:evaluated.map((item)=>({...item,visible:item.visible&&(item.entity.placement.kind==="world"||item.entity.placement.cameraId===camera2.cameraId)})),assets:scene.assets,...scene.fog===undefined?{}:{fog:scene.fog}});return deepFreezeJson(result)}function evaluateSpatialScene(sceneInput,options){return evaluateSpatialSceneInContext(createSpatialEvaluationContext(sceneInput),options)}import{z as z7}from"zod";var SPATIAL_AUDIT_LIMITS=Object.freeze({samples:64,defaultSamples:9,findings:1024,entitySamples:65536,instanceSamples:1048576,reportBytes:33554432});var ENTITY_KINDS=["group","mesh","image","diagram","video","text","light","splat","environment"];var BOUNDS_UNKNOWN_REASONS=["requires-asset-decoding","requires-text-layout","no-surface"];var CONTAINED=["full","partial","outside","behind-camera","clipped"];var FINDING_KINDS=["never-visible","off-camera","empty-scene-region","bounds-unknown","behind-camera-all-samples","shadows-disabled"];var CONTAINED_HISTOGRAM_ORDER=["full","partial","outside","clipped","behind-camera"];var auditVector=z7.tuple([z7.number().finite().min(-1000000000000).max(1000000000000),z7.number().finite().min(-1000000000000).max(1000000000000),z7.number().finite().min(-1000000000000).max(1000000000000)]);var SpatialAuditBoundsSchema=z7.strictObject({min:auditVector,max:auditVector}).refine((bounds)=>bounds.min.every((value,index2)=>value<=bounds.max[index2]),"Bounds min must not exceed max.");var SpatialAuditOptionsSchema=z7.strictObject({cameraId:SpatialCameraIdSchema,timesUs:z7.array(SpatialTimeUsSchema).min(1).max(SPATIAL_AUDIT_LIMITS.samples).optional(),assetBounds:z7.record(SpatialAssetIdSchema,SpatialAuditBoundsSchema).optional()});var SpatialAuditFrustumSchema=z7.strictObject({contained:z7.enum(CONTAINED),pixelFootprint:z7.number().finite().min(0).max(1000000000000000)});var SpatialAuditSampleSchema=z7.strictObject({timeUs:SpatialTimeUsSchema,visible:z7.boolean(),bounds:SpatialAuditBoundsSchema.optional(),frustum:SpatialAuditFrustumSchema.optional(),note:z7.enum(["out-of-range","other-camera"]).optional()});var SpatialAuditEntitySchema=z7.strictObject({entityId:SpatialEntityIdSchema,name:z7.string().min(1).max(256),kind:z7.enum(ENTITY_KINDS),placement:SpatialPlacementSchema,enclosure:z7.discriminatedUnion("status",[z7.strictObject({status:z7.literal("bounded")}),z7.strictObject({status:z7.literal("unknown"),reason:z7.enum(BOUNDS_UNKNOWN_REASONS)})]),samples:z7.array(SpatialAuditSampleSchema).max(SPATIAL_AUDIT_LIMITS.samples),instances:z7.number().int().min(1).max(SPATIAL_SCENE_LIMITS.entities).optional()});var SpatialAuditFindingSchema=z7.strictObject({severity:z7.enum(["info","warning"]),kind:z7.enum(FINDING_KINDS),entityId:SpatialEntityIdSchema.optional(),timeUs:SpatialTimeUsSchema.optional(),detail:z7.string().min(1).max(1024)});var entityKindCounts=z7.strictObject({group:z7.number().int().min(0),mesh:z7.number().int().min(0),image:z7.number().int().min(0),diagram:z7.number().int().min(0),video:z7.number().int().min(0),text:z7.number().int().min(0),light:z7.number().int().min(0),splat:z7.number().int().min(0),environment:z7.number().int().min(0)});var SpatialAuditReportSchema=z7.strictObject({kind:z7.literal("slopcamera.spatial-audit"),schemaVersion:z7.literal(1),sceneId:SpatialSceneIdSchema,sceneSha256:SpatialDigestSchema,cameraId:SpatialCameraIdSchema,durationUs:SpatialTimeUsSchema,timesUs:z7.array(SpatialTimeUsSchema).min(1).max(SPATIAL_AUDIT_LIMITS.samples),summary:z7.strictObject({entities:z7.strictObject({total:z7.number().int().min(0).max(SPATIAL_SCENE_LIMITS.entities),bounded:z7.number().int().min(0).max(SPATIAL_SCENE_LIMITS.entities),unknownBounds:z7.number().int().min(0).max(SPATIAL_SCENE_LIMITS.entities),byKind:entityKindCounts,instances:z7.number().int().min(0).max(SPATIAL_SCENE_LIMITS.entities*SPATIAL_SCENE_LIMITS.entities)}),animations:z7.strictObject({channels:z7.number().int().min(0).max(SPATIAL_SCENE_LIMITS.channels),targets:z7.number().int().min(0).max(SPATIAL_SCENE_LIMITS.entities+SPATIAL_SCENE_LIMITS.cameras),properties:z7.strictObject({position:z7.number().int().min(0),rotation:z7.number().int().min(0),scale:z7.number().int().min(0),opacity:z7.number().int().min(0)})}),cameras:z7.array(SpatialCameraIdSchema).max(SPATIAL_SCENE_LIMITS.cameras),entitiesNeverVisible:z7.array(SpatialEntityIdSchema).max(SPATIAL_SCENE_LIMITS.entities),entitiesNeverInFrustum:z7.array(SpatialEntityIdSchema).max(SPATIAL_SCENE_LIMITS.entities)}),entities:z7.array(SpatialAuditEntitySchema).max(SPATIAL_SCENE_LIMITS.entities),findings:z7.array(SpatialAuditFindingSchema).max(SPATIAL_AUDIT_LIMITS.findings),omittedFindings:z7.number().int().min(0)});function spatialEntityLocalBounds(entity,assetBounds){const supplied=(assetId2)=>assetBounds[assetId2]===undefined?{status:"unknown",reason:"requires-asset-decoding"}:{status:"bounded",bounds:assetBounds[assetId2]};let half;if(entity.kind==="mesh"){switch(entity.geometry.kind){case"asset":return supplied(entity.geometry.assetId);case"box":half=entity.geometry.size.map((value)=>value/2);break;case"plane":half=[entity.geometry.width/2,entity.geometry.height/2,0];break;case"sphere":half=[entity.geometry.radius,entity.geometry.radius,entity.geometry.radius];break;case"cylinder":half=[entity.geometry.radius,entity.geometry.height/2,entity.geometry.radius];break}}else if(entity.kind==="image"||entity.kind==="diagram"||entity.kind==="video"){half=[entity.width/2,entity.height/2,0]}else if(entity.kind==="splat")return supplied(entity.assetId);else return{status:"unknown",reason:entity.kind==="text"?"requires-text-layout":"no-surface"};return{status:"bounded",bounds:{min:[-half[0],-half[1],-half[2]],max:half}}}var round3=(value)=>Math.round(value*1000)/1000;function boundsCorners(bounds){const corners=[];for(let mask=0;mask<8;mask++){corners.push([mask&1?bounds.max[0]:bounds.min[0],mask&2?bounds.max[1]:bounds.min[1],mask&4?bounds.max[2]:bounds.min[2]])}return corners}function classifyWorldFrustum(view,bounds){const{width,height}=view.projection;let behind=0,inside=0,inClip=0;let minX=Infinity,minY=Infinity,maxX=-Infinity,maxY=-Infinity;for(const corner of boundsCorners(bounds)){const projected=projectPreparedPoint(view,corner);if(projected===null){behind++;continue}minX=Math.min(minX,projected.pixel[0]);maxX=Math.max(maxX,projected.pixel[0]);minY=Math.min(minY,projected.pixel[1]);maxY=Math.max(maxY,projected.pixel[1]);if(projected.insideClip)inClip++;if(projected.insideImage&&projected.insideClip)inside++}const contained=behind===8?"behind-camera":inside===8?"full":inside>0||behind>0?"partial":inClip>0?"outside":"clipped";const pixelFootprint=behind===8?0:round3(Math.max(0,Math.min(maxX,width)-Math.max(minX,0))*Math.max(0,Math.min(maxY,height)-Math.max(minY,0)));return{contained,pixelFootprint}}function classifyViewOverlay(bounds,units,width,height){const scaleX=units==="normalized"?width:1;const scaleY=units==="normalized"?height:1;const minX=bounds.min[0]*scaleX,maxX=bounds.max[0]*scaleX;const minY=bounds.min[1]*scaleY,maxY=bounds.max[1]*scaleY;const pixelFootprint=round3(Math.max(0,Math.min(maxX,width)-Math.max(minX,0))*Math.max(0,Math.min(maxY,height)-Math.max(minY,0)));const contained=minX>=0&&minY>=0&&maxX<=width&&maxY<=height?"full":pixelFootprint>0?"partial":"outside";return{contained,pixelFootprint}}function spatialAuditDefaultTimesUs(durationUs){const count=SPATIAL_AUDIT_LIMITS.defaultSamples;return Array.from({length:count},(_,index2)=>Math.round(index2*durationUs/(count-1)))}var findingOrder=(finding)=>`${finding.kind}:${finding.entityId??""}:${String(finding.timeUs??-1).padStart(12,"0")}`;function unionBounds(items){return items.reduce((union,next)=>({min:union.min.map((value,axis2)=>Math.min(value,next.min[axis2])),max:union.max.map((value,axis2)=>Math.max(value,next.max[axis2]))}))}function instanceDomain(worldMatrix,entity,local){if(entity.kind!=="mesh"||entity.instances===undefined)return transformBounds(worldMatrix,local);return unionBounds(entity.instances.map((instance)=>transformBounds(multiplyTransforms(worldMatrix,composeTransform(instance)),local)))}function auditSpatialScene(sceneInput,options){return auditSpatialSceneInContext(createSpatialEvaluationContext(sceneInput),options)}function auditSpatialSceneInContext(context,options){const scene=context.scene;const captured=parseSpatialValue(SpatialAuditOptionsSchema,options,"audit options");const cameraId=captured.cameraId;if(!context.camerasById.has(cameraId)){throw new SpatialSceneError("not-found",`Unknown camera ${cameraId}.`,"cameraId")}const assetIds=new Set(scene.assets.map((asset)=>asset.assetId));const assetBounds=Object.create(null);for(const[assetId2,bounds]of Object.entries(captured.assetBounds??{})){if(!assetIds.has(assetId2))throw new SpatialSceneError("invalid-data",`Asset bounds reference unknown ${assetId2}.`,"assetBounds");assetBounds[assetId2]=Object.freeze({min:Object.freeze([...bounds.min]),max:Object.freeze([...bounds.max])})}const timesUs=[...new Set(captured.timesUs??spatialAuditDefaultTimesUs(scene.durationUs))].sort((a,b)=>a-b);for(const timeUs of timesUs){if(timeUs>scene.durationUs)throw new SpatialSceneError("invalid-data","Audit sample time exceeds scene duration.","timesUs")}if(scene.entities.length*timesUs.length>SPATIAL_AUDIT_LIMITS.entitySamples){throw new SpatialSceneError("invalid-data","Audit entity-sample budget exceeded; pass fewer timesUs samples.","timesUs")}const instanceTotal=scene.entities.reduce((total,entity)=>total+(entity.kind==="mesh"&&entity.instances!==undefined?entity.instances.length:1),0);if(instanceTotal*timesUs.length>SPATIAL_AUDIT_LIMITS.instanceSamples){throw new SpatialSceneError("invalid-data","Audit instance-sample budget exceeded; pass fewer timesUs samples.","timesUs")}const enclosures=new Map(scene.entities.map((entity)=>[entity.entityId,spatialEntityLocalBounds(entity,assetBounds)]));const samplesByEntity=new Map(scene.entities.map((entity)=>[entity.entityId,[]]));for(const timeUs of timesUs){const snapshot=evaluateSpatialSceneInContext(context,{timeUs,cameraId});const view=prepareCameraView(cameraMathView(snapshot.camera));const{width,height}=snapshot.camera.projection;for(const entry of snapshot.entities){const entity=entry.entity;const samples=samplesByEntity.get(entity.entityId);const placement=entity.placement;if(placement.kind==="view"&&placement.cameraId!==cameraId){samples.push({timeUs,visible:entry.visible,note:"other-camera"});continue}const enclosure=enclosures.get(entity.entityId);if(enclosure.status==="unknown"){samples.push({timeUs,visible:entry.visible});continue}try{const domain=instanceDomain(entry.worldMatrix,entity,enclosure.bounds);const frustum=placement.kind==="view"?classifyViewOverlay(domain,placement.units,width,height):classifyWorldFrustum(view,domain);samples.push({timeUs,visible:entry.visible,bounds:domain,frustum})}catch(error){if(!(error instanceof RangeError))throw error;samples.push({timeUs,visible:entry.visible,note:"out-of-range"})}}}const findings=[];const neverVisible=[];const neverInFrustum=[];const auditedEntities=[];for(const entity of scene.entities){const enclosure=enclosures.get(entity.entityId);const samples=samplesByEntity.get(entity.entityId);auditedEntities.push({entityId:entity.entityId,name:entity.name,kind:entity.kind,placement:entity.placement,enclosure:enclosure.status==="bounded"?{status:"bounded"}:{status:"unknown",reason:enclosure.reason},samples,...entity.kind==="mesh"&&entity.instances!==undefined?{instances:entity.instances.length}:{}});const applicable=samples.filter((sample)=>sample.note!=="other-camera");const visible=applicable.filter((sample)=>sample.visible);if(visible.length===0){neverVisible.push(entity.entityId);findings.push({severity:"info",kind:"never-visible",entityId:entity.entityId,detail:entity.placement.kind==="view"&&entity.placement.cameraId!==cameraId?`View-bound to ${entity.placement.cameraId}; not evaluated under ${cameraId}.`:"Effective visibility is false at every sampled time."});continue}if(enclosure.status==="unknown"){if(enclosure.reason!=="no-surface"){findings.push({severity:"info",kind:"bounds-unknown",entityId:entity.entityId,detail:enclosure.reason==="requires-asset-decoding"?"Bounds require decoded asset data; supply assetBounds to audit this entity.":"Text bounds require font layout; audited for visibility only."})}continue}const outOfRange=visible.filter((sample)=>sample.note==="out-of-range").length;if(outOfRange>0){findings.push({severity:"info",kind:"bounds-unknown",entityId:entity.entityId,detail:`World bounds exceed numeric limits at ${String(outOfRange)} visible sample${outOfRange===1?"":"s"}.`})}const statuses=visible.filter((sample)=>sample.frustum!==undefined).map((sample)=>sample.frustum.contained);if(statuses.length===0)continue;if(!statuses.some((status)=>status==="full"||status==="partial")){neverInFrustum.push(entity.entityId);if(statuses.every((status)=>status==="behind-camera")){findings.push({severity:"warning",kind:"behind-camera-all-samples",entityId:entity.entityId,detail:`Every visible sample is behind the camera plane (${String(statuses.length)} sample${statuses.length===1?"":"s"}).`})}else{const histogram=CONTAINED_HISTOGRAM_ORDER.map((status)=>[status,statuses.filter((value)=>value===status).length]).filter(([,count])=>count>0).map(([status,count])=>`${status} \xD7${String(count)}`).join(", ");findings.push({severity:"warning",kind:"off-camera",entityId:entity.entityId,detail:`Never inside the camera frustum: ${histogram} across ${String(statuses.length)} visible samples.`})}}}const visibleAtSomeSample=new Set(scene.entities.filter((entity)=>samplesByEntity.get(entity.entityId).some((sample)=>sample.visible&&sample.note!=="other-camera")).map((entity)=>entity.entityId));const shadowLights=scene.entities.filter((entity)=>entity.kind==="light"&&entity.shadow===true&&visibleAtSomeSample.has(entity.entityId));const shadowMeshes=scene.entities.filter((entity)=>entity.kind==="mesh"&&(entity.castShadow===true||entity.receiveShadow===true));if(shadowLights.length===0){for(const entity of shadowMeshes){findings.push({severity:"warning",kind:"shadows-disabled",entityId:entity.entityId,detail:"Declares shadow participation, but no evaluated light enables shadow casting; the renderer leaves shadow maps disabled."})}}else{const casters=shadowMeshes.filter((entity)=>entity.castShadow===true);const receivers=shadowMeshes.filter((entity)=>entity.receiveShadow===true);for(const light of shadowLights){if(casters.length===0||receivers.length===0){findings.push({severity:"warning",kind:"shadows-disabled",entityId:light.entityId,detail:casters.length===0&&receivers.length===0?"Enables shadow casting, but no mesh declares castShadow or receiveShadow; the shadow map renders no geometry.":casters.length===0?"Enables shadow casting, but no mesh declares castShadow; nothing writes into the shadow map.":"Enables shadow casting, but no mesh declares receiveShadow; shadows have no receiving surface."})}}}const boundedVisible=scene.entities.filter((entity)=>enclosures.get(entity.entityId).status==="bounded"&&samplesByEntity.get(entity.entityId).some((sample)=>sample.visible&&sample.note!=="other-camera")).length;const everInFrustum=scene.entities.some((entity)=>samplesByEntity.get(entity.entityId).some((sample)=>sample.visible&&(sample.frustum?.contained==="full"||sample.frustum?.contained==="partial")));if(!everInFrustum){const unknownCount=scene.entities.length-[...enclosures.values()].filter((item)=>item.status==="bounded").length;findings.push({severity:"warning",kind:"empty-scene-region",detail:`No visible bounded entity intersects the camera frustum at any sampled time (${String(boundedVisible)} bounded visible, ${String(unknownCount)} with unknown bounds).`})}const sortedFindings=sortSpatialBy(findings,findingOrder);const retainedFindings=sortedFindings.slice(0,SPATIAL_AUDIT_LIMITS.findings);const byKind=Object.fromEntries(ENTITY_KINDS.map((kind)=>[kind,0]));for(const entity of scene.entities)byKind[entity.kind]++;const properties={position:0,rotation:0,scale:0,opacity:0};for(const channel of scene.animations)properties[channel.property]++;const report={kind:"slopcamera.spatial-audit",schemaVersion:1,sceneId:scene.sceneId,sceneSha256:context.sceneSha256,cameraId,durationUs:scene.durationUs,timesUs,summary:{entities:{total:scene.entities.length,bounded:[...enclosures.values()].filter((item)=>item.status==="bounded").length,unknownBounds:[...enclosures.values()].filter((item)=>item.status==="unknown").length,byKind,instances:scene.entities.reduce((total,entity)=>total+(entity.kind==="mesh"&&entity.instances!==undefined?entity.instances.length:0),0)},animations:{channels:scene.animations.length,targets:new Set(scene.animations.map((channel)=>channel.targetId)).size,properties},cameras:scene.cameras.map((camera2)=>camera2.cameraId),entitiesNeverVisible:sortSpatialBy(neverVisible,(id)=>id),entitiesNeverInFrustum:sortSpatialBy(neverInFrustum,(id)=>id)},entities:auditedEntities,findings:retainedFindings,omittedFindings:sortedFindings.length-retainedFindings.length};const parsed=SpatialAuditReportSchema.parse(report);try{createBoundedJsonValueSnapshot(parsed,SPATIAL_AUDIT_LIMITS.reportBytes,"audit report",{maximumDepth:SPATIAL_SCENE_LIMITS.sourceDepth+8,maximumValues:SPATIAL_SCENE_LIMITS.sourceValues+SPATIAL_AUDIT_LIMITS.entitySamples*16})}catch(error){throw new SpatialSceneError("invalid-data",error instanceof Error?error.message:"Audit report exceeds its bounded size.","audit")}return deepFreezeJson(parsed)}var SpatialAuditAssetBoundsMapSchema=z7.record(SpatialAssetIdSchema,SpatialAuditBoundsSchema);var SpatialAuditAssetFactsPairSchema=z7.strictObject({manifest:SpatialAssetManifestSchema,facts:SpatialAssetFactsV1Schema});function auditSubjectBounds(manifest,facts){if(facts.subject.sha256!==manifest.payload.sha256||facts.subject.bytes!==manifest.payload.bytes){throw new SpatialSceneError("invalid-data",`Asset facts for ${manifest.assetId} do not describe the manifest payload.`,"assetBounds")}return{[manifest.assetId]:facts.bounds.sceneSpace}}function auditBoundsRecord(document){if(typeof document==="object"&&document!==null&&!Array.isArray(document)){const kind=document.kind;if(kind==="slopcamera.spatial-asset-admission"){const admission=parseSpatialValue(SpatialAssetAdmissionV1Schema,document,"asset admission");return auditSubjectBounds(admission.manifest,admission.facts)}if(kind==="slopcamera.spatial-asset-facts"){throw new SpatialSceneError("invalid-data","A slopcamera.spatial-asset-facts payload carries no assetId; pass its slopcamera.spatial-asset-admission document or a {manifest, facts} pair.","assetBounds")}const pair=SpatialAuditAssetFactsPairSchema.safeParse(document);if(pair.success)return auditSubjectBounds(pair.data.manifest,pair.data.facts);if(SpatialAuditAssetBoundsMapSchema.safeParse(document).success)return document}throw new SpatialSceneError("invalid-data","Asset bounds input accepts a Record<assetId, {min, max}> bounds map, a slopcamera.spatial-asset-admission document, a {manifest, facts} pair, or an array of those documents.","assetBounds")}function normalizeSpatialAuditAssetBounds(input){const merged=Object.create(null);for(const document of Array.isArray(input)?input:[input]){for(const[assetId2,bounds]of Object.entries(auditBoundsRecord(document))){const existing=merged[assetId2];if(existing!==undefined&&canonicalJson(existing)!==canonicalJson(bounds)){throw new SpatialSceneError("conflict",`Asset bounds input supplies conflicting scene-space bounds for ${assetId2}.`,"assetBounds")}merged[assetId2]=bounds}}return parseSpatialValue(SpatialAuditAssetBoundsMapSchema,merged,"asset bounds")}import{z as z8}from"zod";var SPATIAL_BEHAVIOR_LIMITS=Object.freeze({args:16,carry:16,cells:64,channels:64,constPorts:32,eachItems:64,edges:256,findings:128,interfacePorts:32,organisms:8,rounds:16});var organismKey=z8.string().regex(/^organism:[a-z][a-z0-9-]{0,54}$/u);var cellId=z8.string().regex(/^[a-z][a-z0-9-]{0,63}$/u);var portName=z8.string().regex(/^[a-z][a-z0-9-]{0,63}$/u);var interfaceName=z8.string().regex(/^[a-z][a-z0-9-]{0,63}$/u);var organismDigest=z8.string().regex(/^sha256:[a-f0-9]{64}$/u);var fnRef=z8.string().regex(/^[a-z][a-z0-9_.]*\.v[0-9]+$/u).max(64);var SpatialBehaviorPortTypeSchema=z8.strictObject({type:z8.enum(["text","json","choice","ref"]),optional:z8.boolean().optional(),many:z8.boolean().optional(),labels:z8.array(z8.string().min(1).max(64)).max(32).optional(),schema:z8.unknown().optional()}).superRefine((port,context)=>{if(port.labels!==undefined&&port.type!=="choice"){context.addIssue({code:"custom",message:"Only choice ports declare labels.",path:["labels"]})}if(port.schema!==undefined&&port.type!=="json"){context.addIssue({code:"custom",message:"Only json ports declare a schema.",path:["schema"]})}});var SpatialBehaviorPortMapSchema=z8.record(portName,SpatialBehaviorPortTypeSchema).refine((ports)=>Object.keys(ports).length<=SPATIAL_BEHAVIOR_LIMITS.interfacePorts,{message:`A port map admits at most ${SPATIAL_BEHAVIOR_LIMITS.interfacePorts} ports.`});var constOutput=z8.record(portName,SpatialBehaviorPortTypeSchema.extend({value:z8.unknown()})).refine((ports)=>Object.keys(ports).length<=SPATIAL_BEHAVIOR_LIMITS.constPorts,{message:`A const cell declares at most ${SPATIAL_BEHAVIOR_LIMITS.constPorts} outputs.`});var SpatialBehaviorCellSchema=z8.discriminatedUnion("kind",[z8.strictObject({id:cellId,kind:z8.literal("input"),outputs:SpatialBehaviorPortMapSchema}),z8.strictObject({id:cellId,kind:z8.literal("const"),outputs:constOutput}),z8.strictObject({id:cellId,kind:z8.literal("fn"),fn:fnRef}),z8.strictObject({id:cellId,kind:z8.literal("repeat"),manifest:organismDigest,maxRounds:z8.number().int().min(1).max(SPATIAL_BEHAVIOR_LIMITS.rounds),carry:z8.record(interfaceName,interfaceName).refine((carry)=>Object.keys(carry).length<=SPATIAL_BEHAVIOR_LIMITS.carry,{message:`A repeat cell carries at most ${SPATIAL_BEHAVIOR_LIMITS.carry} ports.`}).optional(),until:z8.strictObject({output:interfaceName,equals:z8.string().min(1).max(64),field:portName.optional()}).optional()}),z8.strictObject({id:cellId,kind:z8.literal("each"),manifest:organismDigest,over:interfaceName,maxItems:z8.number().int().min(1).max(SPATIAL_BEHAVIOR_LIMITS.eachItems)}),z8.strictObject({id:cellId,kind:z8.literal("organism"),manifest:organismDigest})]);var SpatialBehaviorEdgeSchema=z8.strictObject({from:z8.strictObject({cell:cellId,port:portName}),to:z8.strictObject({cell:cellId,port:portName}),guard:z8.strictObject({equals:z8.string().min(1).max(64),field:portName.optional()}).optional(),on:z8.literal("fail").optional()});var behaviorBudgets=z8.strictObject({maxSteps:z8.number().int().min(1).max(1024).optional(),maxAgentCalls:z8.number().int().min(0).max(64).optional(),maxWork:z8.number().int().min(1).max(1e8).optional(),maxContextBytes:z8.number().int().min(1).max(262144).optional(),maxOutputBytes:z8.number().int().min(1).max(262144).optional(),maxDepth:z8.number().int().min(1).max(8).optional()});var interfaceEndpoint=z8.strictObject({cell:cellId,port:portName});var SpatialBehaviorOrganismSchema=z8.strictObject({contract:z8.literal("morphogen.organism.v1"),key:organismKey,name:z8.string().min(1).max(120),note:z8.string().max(2000).optional(),budgets:behaviorBudgets.optional(),interface:z8.strictObject({inputs:z8.record(interfaceName,interfaceEndpoint),outputs:z8.record(interfaceName,interfaceEndpoint)}),cells:z8.array(SpatialBehaviorCellSchema).min(1).max(SPATIAL_BEHAVIOR_LIMITS.cells),edges:z8.array(SpatialBehaviorEdgeSchema).max(SPATIAL_BEHAVIOR_LIMITS.edges)}).superRefine((manifest,context)=>{const ids=new Set;for(const[index2,cell]of manifest.cells.entries()){if(ids.has(cell.id)){context.addIssue({code:"custom",message:`Duplicate cell id ${cell.id}.`,path:["cells",index2,"id"]})}ids.add(cell.id);if(cell.kind==="input"||cell.kind==="const"){for(const[name,port]of Object.entries(cell.outputs)){if(port.many===true){context.addIssue({code:"custom",message:`Port ${name} declares many, which is only valid on consumer ports.`,path:["cells",index2,"outputs",name,"many"]})}}}}});var SpatialBehaviorSchema=z8.strictObject({kind:z8.literal("slopcamera.spatial-behavior"),schemaVersion:z8.literal(1),behaviorId:z8.string().regex(/^behavior_[a-zA-Z0-9_-]{1,64}$/u),entityId:z8.string().min(1).max(128).regex(/^[a-z][a-z0-9_-]*$/u),sceneSha256:SpatialDigestSchema,seed:z8.number().int().min(0).max(4294967295),rangeUs:z8.strictObject({startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema}).refine((range)=>range.endUs>range.startUs,{message:"rangeUs.endUs must exceed rangeUs.startUs."}),organisms:z8.record(z8.string(),SpatialBehaviorOrganismSchema).refine((organisms)=>{const keys=Object.keys(organisms);return keys.length>=1&&keys.length<=SPATIAL_BEHAVIOR_LIMITS.organisms&&keys.every((key2)=>/^sha256:[a-f0-9]{64}$/u.test(key2))},{message:`organisms maps 1\u2013${SPATIAL_BEHAVIOR_LIMITS.organisms} sha256:<64-hex> digests to manifests.`}),entry:organismDigest,channels:z8.array(z8.string().regex(/^[a-z][a-z0-9_.-]{0,62}$/u)).min(1).max(SPATIAL_BEHAVIOR_LIMITS.channels),args:z8.record(interfaceName,z8.unknown()).refine((args)=>Object.keys(args).length<=SPATIAL_BEHAVIOR_LIMITS.args,{message:`At most ${SPATIAL_BEHAVIOR_LIMITS.args} entry args.`}).optional()}).superRefine((behavior,context)=>{const channelSet=new Set(behavior.channels);if(channelSet.size!==behavior.channels.length){context.addIssue({code:"custom",message:"Behavior channels must be unique.",path:["channels"]})}});function parseSpatialBehavior(input){return deepFreezeJson(parseSpatialValue(SpatialBehaviorSchema,input,"spatial behavior"))}function spatialBehaviorSha256(behavior){return spatialValueSha256(behavior)}var ALGAL_DEFAULT_BUDGETS=Object.freeze({maxSteps:256,maxAgentCalls:16,maxWork:1e6,maxContextBytes:65536,maxOutputBytes:65536,maxDepth:4});function portTypeJson(port){const out={type:port.type};if(port.optional===true)out.optional=true;if(port.many===true)out.many=true;if(port.type==="choice"&&port.labels!==undefined)out.labels=[...port.labels];if(port.type==="json"&&port.schema!==undefined)out.schema=port.schema;return out}function cellJson(cell){switch(cell.kind){case"input":return{id:cell.id,kind:cell.kind,outputs:portMapJson(cell.outputs)};case"const":{const outputs={};for(const[name,port]of Object.entries(cell.outputs)){const projected=portTypeJson(port);projected.value=port.value;outputs[name]=projected}return{id:cell.id,kind:cell.kind,outputs}}case"fn":return{id:cell.id,kind:cell.kind,fn:cell.fn};case"organism":return{id:cell.id,kind:cell.kind,manifest:cell.manifest};case"repeat":{const out={id:cell.id,kind:cell.kind,manifest:cell.manifest,maxRounds:cell.maxRounds};if(cell.carry!==undefined)out.carry={...cell.carry};if(cell.until!==undefined){out.until={output:cell.until.output,equals:cell.until.equals,...cell.until.field===undefined?{}:{field:cell.until.field}}}return out}case"each":return{id:cell.id,kind:cell.kind,manifest:cell.manifest,over:cell.over,maxItems:cell.maxItems}}}function portMapJson(ports){const out={};for(const[name,port]of Object.entries(ports))out[name]=portTypeJson(port);return out}function behaviorOrganismCanonicalValue(manifest){const budgets={...ALGAL_DEFAULT_BUDGETS,...manifest.budgets??{}};const out={contract:manifest.contract,key:manifest.key,name:manifest.name,budgets:{maxAgentCalls:budgets.maxAgentCalls,maxContextBytes:budgets.maxContextBytes,maxDepth:budgets.maxDepth,maxOutputBytes:budgets.maxOutputBytes,maxSteps:budgets.maxSteps,maxWork:budgets.maxWork},cells:manifest.cells.map(cellJson),edges:manifest.edges.map((edge)=>({from:{cell:edge.from.cell,port:edge.from.port},to:{cell:edge.to.cell,port:edge.to.port},...edge.on===undefined?{}:{on:edge.on},...edge.guard===undefined?{}:{guard:{equals:edge.guard.equals,...edge.guard.field===undefined?{}:{field:edge.guard.field}}}}))};if(manifest.note!==undefined)out.note=manifest.note;const mapEnds=(endpoints)=>{const mapped={};for(const[name,target]of Object.entries(endpoints))mapped[name]={cell:target.cell,port:target.port};return mapped};out.interface={inputs:mapEnds(manifest.interface.inputs),outputs:mapEnds(manifest.interface.outputs)};return out}function behaviorOrganismSha256(manifest){return`sha256:${boundedCanonicalJsonSha256(behaviorOrganismCanonicalValue(manifest),{maximumBytes:262144,name:"behavior organism"})}`}var SpatialBehaviorFindingCodeSchema=z8.enum(["stale-digest","unresolved-entity","unresolved-entry","unresolved-manifest","unresolved-fn","closure-digest-mismatch","invalid-wiring","undeclared-arg","range-outside-scene","unreachable-organism","cyclic-composition","unfed-input"]);var SpatialBehaviorCheckFindingSchema=z8.strictObject({code:SpatialBehaviorFindingCodeSchema,severity:z8.enum(["error","warning"]),referenceId:z8.string().min(1).max(128).optional(),detail:z8.string().min(1).max(240)});var SpatialBehaviorCheckReportSchema=z8.strictObject({kind:z8.literal("slopcamera.spatial-behavior-check"),schemaVersion:z8.literal(1),behaviorSha256:SpatialDigestSchema,sceneSha256:SpatialDigestSchema,findings:z8.array(SpatialBehaviorCheckFindingSchema).max(SPATIAL_BEHAVIOR_LIMITS.findings),counts:z8.strictObject({organisms:z8.number().int().min(0),cells:z8.number().int().min(0),edges:z8.number().int().min(0),fnRefs:z8.number().int().min(0),errors:z8.number().int().min(0),warnings:z8.number().int().min(0)})});var checkOptionsSchema=z8.strictObject({behavior:z8.unknown(),scene:z8.unknown()});function resolveEntityId(scene,referenceId){const ids=new Set(scene.entities.map((entity)=>entity.entityId));if(ids.has(referenceId))return referenceId;const prefixed=`entity_${referenceId}`;return ids.has(prefixed)?prefixed:undefined}function checkSpatialBehavior(input,admittedFns){const options=parseSpatialValue(checkOptionsSchema,input,"behavior check");const behavior=parseSpatialBehavior(options.behavior);const scene=parseSpatialValue(SpatialSceneV1Schema,options.scene,"scene");const sceneSha256=spatialValueSha256(scene);const findings=[];const finding=(code,severity,detail,referenceId)=>{findings.push(deepFreezeJson(referenceId===undefined?{code,severity,detail}:{code,severity,detail,referenceId}))};if(behavior.sceneSha256!==sceneSha256){finding("stale-digest","error",`Behavior sceneSha256 ${behavior.sceneSha256} does not match scene digest ${sceneSha256}; re-author or rebind the behavior.`)}if(resolveEntityId(scene,behavior.entityId)===undefined){finding("unresolved-entity","error",`Behavior entity ${behavior.entityId} is not a scene entity.`,behavior.entityId)}if(behavior.rangeUs.endUs>scene.durationUs){finding("range-outside-scene","error",`Behavior range ends at ${behavior.rangeUs.endUs}us beyond scene duration ${scene.durationUs}us.`)}if(behavior.organisms[behavior.entry]===undefined){finding("unresolved-entry","error",`Entry digest ${behavior.entry.slice(0,24)}\u2026 is not a member of the organisms closure.`,behavior.entry.slice(7,39))}let cellTotal=0;let edgeTotal=0;let fnRefTotal=0;const contexts=new Map;for(const[digest,manifest]of Object.entries(behavior.organisms)){const recomputed=behaviorOrganismSha256(manifest);if(recomputed!==digest){finding("closure-digest-mismatch","error",`Organisms key ${digest.slice(0,24)}\u2026 rehashes to ${recomputed.slice(0,24)}\u2026; the manifest changed after admission.`,manifest.key)}cellTotal+=manifest.cells.length;edgeTotal+=manifest.edges.length;const outputPorts=new Map;const inputPorts=new Map;for(const cell of manifest.cells){switch(cell.kind){case"input":case"const":outputPorts.set(cell.id,new Set(Object.keys(cell.outputs)));break;case"fn":{fnRefTotal+=1;const signature=admittedFns.get(cell.fn);if(signature===undefined){finding("unresolved-fn","error",`Cell ${cell.id} names fn ${cell.fn}, which the admitted behavior catalog does not contain.`,`${manifest.key}/${cell.id}`)}else{outputPorts.set(cell.id,new Set(Object.keys(signature.outputs)));inputPorts.set(cell.id,new Set(Object.keys(signature.inputs)))}break}case"repeat":case"each":case"organism":{const child=behavior.organisms[cell.manifest];if(child===undefined){finding("unresolved-manifest","error",`Cell ${cell.id} references manifest ${cell.manifest.slice(0,24)}\u2026, absent from the organisms closure.`,`${manifest.key}/${cell.id}`)}else{outputPorts.set(cell.id,new Set(Object.keys(child.interface.outputs)));inputPorts.set(cell.id,new Set(Object.keys(child.interface.inputs)))}break}}}contexts.set(digest,{manifest,outputPorts,inputPorts})}for(const context of contexts.values()){const{manifest,outputPorts,inputPorts}=context;const cellIds=new Set(manifest.cells.map((cell)=>cell.id));const ref=(cell)=>`${manifest.key}/${cell}`;for(const[name,endpoint]of Object.entries(manifest.interface.inputs)){const cell=manifest.cells.find((candidate)=>candidate.id===endpoint.cell);if(cell===undefined){finding("invalid-wiring","error",`Interface input ${name} references absent cell ${endpoint.cell}.`,manifest.key)}else if(cell.kind!=="input"){finding("invalid-wiring","error",`Interface input ${name} references ${cell.kind} cell ${cell.id}; only input cells receive entry args.`,ref(cell.id))}else if(!(endpoint.port in cell.outputs)){finding("invalid-wiring","error",`Interface input ${name} names undeclared port ${endpoint.port} on input cell ${cell.id}.`,ref(cell.id))}}for(const[name,endpoint]of Object.entries(manifest.interface.outputs)){if(!cellIds.has(endpoint.cell)){finding("invalid-wiring","error",`Interface output ${name} references absent cell ${endpoint.cell}.`,manifest.key)}else if(!outputPorts.get(endpoint.cell)?.has(endpoint.port)){finding("invalid-wiring","error",`Interface output ${name} names undeclared output port ${endpoint.port} on cell ${endpoint.cell}.`,ref(endpoint.cell))}}for(const cell of manifest.cells){if(cell.kind==="repeat"||cell.kind==="each"||cell.kind==="organism"){const child=behavior.organisms[cell.manifest];if(child!==undefined){if(cell.kind==="repeat"){for(const[outName,inName]of Object.entries(cell.carry??{})){if(!(outName in child.interface.outputs)){finding("invalid-wiring","error",`Repeat ${cell.id} carries undeclared output ${outName} from ${child.key}.`,ref(cell.id))}if(!(inName in child.interface.inputs)){finding("invalid-wiring","error",`Repeat ${cell.id} carries into undeclared input ${inName} on ${child.key}.`,ref(cell.id))}}if(cell.until!==undefined&&!(cell.until.output in child.interface.outputs)){finding("invalid-wiring","error",`Repeat ${cell.id} until watches undeclared output ${cell.until.output} on ${child.key}.`,ref(cell.id))}}if(cell.kind==="each"&&!(cell.over in child.interface.inputs)){finding("invalid-wiring","error",`Each ${cell.id} over names undeclared input ${cell.over} on ${child.key}.`,ref(cell.id))}const carried=cell.kind==="repeat"?new Set(Object.values(cell.carry??{})):new Set;for(const input2 of Object.keys(child.interface.inputs)){if(carried.has(input2))continue;if(cell.kind==="each"&&input2===cell.over)continue;const fed=manifest.edges.some((edge)=>edge.to.cell===cell.id&&edge.to.port===input2);if(!fed){finding("unfed-input","warning",`${cell.kind} cell ${cell.id} leaves interface input ${input2} of ${child.key} without a delivering edge; the input cell produces no value.`,ref(cell.id))}}}}if(cell.kind==="each"){const delivered=manifest.edges.some((edge)=>edge.to.cell===cell.id&&edge.to.port===cell.over);if(!delivered){finding("invalid-wiring","error",`Each ${cell.id} over port ${cell.over} has no delivering edge; the list can never arrive.`,ref(cell.id))}}}for(const[index2,edge]of manifest.edges.entries()){if(!cellIds.has(edge.from.cell)){finding("invalid-wiring","error",`Edge ${index2} from references absent cell ${edge.from.cell}.`,manifest.key)}else if(!outputPorts.get(edge.from.cell)?.has(edge.from.port)){finding("invalid-wiring","error",`Edge ${index2} names undeclared output port ${edge.from.port} on cell ${edge.from.cell}.`,ref(edge.from.cell))}if(!cellIds.has(edge.to.cell)){finding("invalid-wiring","error",`Edge ${index2} to references absent cell ${edge.to.cell}.`,manifest.key)}else if(!inputPorts.get(edge.to.cell)?.has(edge.to.port)){finding("invalid-wiring","error",`Edge ${index2} names undeclared input port ${edge.to.port} on cell ${edge.to.cell}; input and const cells have no input ports.`,ref(edge.to.cell))}}}const visiting=new Set;const done=new Set;const detectCycles=(digest)=>{if(done.has(digest))return;if(visiting.has(digest)){const context2=contexts.get(digest);finding("cyclic-composition","error",`Organism ${context2?.manifest.key??digest.slice(0,24)} participates in a manifest-reference cycle that cannot terminate within any depth budget.`,context2?.manifest.key);return}visiting.add(digest);const context=contexts.get(digest);if(context!==undefined){for(const cell of context.manifest.cells){if(cell.kind==="repeat"||cell.kind==="each"||cell.kind==="organism")detectCycles(cell.manifest)}}visiting.delete(digest);done.add(digest)};for(const digest of contexts.keys())detectCycles(digest);const reachable=new Set;const walk=(digest)=>{if(reachable.has(digest))return;const context=contexts.get(digest);if(context===undefined)return;reachable.add(digest);for(const cell of context.manifest.cells){if(cell.kind==="repeat"||cell.kind==="each"||cell.kind==="organism")walk(cell.manifest)}};walk(behavior.entry);for(const[entryDigest,context]of contexts){if(!reachable.has(entryDigest)){finding("unreachable-organism","warning",`Organism ${context.manifest.key} is in the closure but unreachable from the entry manifest.`,context.manifest.key)}}const entryContext=contexts.get(behavior.entry);if(entryContext!==undefined){const argNames=new Set(Object.keys(behavior.args??{}));for(const name of Object.keys(behavior.args??{})){if(!(name in entryContext.manifest.interface.inputs)){finding("undeclared-arg","error",`Arg ${name} is not a declared interface input of entry organism ${entryContext.manifest.key}.`,`${entryContext.manifest.key}/${name}`)}}for(const name of Object.keys(entryContext.manifest.interface.inputs)){if(!argNames.has(name)&&name!=="seed"){finding("unfed-input","warning",`Entry organism ${entryContext.manifest.key} declares interface input ${name} but no arg binds it; the input cell produces no value.`,`${entryContext.manifest.key}/${name}`)}}}const errors=findings.filter((item)=>item.severity==="error").length;return deepFreezeJson(SpatialBehaviorCheckReportSchema.parse({kind:"slopcamera.spatial-behavior-check",schemaVersion:1,behaviorSha256:spatialBehaviorSha256(behavior),sceneSha256,findings,counts:{organisms:Object.keys(behavior.organisms).length,cells:cellTotal,edges:edgeTotal,fnRefs:fnRefTotal,errors,warnings:findings.length-errors}}))}import{z as z9}from"zod";var SPATIAL_BEHAVIOR_AUDIT_LIMITS=Object.freeze({findings:128,channels:64});var SpatialBehaviorAuditFindingKindSchema=z9.enum(["state-thrash","exact-periodicity","dead-channel","unreachable-state"]);var SpatialBehaviorAuditFindingSchema=z9.strictObject({kind:SpatialBehaviorAuditFindingKindSchema,channel:z9.string().min(1).max(64),severity:z9.enum(["warning","info"]),detail:z9.string().min(1).max(240),measured:z9.number().finite().optional(),limit:z9.number().finite().optional()});var SpatialBehaviorAuditOptionsSchema=z9.strictObject({maxTransitionsPerSecond:z9.number().int().min(1).max(1000).default(10),minDistinctValues:z9.number().int().min(2).max(100).default(2),maxPeriodicityWindowUs:z9.number().int().min(1e5).max(60000000).default(5000000)});var SpatialBehaviorAuditReportSchema=z9.strictObject({kind:z9.literal("slopcamera.spatial-behavior-audit-report"),schemaVersion:z9.literal(1),behaviorSha256:SpatialDigestSchema,emittedSha256:SpatialDigestSchema,rangeUs:z9.strictObject({startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema}),emittedCount:z9.number().int().min(0),channelCount:z9.number().int().min(0),findings:z9.array(SpatialBehaviorAuditFindingSchema).max(SPATIAL_BEHAVIOR_AUDIT_LIMITS.findings),omittedFindings:z9.number().int().min(0)});function spatialBehaviorAuditReportSha256(report){return spatialValueSha256(report)}var valueKey=(value)=>{if(typeof value==="string")return value;if(typeof value==="number")return`n:${value}`;if(typeof value==="boolean")return`b:${value?1:0}`;try{return JSON.stringify(value)}catch{return"\x00"}};function groupByChannel(emitted){const groups=new Map;for(const record of emitted){let list=groups.get(record.channel);if(list===undefined){list=[];groups.set(record.channel,list)}list.push(record)}const result=new Map;for(const[channel,records]of groups){const values2=records.map((record)=>valueKey(record.value));result.set(channel,{channel,records,values:values2,distinctValues:new Set(values2)})}return result}function checkStateThrash(trace,maxTransitionsPerSecond,findings){const{records,values:values2}=trace;if(records.length<3)return;const windowUs=1e6;let windowStart=0;let transitions=0;let maxSeen=0;for(let i=1;i<records.length;i+=1){if(values2[i]!==values2[i-1])transitions+=1;while(windowStart<i&&records[i].tUs-records[windowStart].tUs>windowUs){if(values2[windowStart+1]!==values2[windowStart])transitions-=1;windowStart+=1}maxSeen=Math.max(maxSeen,transitions)}if(maxSeen>maxTransitionsPerSecond){findings.push({kind:"state-thrash",channel:trace.channel,severity:"warning",detail:`${maxSeen} transitions/sec in a 1s window exceeds ${maxTransitionsPerSecond}/sec threshold.`,measured:maxSeen,limit:maxTransitionsPerSecond})}}function checkDeadChannel(trace,minDistinct,findings){if(trace.records.length<2)return;if(trace.distinctValues.size<minDistinct){findings.push({kind:"dead-channel",channel:trace.channel,severity:"info",detail:`Channel emits ${trace.distinctValues.size} distinct value(s) across ${trace.records.length} records.`,measured:trace.distinctValues.size,limit:minDistinct})}}function checkExactPeriodicity(trace,maxWindowUs,findings){const{records,values:values2}=trace;if(records.length<6)return;const rangeUs=records[records.length-1].tUs-records[0].tUs;if(rangeUs<=0)return;const halfLen=Math.floor(values2.length/2);const maxPeriod=Math.min(halfLen,Math.floor(values2.length*maxWindowUs/rangeUs));for(let period=2;period<=maxPeriod;period+=1){let match=true;for(let i=period;i<values2.length;i+=1){if(values2[i]!==values2[i-period]){match=false;break}}if(match){findings.push({kind:"exact-periodicity",channel:trace.channel,severity:"info",detail:`Values repeat exactly every ${period} records \u2014 the behavior may be trivially cyclic.`,measured:period});return}}}function checkUnreachableStates(channels,findings){for(const[channel,trace]of channels){const transitionChannel=`${channel}.transition`;const transitionTrace=channels.get(transitionChannel);if(transitionTrace===undefined)continue;const visited=new Set;for(const value of trace.values){if(typeof value==="string")visited.add(value)}const referenced=new Set;for(const record of transitionTrace.records){const value=record.value;if(value!==null&&typeof value==="object"&&!Array.isArray(value)){const typed=value;if(typeof typed.to==="string")referenced.add(typed.to);if(typeof typed.from==="string")referenced.add(typed.from)}}for(const state of referenced){if(!visited.has(state)){findings.push({kind:"unreachable-state",channel,severity:"warning",detail:`State "${state}" appears in ${transitionChannel} transitions but never as the current ${channel} value.`})}}}}var auditInputSchema=z9.strictObject({emitted:z9.array(z9.strictObject({tUs:SpatialTimeUsSchema,channel:z9.string().min(1).max(64),value:z9.unknown()})).max(16384),behaviorSha256:SpatialDigestSchema,emittedSha256:SpatialDigestSchema,rangeUs:z9.strictObject({startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema}),options:SpatialBehaviorAuditOptionsSchema.optional()});function auditSpatialBehaviorTrace(input){const parsed=parseSpatialValue(auditInputSchema,input,"behavior audit");const options=parsed.options??SpatialBehaviorAuditOptionsSchema.parse({});const channels=groupByChannel(parsed.emitted);const findings=[];for(const trace of channels.values()){if(findings.length>=SPATIAL_BEHAVIOR_AUDIT_LIMITS.findings)break;checkStateThrash(trace,options.maxTransitionsPerSecond,findings);checkDeadChannel(trace,options.minDistinctValues,findings);checkExactPeriodicity(trace,options.maxPeriodicityWindowUs,findings)}checkUnreachableStates(channels,findings);const bounded=findings.slice(0,SPATIAL_BEHAVIOR_AUDIT_LIMITS.findings);const omitted=findings.length-bounded.length;return deepFreezeJson(SpatialBehaviorAuditReportSchema.parse({kind:"slopcamera.spatial-behavior-audit-report",schemaVersion:1,behaviorSha256:parsed.behaviorSha256,emittedSha256:parsed.emittedSha256,rangeUs:parsed.rangeUs,emittedCount:parsed.emitted.length,channelCount:channels.size,findings:bounded,omittedFindings:omitted}))}import{z as z10}from"zod";var SPATIAL_BEHAVIOR_FN_LIMITS=Object.freeze({drawsPerCall:256,emittedPerCall:4096,fsmStates:16,fsmTransitions:64,gazeTargets:8,layers:8,moodChannels:8,obsFlags:32,pairs:8,phases:8,positionsPerTick:8,ticksPerWindow:512});class SpatialBehaviorFnError extends Error{code;constructor(code,detail){super(detail);this.name="SpatialBehaviorFnError";this.code=code}}var uint=z10.number().int().min(0).max(Number.MAX_SAFE_INTEGER);var channelName=z10.string().regex(/^[a-z][a-z0-9_.-]{0,62}$/u);var kebabName=z10.string().regex(/^[a-z][a-z0-9-]{0,62}$/u);function parseSpec(schema,input,fn,field){const parsed=schema.safeParse(input??null);if(!parsed.success){const issue=parsed.error.issues[0];throw new SpatialBehaviorFnError(field==="state"?"invalid-state":"invalid-input",`${fn}: ${field} invalid \u2014 ${issue?.message??"schema mismatch"}`)}return parsed.data}function requireField(inputs,name,fn){const value=inputs[name];if(value===undefined)throw new SpatialBehaviorFnError("invalid-input",`${fn}: missing required input ${name}`);return value}function rngNext(state){const next=state+1831565813>>>0;let t=next;t=Math.imul(t^t>>>15,t|1);t^=t+Math.imul(t^t>>>7,t|61);return{value:((t^t>>>14)>>>0)/4294967296,next}}function drawStream(seed,count){const draws=[];let state=seed>>>0;for(let i=0;i<count;i+=1){const drawn=rngNext(state);draws.push(drawn.value);state=drawn.next}return{draws,next:state}}var obsSchema=z10.strictObject({draw:z10.number().min(0).max(1).optional(),flags:z10.record(kebabName,z10.boolean()).refine((flags)=>Object.keys(flags).length<=SPATIAL_BEHAVIOR_FN_LIMITS.obsFlags,{message:`At most ${SPATIAL_BEHAVIOR_FN_LIMITS.obsFlags} obs flags per tick.`}).optional(),distances:z10.record(kebabName,z10.number().min(0)).refine((distances)=>Object.keys(distances).length<=SPATIAL_BEHAVIOR_FN_LIMITS.obsFlags,{message:`At most ${SPATIAL_BEHAVIOR_FN_LIMITS.obsFlags} obs distances per tick.`}).optional()});var windowSchema=z10.strictObject({ticks:z10.array(z10.strictObject({tUs:uint,obs:obsSchema.optional(),positions:z10.record(kebabName,z10.tuple([z10.number(),z10.number(),z10.number()])).refine((positions)=>Object.keys(positions).length<=SPATIAL_BEHAVIOR_FN_LIMITS.positionsPerTick,{message:`At most ${SPATIAL_BEHAVIOR_FN_LIMITS.positionsPerTick} positions per tick.`}).optional()})).min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.ticksPerWindow)}).superRefine((window,context)=>{for(let i=1;i<window.ticks.length;i+=1){const previous=window.ticks[i-1]?.tUs??0;const current=window.ticks[i]?.tUs??0;if(current<=previous){context.addIssue({code:"custom",message:"window.ticks must be strictly increasing in tUs.",path:["ticks",i,"tUs"]})}}});var emittedSchema=z10.array(z10.strictObject({tUs:uint,channel:channelName,value:z10.unknown()})).max(SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall);function emit(emitted,tUs,channel,value){if(emitted.length>=SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall){throw new SpatialBehaviorFnError("over-bound",`Emitted records exceed ${SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall} per call.`)}emitted.push({tUs,channel,value})}var rngInputs=z10.strictObject({seed:uint,count:z10.number().int().min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.drawsPerCall),stream:uint.optional()});function rngSeeded(inputs){const spec=parseSpec(rngInputs,{seed:inputs.seed,count:inputs.count,stream:inputs.stream},"rng.seeded.v1","inputs");const salted=(spec.seed^Math.imul(spec.stream??0,2654435769))>>>0;const{draws,next}=drawStream(salted,spec.count);return{draws,next}}var fsmGuardSchema=z10.discriminatedUnion("kind",[z10.strictObject({kind:z10.literal("after"),us:uint}),z10.strictObject({kind:z10.literal("chance"),threshold:z10.number().min(0).max(1)}),z10.strictObject({kind:z10.literal("flag"),name:kebabName}),z10.strictObject({kind:z10.literal("clear"),name:kebabName}),z10.strictObject({kind:z10.literal("always")})]);var fsmMachineSchema=z10.strictObject({channel:channelName,states:z10.array(kebabName).min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.fsmStates),transitions:z10.array(z10.strictObject({from:kebabName,to:kebabName,guard:fsmGuardSchema})).max(SPATIAL_BEHAVIOR_FN_LIMITS.fsmTransitions),minDwellUs:uint.optional()}).superRefine((machine,context)=>{const states=new Set(machine.states);if(states.size!==machine.states.length){context.addIssue({code:"custom",message:"machine.states must be unique.",path:["states"]})}for(const[index2,transition]of machine.transitions.entries()){if(!states.has(transition.from))context.addIssue({code:"custom",message:`Transition from undeclared state ${transition.from}.`,path:["transitions",index2,"from"]});if(!states.has(transition.to))context.addIssue({code:"custom",message:`Transition to undeclared state ${transition.to}.`,path:["transitions",index2,"to"]})}});var fsmStateSchema=z10.strictObject({name:kebabName,enteredUs:uint});function guardPasses(guard,elapsedUs,obs,fn){switch(guard.kind){case"after":return elapsedUs>=guard.us;case"chance":{if(obs?.draw===undefined){throw new SpatialBehaviorFnError("invalid-input",`${fn}: a chance guard fired with no obs.draw supplied for the tick`)}return obs.draw<guard.threshold}case"flag":return obs?.flags?.[guard.name]===true;case"clear":return obs?.flags?.[guard.name]!==true;case"always":return true}}function behaviorFsm(inputs){const machine=parseSpec(fsmMachineSchema,inputs.machine,"behavior.fsm.v1","machine");const state=parseSpec(fsmStateSchema,requireField(inputs,"state","behavior.fsm.v1"),"behavior.fsm.v1","state");const window=parseSpec(windowSchema,requireField(inputs,"window","behavior.fsm.v1"),"behavior.fsm.v1","window");if(!machine.states.includes(state.name)){throw new SpatialBehaviorFnError("invalid-state",`behavior.fsm.v1: state ${state.name} is not declared in machine.states`)}const emitted=[];let current={...state};for(const tick of window.ticks){const elapsedUs=Math.max(0,tick.tUs-current.enteredUs);if(machine.minDwellUs===undefined||elapsedUs>=machine.minDwellUs){const fired=machine.transitions.find((transition)=>transition.from===current.name&&guardPasses(transition.guard,elapsedUs,tick.obs,"behavior.fsm.v1"));if(fired!==undefined){emit(emitted,tick.tUs,`${machine.channel}.transition`,{from:current.name,to:fired.to,guard:fired.guard.kind});current={name:fired.to,enteredUs:tick.tUs}}}emit(emitted,tick.tUs,machine.channel,current.name)}return{next:current,emitted}}var expressionSpecSchema=z10.strictObject({channel:channelName,seed:uint,blinkEveryUs:z10.number().int().min(1e5).max(60000000),blinkUs:z10.number().int().min(1e4).max(1e6),saccadeEveryUs:z10.number().int().min(50000).max(60000000),gazeTargets:z10.array(kebabName).min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.gazeTargets),mood:z10.record(kebabName,z10.number().min(0).max(1)).refine((mood)=>Object.keys(mood).length<=SPATIAL_BEHAVIOR_FN_LIMITS.moodChannels,{message:`At most ${SPATIAL_BEHAVIOR_FN_LIMITS.moodChannels} mood channels.`})});var expressionStateSchema=z10.strictObject({rng:uint,nextBlinkUs:uint,nextSaccadeUs:uint,gazeIndex:z10.number().int().min(0).max(SPATIAL_BEHAVIOR_FN_LIMITS.gazeTargets-1)});function behaviorExpression(inputs){const spec=parseSpec(expressionSpecSchema,inputs.spec,"behavior.expression.v1","spec");const state=parseSpec(expressionStateSchema,requireField(inputs,"state","behavior.expression.v1"),"behavior.expression.v1","state");const window=parseSpec(windowSchema,requireField(inputs,"window","behavior.expression.v1"),"behavior.expression.v1","window");if(state.gazeIndex>=spec.gazeTargets.length){throw new SpatialBehaviorFnError("invalid-state",`behavior.expression.v1: state.gazeIndex ${state.gazeIndex} exceeds gazeTargets`)}const emitted=[];let{rng,nextBlinkUs,nextSaccadeUs,gazeIndex}=state;for(const tick of window.ticks){if(tick.tUs>=nextSaccadeUs){const draw=rngNext(rng);rng=draw.next;const step=spec.gazeTargets.length===1?0:1+Math.floor(draw.value*(spec.gazeTargets.length-1));gazeIndex=(gazeIndex+step)%spec.gazeTargets.length;const jitter=rngNext(rng);rng=jitter.next;nextSaccadeUs=tick.tUs+spec.saccadeEveryUs+Math.floor(jitter.value*spec.saccadeEveryUs*0.5)}if(tick.tUs>=nextBlinkUs+spec.blinkUs){const jitter=rngNext(rng);rng=jitter.next;nextBlinkUs=tick.tUs+spec.blinkEveryUs+Math.floor(jitter.value*spec.blinkEveryUs*0.5)}const blinking=tick.tUs>=nextBlinkUs&&tick.tUs<nextBlinkUs+spec.blinkUs;emit(emitted,tick.tUs,`${spec.channel}.blink`,blinking?1:0);emit(emitted,tick.tUs,`${spec.channel}.gaze`,spec.gazeTargets[gazeIndex]??spec.gazeTargets[0]??"center");emit(emitted,tick.tUs,`${spec.channel}.mood`,spec.mood)}return{next:{rng,nextBlinkUs,nextSaccadeUs,gazeIndex},emitted}}var interactSpecSchema=z10.strictObject({channel:channelName,phases:z10.array(z10.strictObject({name:kebabName,minUs:uint,emit:z10.array(z10.strictObject({channel:channelName,value:z10.unknown()})).max(8).optional()})).min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.phases),loop:z10.boolean().optional()});var interactStateSchema=z10.strictObject({phaseIndex:z10.number().int().min(0).max(SPATIAL_BEHAVIOR_FN_LIMITS.phases-1),enteredUs:uint});function behaviorInteract(inputs){const spec=parseSpec(interactSpecSchema,inputs.spec,"behavior.interact.v1","spec");const state=parseSpec(interactStateSchema,requireField(inputs,"state","behavior.interact.v1"),"behavior.interact.v1","state");const window=parseSpec(windowSchema,requireField(inputs,"window","behavior.interact.v1"),"behavior.interact.v1","window");if(state.phaseIndex>=spec.phases.length){throw new SpatialBehaviorFnError("invalid-state",`behavior.interact.v1: state.phaseIndex ${state.phaseIndex} exceeds phases`)}const emitted=[];let{phaseIndex,enteredUs}=state;for(const tick of window.ticks){let advanced=true;while(advanced){advanced=false;const phase=spec.phases[phaseIndex];if(phase!==undefined&&tick.tUs-enteredUs>=phase.minUs){const last=phaseIndex+1>=spec.phases.length;if(!last||spec.loop===true){const nextIndex=last?0:phaseIndex+1;const entered=spec.phases[nextIndex];emit(emitted,tick.tUs,`${spec.channel}.phase`,{from:phase.name,to:entered?.name??phase.name});for(const record of entered?.emit??[]){emit(emitted,tick.tUs,record.channel,record.value)}phaseIndex=nextIndex;enteredUs=tick.tUs;advanced=true}}}emit(emitted,tick.tUs,spec.channel,spec.phases[phaseIndex]?.name??"done")}return{next:{phaseIndex,enteredUs},emitted}}function channelEmit(inputs){const channel=parseSpec(channelName,inputs.channel,"channel.emit.v1","channel");const window=parseSpec(windowSchema,requireField(inputs,"window","channel.emit.v1"),"channel.emit.v1","window");const value=inputs.value??null;const emitted=[];for(const tick of window.ticks)emit(emitted,tick.tUs,channel,value);return{emitted}}var sampleSpecSchema=z10.strictObject({pairs:z10.array(z10.strictObject({a:kebabName,b:kebabName,within:z10.number().min(0).max(100)})).min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.pairs)});function sceneSample(inputs){const spec=parseSpec(sampleSpecSchema,inputs.spec,"scene.sample.v1","spec");const window=parseSpec(windowSchema,requireField(inputs,"window","scene.sample.v1"),"scene.sample.v1","window");const ticks=window.ticks.map((tick)=>{const positions=tick.positions??{};const flags={};const distances={};for(const pair of spec.pairs){const a=positions[pair.a];const b=positions[pair.b];if(a===undefined||b===undefined){throw new SpatialBehaviorFnError("invalid-input",`scene.sample.v1: pair ${pair.a}/${pair.b} missing positions at ${tick.tUs}us`)}const distance=Math.hypot(a[0]-b[0],a[1]-b[1],a[2]-b[2]);const key2=`${pair.a}-${pair.b}`;distances[`dist-${key2}`]=Math.round(distance*1e6)/1e6;flags[`contact-${key2}`]=distance<=pair.within}const obs={...tick.obs??{},flags:{...tick.obs?.flags??{},...flags},distances:{...tick.obs?.distances??{},...distances}};return{tUs:tick.tUs,obs}});return{window:{ticks}}}var combineInputs=z10.strictObject({layers:z10.array(z10.strictObject({priority:z10.number().int().min(0).max(1000),emitted:emittedSchema})).min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.layers)});function behaviorCombine(inputs){const spec=parseSpec(combineInputs,{layers:inputs.layers},"behavior.combine.v1","layers");const winners=new Map;spec.layers.forEach((layer,layerIndex)=>{for(const record of layer.emitted){const key2=`${record.tUs}${record.channel}`;const held=winners.get(key2);if(held===undefined||layer.priority>held.priority){winners.set(key2,{priority:layer.priority,order:layerIndex,record})}}});const merged=[...winners.values()].sort((left,right)=>left.record.tUs-right.record.tUs||(left.record.channel<right.record.channel?-1:left.record.channel>right.record.channel?1:0)||left.order-right.order).map((entry)=>entry.record);if(merged.length>SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall){throw new SpatialBehaviorFnError("over-bound",`behavior.combine.v1: merged emissions exceed ${SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall}`)}return{emitted:merged}}var appendInputs=z10.strictObject({prior:emittedSchema,fresh:emittedSchema});function emittedAppend(inputs){const spec=parseSpec(appendInputs,{prior:inputs.prior,fresh:inputs.fresh},"emitted.append.v1","prior");const merged=[...spec.prior,...spec.fresh].sort((left,right)=>left.tUs-right.tUs||(left.channel<right.channel?-1:left.channel>right.channel?1:0));if(merged.length>SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall){throw new SpatialBehaviorFnError("over-bound",`emitted.append.v1: accumulated emissions exceed ${SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall}`)}return{emitted:merged}}var flattenInputs=z10.strictObject({nested:z10.array(emittedSchema).max(SPATIAL_BEHAVIOR_FN_LIMITS.layers)});function emittedFlatten(inputs){const spec=parseSpec(flattenInputs,{nested:inputs.nested},"emitted.flatten.v1","nested");const merged=spec.nested.flat().sort((left,right)=>left.tUs-right.tUs||(left.channel<right.channel?-1:left.channel>right.channel?1:0));if(merged.length>SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall){throw new SpatialBehaviorFnError("over-bound",`emitted.flatten.v1: flattened emissions exceed ${SPATIAL_BEHAVIOR_FN_LIMITS.emittedPerCall}`)}return{emitted:merged}}var advanceInputs=z10.strictObject({window:windowSchema,step:uint.min(1).max(SPATIAL_BEHAVIOR_FN_LIMITS.ticksPerWindow)});function windowAdvance(inputs){const spec=parseSpec(advanceInputs,{window:inputs.window,step:inputs.step},"window.advance.v1","window");const head=spec.window.ticks.slice(0,spec.step);const rest=spec.window.ticks.slice(spec.step);return{head:{ticks:head},rest:{ticks:rest},done:rest.length===0?"true":"false"}}var ports=(map)=>map;var SPATIAL_BEHAVIOR_FNS=new Map(Object.entries({"rng.seeded.v1":{signature:{inputs:ports({seed:{type:"json"},count:{type:"json"},stream:{type:"json",optional:true}}),outputs:ports({draws:{type:"json"},next:{type:"json"}}),cost:50},invoke:rngSeeded},"behavior.fsm.v1":{signature:{inputs:ports({machine:{type:"json"},state:{type:"json"},window:{type:"json"}}),outputs:ports({next:{type:"json"},emitted:{type:"json"}}),cost:200},invoke:behaviorFsm},"behavior.expression.v1":{signature:{inputs:ports({spec:{type:"json"},state:{type:"json"},window:{type:"json"}}),outputs:ports({next:{type:"json"},emitted:{type:"json"}}),cost:200},invoke:behaviorExpression},"behavior.interact.v1":{signature:{inputs:ports({spec:{type:"json"},state:{type:"json"},window:{type:"json"}}),outputs:ports({next:{type:"json"},emitted:{type:"json"}}),cost:200},invoke:behaviorInteract},"channel.emit.v1":{signature:{inputs:ports({channel:{type:"text"},value:{type:"json",optional:true},window:{type:"json"}}),outputs:ports({emitted:{type:"json"}}),cost:25},invoke:channelEmit},"scene.sample.v1":{signature:{inputs:ports({spec:{type:"json"},window:{type:"json"}}),outputs:ports({window:{type:"json"}}),cost:100},invoke:sceneSample},"behavior.combine.v1":{signature:{inputs:ports({layers:{type:"json"}}),outputs:ports({emitted:{type:"json"}}),cost:50},invoke:behaviorCombine},"emitted.append.v1":{signature:{inputs:ports({prior:{type:"json"},fresh:{type:"json"}}),outputs:ports({emitted:{type:"json"}}),cost:25},invoke:emittedAppend},"emitted.flatten.v1":{signature:{inputs:ports({nested:{type:"json"}}),outputs:ports({emitted:{type:"json"}}),cost:25},invoke:emittedFlatten},"window.advance.v1":{signature:{inputs:ports({window:{type:"json"},step:{type:"json"}}),outputs:ports({head:{type:"json"},rest:{type:"json"},done:{type:"text"}}),cost:10},invoke:windowAdvance}}));function spatialBehaviorFnSignatures(){const signatures=new Map;for(const[name,entry]of SPATIAL_BEHAVIOR_FNS){signatures.set(name,{inputs:entry.signature.inputs,outputs:entry.signature.outputs})}return signatures}function gcd(a,b){while(b!==0n){const remainder=a%b;a=b;b=remainder}return a}function rational(numerator,denominator){const divisor=gcd(numerator,denominator);return Object.freeze({numerator:String(numerator/divisor),denominator:String(denominator/divisor)})}function integer(input,name){if(!Number.isSafeInteger(input)||input<0)throw new SpatialSceneError("invalid-data",`${name} must be a nonnegative safe integer.`);return BigInt(input)}function duration(input){const value=parseSpatialValue(SpatialTimeUsSchema,input,"durationUs");if(value===0)throw new SpatialSceneError("invalid-data","Output duration must be positive.");return BigInt(value)}function reduceSpatialFrameRate(input){const rate=parseSpatialValue(SpatialFrameRateSchema,input,"frame rate");const divisor=Number(gcd(BigInt(rate.numerator),BigInt(rate.denominator)));return Object.freeze({numerator:rate.numerator/divisor,denominator:rate.denominator/divisor})}function spatialFrameCount(durationUs,rateInput){const end=duration(durationUs),rate=reduceSpatialFrameRate(rateInput);const numerator=end*BigInt(rate.numerator),denominator=1000000n*BigInt(rate.denominator);return Number((numerator+denominator-1n)/denominator)}function spatialFrameSample(frameIndex,durationUs,rateInput){const index2=integer(frameIndex,"frameIndex"),end=duration(durationUs),rate=reduceSpatialFrameRate(rateInput);const numerator=index2*1000000n*BigInt(rate.denominator),denominator=BigInt(rate.numerator);if(numerator>=end*denominator)throw new SpatialSceneError("invalid-data","Frame lies outside the half-open duration before quantization.","frameIndex");const timeUs=Number((2n*numerator+denominator)/(2n*denominator));return deepFreezeJson({frameIndex,timeUs,exactTimeUs:rational(numerator,denominator)})}function spatialOutputDuration(durationUs,rateInput){const rate=reduceSpatialFrameRate(rateInput);return rational(BigInt(spatialFrameCount(durationUs,rate))*1000000n*BigInt(rate.denominator),BigInt(rate.numerator))}import{z as z11}from"zod";var SPATIAL_CAMERA_TRACK_MAX_FRAMES=2048;var clockSchema=z11.strictObject({startUs:SpatialTimeUsSchema,frameRate:SpatialFrameRateSchema,frameCount:z11.number().int().min(1).max(SPATIAL_CAMERA_TRACK_MAX_FRAMES)});var rationalSchema=z11.strictObject({numerator:z11.string().regex(/^(0|[1-9][0-9]{0,19})$/u),denominator:z11.string().regex(/^[1-9][0-9]{0,6}$/u)});var SpatialCameraTrackSchema=z11.strictObject({kind:z11.literal("slopcamera.spatial-camera-track"),schemaVersion:z11.literal(1),sceneSha256:SpatialDigestSchema,cameraId:SpatialCameraIdSchema,clock:clockSchema,samples:z11.array(z11.strictObject({frameIndex:z11.number().int().min(0).max(SPATIAL_CAMERA_TRACK_MAX_FRAMES-1),timeUs:SpatialTimeUsSchema,exactTimeUs:rationalSchema,camera:SpatialCameraSchema})).min(1).max(SPATIAL_CAMERA_TRACK_MAX_FRAMES)});var optionsSchema2=clockSchema.extend({cameraId:SpatialCameraIdSchema});function absoluteSample(frameIndex,clock){const sample=spatialFrameSample(frameIndex,3600000000,clock.frameRate);const denominator=BigInt(sample.exactTimeUs.denominator);return{frameIndex,timeUs:clock.startUs+sample.timeUs,exactTimeUs:{numerator:String(BigInt(clock.startUs)*denominator+BigInt(sample.exactTimeUs.numerator)),denominator:String(denominator)}}}function parseSpatialCameraTrack(input){const track=parseSpatialValue(SpatialCameraTrackSchema,input,"camera track");const rate=reduceSpatialFrameRate(track.clock.frameRate);if(rate.numerator!==track.clock.frameRate.numerator||rate.denominator!==track.clock.frameRate.denominator||track.samples.length!==track.clock.frameCount)throw new SpatialSceneError("invalid-data","Camera track clock or coverage is not canonical.");const first=track.samples[0].camera.projection;for(const[index2,sample]of track.samples.entries()){const expected=absoluteSample(index2,track.clock);if(sample.frameIndex!==index2||sample.timeUs!==expected.timeUs||sample.exactTimeUs.numerator!==expected.exactTimeUs.numerator||sample.exactTimeUs.denominator!==expected.exactTimeUs.denominator||sample.camera.cameraId!==track.cameraId||sample.camera.projection.width!==first.width||sample.camera.projection.height!==first.height){throw new SpatialSceneError("invalid-data","Camera track must preserve exact clock, camera identity, order and image dimensions.")}}return deepFreezeJson(track)}function sampleSpatialCameraTrack(sceneInput,optionsInput){const scene=parseSpatialScene(sceneInput);const{cameraId,...inputClock}=parseSpatialValue(optionsSchema2,optionsInput,"camera track options");const clock={...inputClock,frameRate:reduceSpatialFrameRate(inputClock.frameRate)};const last=absoluteSample(clock.frameCount-1,clock);if(BigInt(last.exactTimeUs.numerator)>=BigInt(scene.durationUs)*BigInt(last.exactTimeUs.denominator)){throw new SpatialSceneError("invalid-data","Camera samples exceed the half-open scene duration.")}const camera2=scene.cameras.find((item)=>item.cameraId===cameraId);if(!camera2)throw new SpatialSceneError("not-found",`Unknown camera ${cameraId}.`);const cameraScene={...scene,cameras:[camera2],entities:[],assets:[],generators:[],overrides:[],animations:scene.animations.filter((channel)=>channel.targetId===cameraId)};const cameraContext=createSpatialEvaluationContext(cameraScene);return parseSpatialCameraTrack({kind:"slopcamera.spatial-camera-track",schemaVersion:1,sceneSha256:spatialValueSha256(scene),cameraId,clock,samples:Array.from({length:clock.frameCount},(_,frameIndex)=>{const sample=absoluteSample(frameIndex,clock);return{...sample,camera:evaluateSpatialSceneInContext(cameraContext,{cameraId,timeUs:sample.timeUs}).camera}})})}import{z as z12}from"zod";var scalar=z12.number().finite().min(-1e6).max(1e6);var positive2=z12.number().finite().positive().max(1e6);var target=z12.strictObject({entityId:SpatialEntityIdSchema.optional(),position:SpatialVec3Schema,radiusM:positive2});var timing={startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema};var base={cameraId:SpatialCameraIdSchema,...timing,easing:z12.enum(["linear","smoothstep","smootherstep"]).optional()};var shake=z12.strictObject({seed:z12.number().int().min(0).max(4294967295),amplitudeM:z12.number().finite().min(0).max(10),frequencyHz:z12.number().finite().min(0.01).max(100),layers:z12.number().int().min(1).max(8)});var SpatialCameraRigSchema=z12.discriminatedUnion("kind",[z12.strictObject({...base,kind:z12.literal("dolly"),from:SpatialVec3Schema,to:SpatialVec3Schema,target}),z12.strictObject({...base,kind:z12.literal("crane"),from:SpatialVec3Schema,to:SpatialVec3Schema,target}),z12.strictObject({...base,kind:z12.literal("orbit"),center:SpatialVec3Schema,radiusM:positive2,startAngleRad:scalar,endAngleRad:scalar,heightM:scalar,target}),z12.strictObject({...base,kind:z12.literal("rail"),points:z12.array(SpatialVec3Schema).min(2).max(64),target}),z12.strictObject({...base,kind:z12.literal("handheld"),pose:SpatialPoseSchema,target,shake}),z12.strictObject({...base,kind:z12.literal("chase"),target,offset:SpatialVec3Schema,fromTarget:SpatialVec3Schema.optional(),toTarget:SpatialVec3Schema.optional(),shake:shake.optional()}),z12.strictObject({...base,kind:z12.literal("tripod"),pose:SpatialPoseSchema,target}),z12.strictObject({...base,kind:z12.literal("target-tracking"),from:SpatialVec3Schema,to:SpatialVec3Schema,target,targetEnd:SpatialVec3Schema.optional()})]).refine((value)=>value.endUs>value.startUs,"Camera rig duration must be nonempty.");var SpatialRackFocusSchema=z12.strictObject({startDistanceM:positive2,endDistanceM:positive2});var compileSchema=z12.strictObject({camera:SpatialCameraSchema,rig:SpatialCameraRigSchema,frameRate:SpatialFrameRateSchema,frameCount:z12.number().int().min(1).max(SPATIAL_CAMERA_TRACK_MAX_FRAMES),rackFocus:SpatialRackFocusSchema.optional()});var mix=(a,b,t)=>a+(b-a)*t;var vec=(a,b,t)=>[mix(a[0],b[0],t),mix(a[1],b[1],t),mix(a[2],b[2],t)];function eased(t,kind){return kind==="smoothstep"?t*t*(3-2*t):kind==="smootherstep"?t*t*t*(t*(t*6-15)+10):t}function hash(seed,n){let x=(seed^Math.imul(n+1,2654435761))>>>0;x^=x>>>16;x=Math.imul(x,2146121005);x^=x>>>15;return(x>>>0)/4294967296*2-1}function shakeAt(spec,seconds){if(!spec)return[0,0,0];const out=[0,0,0];for(let layer=0;layer<spec.layers;layer++)for(let axis2=0;axis2<3;axis2++)out[axis2]=out[axis2]+Math.sin(seconds*spec.frequencyHz*(layer+1)*Math.PI*2+hash(spec.seed,layer*3+axis2)*Math.PI)*spec.amplitudeM/(spec.layers*(layer+1));return out}var normalize=(v)=>{const n=Math.hypot(...v);return[v[0]/n,v[1]/n,v[2]/n]};var cross=(a,b)=>[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]];function quaternionFromBasis(x,y,z13){const m00=x[0],m01=y[0],m02=z13[0],m10=x[1],m11=y[1],m12=z13[1],m20=x[2],m21=y[2],m22=z13[2],trace=m00+m11+m22;let q;if(trace>0){const s=2*Math.sqrt(trace+1);q=[(m21-m12)/s,(m02-m20)/s,(m10-m01)/s,s/4]}else if(m00>m11&&m00>m22){const s=2*Math.sqrt(1+m00-m11-m22);q=[s/4,(m01+m10)/s,(m02+m20)/s,(m21-m12)/s]}else if(m11>m22){const s=2*Math.sqrt(1+m11-m00-m22);q=[(m01+m10)/s,s/4,(m12+m21)/s,(m02-m20)/s]}else{const s=2*Math.sqrt(1+m22-m00-m11);q=[(m02+m20)/s,(m12+m21)/s,s/4,(m10-m01)/s]}const n=Math.hypot(...q);return q.map((v)=>v/n)}function lookAt(position,targetPosition){const forward=[targetPosition[0]-position[0],targetPosition[1]-position[1],targetPosition[2]-position[2]];if(Math.hypot(...forward)<0.000000001)throw new SpatialSceneError("invalid-data","Camera and look-at target must not coincide.");const f=normalize(forward),up=Math.abs(f[1])>0.999999?[0,0,1]:[0,1,0],right=normalize(cross(f,up)),correctedUp=cross(right,f);return quaternionFromBasis(right,correctedUp,[-f[0],-f[1],-f[2]])}function pointOnRail(points,t){const lengths=points.slice(1).map((p,i)=>Math.hypot(p[0]-points[i][0],p[1]-points[i][1],p[2]-points[i][2])),total=lengths.reduce((a,b)=>a+b,0);if(total===0)return[...points[0]];let distance=t*total,index2=0;while(index2<lengths.length-1&&distance>lengths[index2]){distance-=lengths[index2];index2++}return vec(points[index2],points[index2+1],lengths[index2]===0?0:distance/lengths[index2])}function sampleRig(rig,t){const u=eased(t,rig.easing);let position,aim=[...rig.target.position];if(rig.kind==="orbit")position=[rig.center[0]+Math.sin(mix(rig.startAngleRad,rig.endAngleRad,u))*rig.radiusM,rig.center[1]+rig.heightM,rig.center[2]+Math.cos(mix(rig.startAngleRad,rig.endAngleRad,u))*rig.radiusM];else if(rig.kind==="rail")position=pointOnRail(rig.points,u);else if(rig.kind==="handheld"||rig.kind==="tripod")position=[...rig.pose.position];else if(rig.kind==="chase"){aim=vec(rig.fromTarget??rig.target.position,rig.toTarget??rig.target.position,u);position=[aim[0]+rig.offset[0],aim[1]+rig.offset[1],aim[2]+rig.offset[2]]}else position=vec(rig.from,rig.to,u);if(rig.kind==="target-tracking"&&rig.targetEnd)aim=vec(rig.target.position,rig.targetEnd,u);const s=shakeAt(rig.kind==="handheld"||rig.kind==="chase"?rig.shake:undefined,(rig.endUs-rig.startUs)*t/1e6);return{position:[position[0]+s[0],position[1]+s[1],position[2]+s[2]],target:aim}}function compileSpatialCameraRig(input){const value=parseSpatialValue(compileSchema,input,"camera rig compilation"),rate=reduceSpatialFrameRate(value.frameRate),duration2=value.rig.endUs-value.rig.startUs;if(value.camera.cameraId!==value.rig.cameraId)throw new SpatialSceneError("conflict","Rig and camera identities differ.");if(spatialFrameCount(duration2,rate)!==value.frameCount)throw new SpatialSceneError("invalid-data","frameCount must exactly cover the rig's half-open duration at frameRate.");const clock={startUs:value.rig.startUs,frameRate:rate,frameCount:value.frameCount};const samples=Array.from({length:value.frameCount},(_,frameIndex)=>{const relative=spatialFrameSample(frameIndex,duration2,rate),t=Number(relative.exactTimeUs.numerator)/Number(relative.exactTimeUs.denominator)/duration2,sampled=sampleRig(value.rig,t),denominator=BigInt(relative.exactTimeUs.denominator);const lens=value.rackFocus?{...value.camera.lens??{focalLengthMm:50,sensorWidthMm:36},focusDistanceM:mix(value.rackFocus.startDistanceM,value.rackFocus.endDistanceM,eased(t,value.rig.easing))}:value.camera.lens;return{frameIndex,timeUs:value.rig.startUs+relative.timeUs,exactTimeUs:{numerator:String(BigInt(value.rig.startUs)*denominator+BigInt(relative.exactTimeUs.numerator)),denominator:String(denominator)},camera:{...value.camera,pose:{position:sampled.position,rotation:lookAt(sampled.position,sampled.target)},...lens===undefined?{}:{lens}}}});return parseSpatialCameraTrack({kind:"slopcamera.spatial-camera-track",schemaVersion:1,sceneSha256:spatialValueSha256({domain:"slopcamera.camera-rig.v1",camera:value.camera,rig:value.rig,frameRate:rate,frameCount:value.frameCount,rackFocus:value.rackFocus??null}),cameraId:value.camera.cameraId,clock,samples})}var framingTolerance=z12.number().finite().min(0).max(0.5).default(0.05);var SpatialFramingGoalSchema=z12.discriminatedUnion("kind",[z12.strictObject({kind:z12.literal("close-up"),targets:z12.array(target).min(1).max(3),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("medium"),targets:z12.array(target).min(1).max(3),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("wide"),targets:z12.array(target).min(1).max(3),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("two-shot"),targets:z12.array(target).length(2),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("over-shoulder"),targets:z12.array(target).min(2).max(3),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("screen-position"),targets:z12.array(target).length(1),position:z12.tuple([z12.number().finite().min(0).max(1),z12.number().finite().min(0).max(1)]),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("headroom"),targets:z12.array(target).length(1),headroom:z12.number().finite().min(0).max(0.5),tolerance:framingTolerance}),z12.strictObject({kind:z12.literal("rule-of-thirds"),targets:z12.array(target).length(1),quadrant:z12.enum(["upper-left","upper-right","lower-left","lower-right"]),tolerance:framingTolerance})]);function solveSpatialFraming(cameraInput,goalInput){const camera2=parseSpatialValue(SpatialCameraSchema,cameraInput,"framing camera"),goal=parseSpatialValue(SpatialFramingGoalSchema,goalInput,"framing goal"),ids=goal.targets.flatMap((x)=>x.entityId?[x.entityId]:[]);if(ids.length!==goal.targets.length)return deepFreezeJson({satisfied:false,report:{code:"missing-bounds",goal:goal.kind,entityIds:ids,detail:"Every framing target requires supplied known bounds and identity."}});if(camera2.projection.kind!=="perspective")return deepFreezeJson({satisfied:false,report:{code:"impossible",goal:goal.kind,entityIds:ids,detail:"Semantic framing requires a perspective camera."}});const p=camera2.projection,min=goal.targets.reduce((a,x)=>[Math.min(a[0],x.position[0]-x.radiusM),Math.min(a[1],x.position[1]-x.radiusM),Math.min(a[2],x.position[2]-x.radiusM)],[Infinity,Infinity,Infinity]),max=goal.targets.reduce((a,x)=>[Math.max(a[0],x.position[0]+x.radiusM),Math.max(a[1],x.position[1]+x.radiusM),Math.max(a[2],x.position[2]+x.radiusM)],[-Infinity,-Infinity,-Infinity]),center=vec(min,max,0.5),halfW=(max[0]-min[0])/2,halfH=(max[1]-min[1])/2,depthRadius=(max[2]-min[2])/2;const fill=goal.kind==="close-up"?0.8:goal.kind==="medium"?0.55:goal.kind==="wide"?0.3:goal.kind==="over-shoulder"?0.7:0.6;const depth=Math.max(halfW*p.fx/(p.width*fill/2),halfH*p.fy/(p.height*fill/2),p.near+depthRadius+0.000001);if(depth+depthRadius>=p.far)return deepFreezeJson({satisfied:false,report:{code:"impossible",goal:goal.kind,entityIds:ids,detail:"Target bounds cannot fit inside the camera clipping range."}});let desiredX=0.5,desiredY=0.5;if(goal.kind==="screen-position")[desiredX,desiredY]=goal.position;else if(goal.kind==="rule-of-thirds"){desiredX=goal.quadrant.endsWith("left")?1/3:2/3;desiredY=goal.quadrant.startsWith("upper")?1/3:2/3}else if(goal.kind==="headroom")desiredY=goal.headroom+halfH*p.fy/depth/p.height;const centerPixelX=desiredX*p.width,centerPixelY=desiredY*p.height,localCenter=[(centerPixelX-p.cx)*depth/p.fx,-(centerPixelY-p.cy)*depth/p.fy,-depth];const q=camera2.pose.rotation,[qx,qy,qz,qw]=q,[lx,ly,lz]=localCenter,tx=2*(qy*lz-qz*ly),ty=2*(qz*lx-qx*lz),tz=2*(qx*ly-qy*lx),worldOffset=[lx+qw*tx+(qy*tz-qz*ty),ly+qw*ty+(qz*tx-qx*tz),lz+qw*tz+(qx*ty-qy*tx)],position=[center[0]-worldOffset[0],center[1]-worldOffset[1],center[2]-worldOffset[2]],solved={...camera2,pose:{position,rotation:q}};const actual=worldToCamera([center[0]-position[0],center[1]-position[1],center[2]-position[2]],q),actualDepth=-actual[2],projectedX=p.cx+actual[0]*p.fx/actualDepth,projectedY=p.cy-actual[1]*p.fy/actualDepth,deviation=Math.hypot(projectedX/p.width-desiredX,projectedY/p.height-desiredY);return deviation<=goal.tolerance+0.000000000001?deepFreezeJson({satisfied:true,camera:solved}):deepFreezeJson({satisfied:false,report:{code:"unsatisfied",goal:goal.kind,entityIds:ids,detail:"Calibrated framing exceeds the declared normalized-screen tolerance.",deviation}})}var auditOptions=z12.strictObject({subjects:z12.array(target).max(128).default([]),collisionBounds:z12.array(target).max(128).default([]),cameraCollisionRadiusM:z12.number().finite().min(0).max(100).default(0),maxAcceleration:z12.number().finite().positive().max(1e6).default(50),maxAngularVelocity:z12.number().finite().positive().max(1e5).default(4),maxFramingDeviation:z12.number().finite().min(0).max(1).default(0.1),maxFocusErrorM:z12.number().finite().positive().max(1e6).default(0.5)});function worldToCamera(delta,q){const[x,y,z13,w]=q,tx=2*(-y*delta[2]+z13*delta[1]),ty=2*(-z13*delta[0]+x*delta[2]),tz=2*(-x*delta[1]+y*delta[0]);return[delta[0]+w*tx+(-y*tz+z13*ty),delta[1]+w*ty+(-z13*tx+x*tz),delta[2]+w*tz+(-x*ty+y*tx)]}function auditSpatialCameraTrack(trackInput,optionsInput){const track=parseSpatialCameraTrack(trackInput),options=parseSpatialValue(auditOptions,optionsInput,"camera audit options"),findings=[];const add=(sample,finding)=>findings.push({cameraId:track.cameraId,frameIndex:sample.frameIndex,timeUs:sample.timeUs,...finding});for(let i=0;i<track.samples.length;i++){const s=track.samples[i],p=s.camera.pose.position,proj=s.camera.projection;for(const subject of options.subjects){const delta=[subject.position[0]-p[0],subject.position[1]-p[1],subject.position[2]-p[2]],local=worldToCamera(delta,s.camera.pose.rotation),depth=-local[2],nearEdge=depth-subject.radiusM,farEdge=depth+subject.radiusM;if(nearEdge<proj.near||farEdge>proj.far)add(s,{kind:"clipping",entityId:subject.entityId,measured:depth,limit:nearEdge<proj.near?proj.near:proj.far});const focus=s.camera.lens?.focusDistanceM;if(focus!==undefined&&Math.abs(focus-depth)>options.maxFocusErrorM)add(s,{kind:"focus-error",entityId:subject.entityId,measured:Math.abs(focus-depth),limit:options.maxFocusErrorM});const lateral=Math.hypot(local[0],local[1]),deviation=depth<=0?1:Math.atan2(lateral,depth)/Math.PI;if(deviation>options.maxFramingDeviation)add(s,{kind:"framing-deviation",entityId:subject.entityId,measured:deviation,limit:options.maxFramingDeviation})}for(const bound of options.collisionBounds){const d=Math.hypot(bound.position[0]-p[0],bound.position[1]-p[1],bound.position[2]-p[2]),limit=bound.radiusM+options.cameraCollisionRadiusM;if(d<limit)add(s,{kind:"collision",entityId:bound.entityId,measured:d,limit})}if(i>=2){const a=track.samples[i-2],b=track.samples[i-1],dt=(s.timeUs-b.timeUs)/1e6,dt0=(b.timeUs-a.timeUs)/1e6;if(dt>0&&dt0>0){const acceleration=Math.hypot(...[0,1,2].map((k)=>(p[k]-b.camera.pose.position[k])/dt-(b.camera.pose.position[k]-a.camera.pose.position[k])/dt0))/((dt+dt0)/2);if(acceleration>options.maxAcceleration)add(s,{kind:"acceleration",measured:acceleration,limit:options.maxAcceleration})}}if(i>0){const b=track.samples[i-1],seconds=(s.timeUs-b.timeUs)/1e6;if(seconds>0){const raw=s.camera.pose.rotation.reduce((sum,v,k)=>sum+v*b.camera.pose.rotation[k],0),dot=Math.min(1,Math.max(-1,Math.abs(raw))),velocity=2*Math.acos(dot)/seconds;if(velocity>options.maxAngularVelocity)add(s,{kind:"angular-velocity",measured:velocity,limit:options.maxAngularVelocity})}}}const kindOrder={clipping:0,collision:1,acceleration:2,"framing-deviation":3,"focus-error":4,"angular-velocity":5};findings.sort((a,b)=>a.frameIndex-b.frameIndex||kindOrder[a.kind]-kindOrder[b.kind]||(a.entityId??"").localeCompare(b.entityId??""));return deepFreezeJson(findings)}import{z as z13}from"zod";var SPATIAL_DIRECTION_LIMITS=Object.freeze({actions:256,beats:64,coverage:64,durationUs:3600000000,looks:32});var directionId=z13.string().min(1).max(64).regex(/^[a-z][a-z0-9_-]*$/u);var referenceId=z13.string().min(1).max(128).regex(/^[a-z][a-z0-9_-]*$/u);var intervalShape={endUs:SpatialTimeUsSchema.max(SPATIAL_DIRECTION_LIMITS.durationUs),startUs:SpatialTimeUsSchema.max(SPATIAL_DIRECTION_LIMITS.durationUs)};var SpatialDramaticBeatSchema=z13.strictObject({id:directionId,...intervalShape,intent:z13.string().trim().min(1).max(256),emotion:z13.string().trim().min(1).max(64),verified:z13.boolean().default(false)});var SpatialCharacterActionSchema=z13.strictObject({id:directionId,characterId:referenceId,...intervalShape,action:z13.enum(["idle","walk","run","turn","gesture","interact","morph"]),targetId:referenceId.optional(),verified:z13.boolean().default(false)});var SpatialCameraCoverageSchema=z13.strictObject({id:directionId,...intervalShape,rigKind:z13.enum(["chase","crane","dolly","handheld","orbit","rail","target-tracking","tripod"]),framing:z13.enum(["extreme-close-up","close-up","medium-close-up","medium","medium-wide","wide","extreme-wide","over-shoulder","insert"]),screenDirection:z13.enum(["left","right","neutral"]).optional(),subjectId:referenceId.optional(),verified:z13.boolean().default(false)});var SpatialLookIntentSchema=z13.strictObject({id:directionId,...intervalShape,lighting:z13.string().trim().min(1).max(128),atmosphere:z13.string().trim().min(1).max(128),verified:z13.boolean().default(false)});var SpatialDirectionSchema=z13.strictObject({kind:z13.literal("slopcamera.spatial-direction"),schemaVersion:z13.literal(1),entityId:referenceId,projectDigest:SpatialDigestSchema,beats:z13.array(SpatialDramaticBeatSchema).max(SPATIAL_DIRECTION_LIMITS.beats),actions:z13.array(SpatialCharacterActionSchema).max(SPATIAL_DIRECTION_LIMITS.actions),coverage:z13.array(SpatialCameraCoverageSchema).max(SPATIAL_DIRECTION_LIMITS.coverage),looks:z13.array(SpatialLookIntentSchema).max(SPATIAL_DIRECTION_LIMITS.looks)}).superRefine((direction,context)=>{const ids=new Set;for(const[collectionName,values2]of[["beats",direction.beats],["actions",direction.actions],["coverage",direction.coverage],["looks",direction.looks]]){let previousStartUs=-1;let previousId="";for(const[index2,value]of values2.entries()){if(value.endUs<=value.startUs){context.addIssue({code:"custom",path:[collectionName,index2,"endUs"],message:"Direction intervals must have positive duration."})}if(ids.has(value.id)){context.addIssue({code:"custom",path:[collectionName,index2,"id"],message:`Direction id ${value.id} must be globally unique.`})}ids.add(value.id);if(value.startUs<previousStartUs||value.startUs===previousStartUs&&value.id.localeCompare(previousId)<=0){context.addIssue({code:"custom",path:[collectionName,index2],message:"Direction entries must be ordered by startUs then id."})}previousStartUs=value.startUs;previousId=value.id}}for(const[index2,action]of direction.actions.entries()){if(action.action==="interact"!==(action.targetId!==undefined)){context.addIssue({code:"custom",path:["actions",index2,"targetId"],message:"Only interact actions require a targetId."})}}for(let index2=1;index2<direction.coverage.length;index2+=1){if(direction.coverage[index2].startUs<direction.coverage[index2-1].endUs){context.addIssue({code:"custom",path:["coverage",index2],message:"Camera coverage intervals must not overlap."})}}});function parseSpatialDirection(input){try{return deepFreezeJson(parseSpatialValue(SpatialDirectionSchema,input,"direction"))}catch(error){if(error instanceof SpatialSceneError)throw error;throw new SpatialSceneError("invalid-data",error instanceof Error?error.message:String(error),"direction")}}function spatialDirectionSha256(direction){return spatialValueSha256(direction)}import{z as z14}from"zod";var positiveDimension2=z14.number().finite().positive().max(1e6);var unit4=z14.number().finite().min(0).max(1);var SPATIAL_EFFECT_LIMITS=Object.freeze({dust:500000,embers:1e6,luts:4,outputBytes:8000000000,postProcessStack:8,previewParticles:1e5,rain:1e5,renderPixels:67108864,simulationFrames:1e4,simulationSteps:1e4,texturePixels:268435456});var boundedPixels=z14.number().int().safe().positive();var SpatialRenderQualitySchema=z14.strictObject({outputBytes:z14.number().int().safe().positive().max(SPATIAL_EFFECT_LIMITS.outputBytes),particleCount:z14.number().int().safe().min(0).max(SPATIAL_EFFECT_LIMITS.embers),pixelBudget:boundedPixels.max(SPATIAL_EFFECT_LIMITS.renderPixels),simulationSteps:z14.number().int().safe().min(0).max(SPATIAL_EFFECT_LIMITS.simulationSteps),texturePixelBudget:boundedPixels.max(SPATIAL_EFFECT_LIMITS.texturePixels),tier:z14.enum(["preview","final"])});var SpatialBloomSchema=z14.strictObject({intensity:unit4,kind:z14.literal("bloom"),radius:z14.number().finite().min(0).max(64),threshold:unit4});var SpatialDepthOfFieldSchema=z14.strictObject({aperture:z14.number().finite().positive().max(256),focalLength:z14.number().finite().positive().max(1e4),focusDistance:positiveDimension2,kind:z14.literal("depth-of-field")});var SpatialMotionBlurSchema=z14.strictObject({kind:z14.literal("motion-blur"),samples:z14.number().int().min(1).max(64),shutterAngle:z14.number().finite().min(0).max(360)});var SpatialToneMapSchema=z14.strictObject({exposure:z14.number().finite().min(-20).max(20),kind:z14.literal("tone-map"),whitePoint:z14.number().finite().positive().max(1e6)});var SpatialVignetteSchema=z14.strictObject({intensity:unit4,kind:z14.literal("vignette"),radius:unit4});var SpatialChromaticAberrationSchema=z14.strictObject({kind:z14.literal("chromatic-aberration"),offsetPixels:z14.number().finite().min(0).max(64),radialFalloff:unit4});var SpatialGrainSchema=z14.strictObject({intensity:unit4,kind:z14.literal("grain"),seed:z14.number().int().min(0).max(2147483647)});var SpatialFlareSchema=z14.strictObject({ghosts:z14.number().int().min(0).max(16),haloWidth:unit4,intensity:unit4,kind:z14.literal("flare"),threshold:unit4});var SpatialLutGradeSchema=z14.strictObject({assetId:SpatialAssetIdSchema,intensity:unit4,kind:z14.literal("lut-grade")});var SpatialPostProcessStepSchema=z14.discriminatedUnion("kind",[SpatialBloomSchema,SpatialDepthOfFieldSchema,SpatialMotionBlurSchema,SpatialToneMapSchema,SpatialVignetteSchema,SpatialChromaticAberrationSchema,SpatialGrainSchema,SpatialFlareSchema,SpatialLutGradeSchema]);var SpatialPostProcessStackSchema=z14.strictObject({kind:z14.literal("slopcamera.spatial-post-process"),schemaVersion:z14.literal(1),steps:z14.array(SpatialPostProcessStepSchema).min(1).max(SPATIAL_EFFECT_LIMITS.postProcessStack)}).superRefine((stack,context)=>{if(stack.steps.filter((step)=>step.kind==="lut-grade").length>SPATIAL_EFFECT_LIMITS.luts){context.addIssue({code:"custom",path:["steps"],message:`Post-process stacks support at most ${SPATIAL_EFFECT_LIMITS.luts} LUT grades.`})}});var SpatialRenderPlanSchema=z14.strictObject({kind:z14.literal("slopcamera.spatial-render-plan"),postProcess:SpatialPostProcessStackSchema.optional(),quality:SpatialRenderQualitySchema,schemaVersion:z14.literal(1)});function parseSpatialRenderPlan(input){const plan=parseSpatialValue(SpatialRenderPlanSchema,input,"render plan");if(plan.quality.tier==="preview"&&plan.quality.particleCount>SPATIAL_EFFECT_LIMITS.previewParticles){throw new SpatialSceneError("invalid-data",`Preview tier cannot request more than ${SPATIAL_EFFECT_LIMITS.previewParticles.toLocaleString("en-US")} particles.`,"render-plan.quality.particleCount")}if(plan.quality.outputBytes<plan.quality.particleCount*64){throw new SpatialSceneError("invalid-data","Output byte budget is too small for declared particle count.","render-plan.quality.outputBytes")}return deepFreezeJson(plan)}function spatialRenderPlanAssetIds(plan){return Object.freeze([...new Set(plan.postProcess?.steps.flatMap((step)=>step.kind==="lut-grade"?[step.assetId]:[])??[])].sort())}function spatialRenderPlanSha256(plan){return spatialValueSha256(plan)}import{z as z15}from"zod";var SPATIAL_DIRECTION_COMPILER_ID="slopcamera.spatial-direction-compiler@v1";var SPATIAL_DIRECTION_COMPILATION_LIMITS=Object.freeze({advisories:256,unresolvedIntents:256,checks:512});var SpatialDirectionAdvisoryCodeSchema=z15.enum(["unresolved-reference","stale-digest","defaulted-camera","missing-camera","bounds-unknown","interval-outside-scene","coverage-ungrouped"]);var SpatialDirectionAdvisorySchema=z15.strictObject({code:SpatialDirectionAdvisoryCodeSchema,referenceId:z15.string().min(1).max(128).optional(),detail:z15.string().min(1).max(240)});var SpatialUnresolvedIntentDomainSchema=z15.enum(["performance","camera","shot","look"]);var SpatialUnresolvedIntentSchema=z15.strictObject({intentId:z15.string().min(1).max(96).regex(/^prop_[a-f0-9]{16}$/u),domain:SpatialUnresolvedIntentDomainSchema,referenceId:z15.string().min(1).max(128),slot:z15.string().min(1).max(64).regex(/^[a-z][a-z0-9-]*$/u),detail:z15.string().min(1).max(240)});var unresolvedSlot=(intentId,domain,referenceId2,slot,detail)=>deepFreezeJson({intentId,domain,referenceId:referenceId2,slot,detail});var SpatialPerformanceClipKindSchema=z15.enum(["idle","walk-cycle","run-cycle","turn","gesture","interact","expression"]);var SpatialPerformanceProposalSchema=z15.strictObject({proposalId:z15.string().min(1).max(96).regex(/^prop_[a-f0-9]{16}$/u),actionId:z15.string().min(1).max(64),characterId:z15.string().min(1).max(128),action:SpatialDirectionSchema.shape.actions.element.shape.action,clipKind:SpatialPerformanceClipKindSchema,startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema,characterEntityId:SpatialEntityIdSchema.optional(),targetEntityId:SpatialEntityIdSchema.optional(),unresolved:z15.array(z15.string().min(1).max(64).regex(/^[a-z][a-z0-9-]*$/u)).min(1).max(16)});var SpatialLookProposalSchema=z15.strictObject({proposalId:z15.string().min(1).max(96).regex(/^prop_[a-f0-9]{16}$/u),lookId:z15.string().min(1).max(64),startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema,lighting:z15.string().min(1).max(128),atmosphere:z15.string().min(1).max(128),unresolved:z15.array(z15.string().min(1).max(64).regex(/^[a-z][a-z0-9-]*$/u)).min(1).max(16),suggestedLightingPreset:z15.string().min(1).max(64).optional(),suggestedMaterialPalette:z15.string().min(1).max(64).optional(),suggestedPostProcess:z15.array(SpatialPostProcessStepSchema).max(16).optional()});var SpatialDirectionProposalsSchema=z15.strictObject({performance:z15.array(SpatialPerformanceProposalSchema).max(SPATIAL_DIRECTION_LIMITS.actions),cameraRigs:z15.array(SpatialCameraRigSchema).max(SPATIAL_DIRECTION_LIMITS.coverage),shots:z15.array(SpatialShotV1Schema).max(SPATIAL_DIRECTION_LIMITS.coverage),lookIntents:z15.array(SpatialLookProposalSchema).max(SPATIAL_DIRECTION_LIMITS.looks)});var SpatialDirectionCompilationSchema=z15.strictObject({kind:z15.literal("slopcamera.spatial-direction-compilation"),schemaVersion:z15.literal(1),directionSha256:SpatialDigestSchema,sceneSha256:SpatialDigestSchema,compilerVersion:z15.literal(SPATIAL_DIRECTION_COMPILER_ID),verified:z15.literal(false),cameraId:SpatialCameraIdSchema.optional(),proposals:SpatialDirectionProposalsSchema,advisories:z15.array(SpatialDirectionAdvisorySchema).max(SPATIAL_DIRECTION_COMPILATION_LIMITS.advisories),unresolvedIntents:z15.array(SpatialUnresolvedIntentSchema).max(SPATIAL_DIRECTION_COMPILATION_LIMITS.unresolvedIntents)});var SpatialDirectionCheckFindingSchema=z15.strictObject({code:SpatialDirectionAdvisoryCodeSchema,severity:z15.enum(["error","warning"]),referenceId:z15.string().min(1).max(128).optional(),detail:z15.string().min(1).max(240)});var SpatialDirectionCheckReportSchema=z15.strictObject({kind:z15.literal("slopcamera.spatial-direction-check"),schemaVersion:z15.literal(1),directionSha256:SpatialDigestSchema,sceneSha256:SpatialDigestSchema,findings:z15.array(SpatialDirectionCheckFindingSchema).max(SPATIAL_DIRECTION_COMPILATION_LIMITS.checks),counts:z15.strictObject({beats:z15.number().int().min(0),actions:z15.number().int().min(0),coverage:z15.number().int().min(0),looks:z15.number().int().min(0),errors:z15.number().int().min(0),warnings:z15.number().int().min(0)})});function spatialDirectionCompilationSha256(compilation){return spatialValueSha256(compilation)}var proposalId=(domain,referenceId2)=>`prop_${spatialValueSha256({domain:`slopcamera.direction-proposal.v1.${domain}`,referenceId:referenceId2}).slice(0,16)}`;function resolveEntityId2(scene,referenceId2){const ids=new Set(scene.entities.map((entity)=>entity.entityId));if(ids.has(referenceId2))return referenceId2;const prefixed=`entity_${referenceId2}`;return ids.has(prefixed)?prefixed:undefined}var FRAMING_DISTANCE_M={insert:0.5,"extreme-close-up":0.8,"close-up":1.4,"medium-close-up":2.4,medium:4,"medium-wide":6.5,wide:11,"extreme-wide":20,"over-shoulder":1.8};var CLIP_KIND_BY_ACTION={idle:"idle",walk:"walk-cycle",run:"run-cycle",turn:"turn",gesture:"gesture",interact:"interact",morph:"expression"};var normalize2=(v)=>{const n=Math.hypot(v[0],v[1],v[2]);return n<0.000000001?[0,0,-1]:[v[0]/n,v[1]/n,v[2]/n]};var cross2=(a,b)=>[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]];function quaternionFromBasis2(x,y,z16){const m00=x[0],m01=y[0],m02=z16[0],m10=x[1],m11=y[1],m12=z16[1],m20=x[2],m21=y[2],m22=z16[2],trace=m00+m11+m22;let q;if(trace>0){const s=2*Math.sqrt(trace+1);q=[(m21-m12)/s,(m02-m20)/s,(m10-m01)/s,s/4]}else if(m00>m11&&m00>m22){const s=2*Math.sqrt(1+m00-m11-m22);q=[s/4,(m01+m10)/s,(m02+m20)/s,(m21-m12)/s]}else if(m11>m22){const s=2*Math.sqrt(1+m11-m00-m22);q=[(m01+m10)/s,s/4,(m12+m21)/s,(m02+m20)/s]}else{const s=2*Math.sqrt(1+m22-m11-m00);q=[(m02+m20)/s,(m12+m21)/s,s/4,(m10-m01)/s]}const n=Math.hypot(...q);return q.map((v)=>v/n)}function lookAtQuaternion(position,target2){const forward=[target2[0]-position[0],target2[1]-position[1],target2[2]-position[2]];if(Math.hypot(...forward)<0.000000001)throw new SpatialSceneError("invalid-data","Camera and look-at target must not coincide.");const f=normalize2(forward),up=Math.abs(f[1])>0.999999?[0,0,1]:[0,1,0];const right=normalize2(cross2(f,up)),correctedUp=cross2(right,f);return quaternionFromBasis2(right,correctedUp,[-f[0],-f[1],-f[2]])}var shakeSeed=(coverageId)=>{let seed=0;const digest=spatialValueSha256({domain:"slopcamera.direction-shake-seed.v1",coverageId});for(let index2=0;index2<8;index2+=1)seed=seed*16+Number.parseInt(digest[index2],16)>>>0;return seed};var advisory=(code,detail,referenceId2)=>deepFreezeJson(referenceId2===undefined?{code,detail}:{code,referenceId:referenceId2,detail});function resolveSubject(context,coverage,evaluation){if(coverage.subjectId===undefined||evaluation===undefined||context.cameraId===undefined)return;const entityId=resolveEntityId2(context.scene,coverage.subjectId);if(entityId===undefined){context.advisories.push(advisory("unresolved-reference",`Coverage ${coverage.id} subject ${coverage.subjectId} is not a scene entity.`,coverage.id));return}const positionAt=(timeUs)=>{const clamped=Math.min(Math.max(timeUs,0),context.scene.durationUs);const snapshot=evaluateSpatialSceneInContext(evaluation,{cameraId:context.cameraId,timeUs:clamped});const evaluated=snapshot.entities.find((item)=>item.entity.entityId===entityId);if(evaluated===undefined)return;return[evaluated.worldMatrix[12],evaluated.worldMatrix[13],evaluated.worldMatrix[14]]};const position=positionAt(coverage.startUs);const positionEnd=positionAt(coverage.endUs);if(position===undefined||positionEnd===undefined){context.advisories.push(advisory("unresolved-reference",`Coverage ${coverage.id} subject ${coverage.subjectId} is absent from evaluated state.`,coverage.id));return}const entity=context.scene.entities.find((item)=>item.entityId===entityId);const enclosure=spatialEntityLocalBounds(entity,{});let radiusM=1;if(enclosure.status==="bounded"){const{min,max}=enclosure.bounds;radiusM=Math.min(Math.max(Math.hypot(max[0]-min[0],max[1]-min[1],max[2]-min[2])/2,0.000001),1e6)}else{context.advisories.push(advisory("bounds-unknown",`Coverage ${coverage.id} subject ${entityId} has unbounded geometry (${enclosure.reason}); radius defaulted to 1m.`,coverage.id))}return{entityId,position,positionEnd,radiusM}}function cameraOffset(coverage,subject){const distance=FRAMING_DISTANCE_M[coverage.framing];const base2=subject?.position??[0,1,0];const lateral=coverage.screenDirection==="left"?-distance*0.6:coverage.screenDirection==="right"?distance*0.6:0;const height=subject===undefined?1.6:Math.min(Math.max(subject.radiusM,0.4),8);return[base2[0]+lateral,base2[1]+height,base2[2]-distance]}function compileCoverageRig(context,coverage,subject){const cameraId=context.cameraId;if(cameraId===undefined)return;const base2={cameraId,startUs:coverage.startUs,endUs:coverage.endUs};const targetPosition=subject?.position??[0,1,0];const target2=subject===undefined?{position:[0,1,0],radiusM:1}:{entityId:subject.entityId,position:targetPosition,radiusM:subject.radiusM};const position=cameraOffset(coverage,subject);const distance=FRAMING_DISTANCE_M[coverage.framing];try{switch(coverage.rigKind){case"tripod":return SpatialCameraRigSchema.parse({...base2,kind:"tripod",pose:{position,rotation:lookAtQuaternion(position,targetPosition)},target:target2});case"handheld":return SpatialCameraRigSchema.parse({...base2,kind:"handheld",pose:{position,rotation:lookAtQuaternion(position,targetPosition)},target:target2,shake:{seed:shakeSeed(coverage.id),amplitudeM:0.05,frequencyHz:1.5,layers:2}});case"dolly":{const toward=normalize2([targetPosition[0]-position[0],0,targetPosition[2]-position[2]]);const from=[position[0]+toward[0]*distance*0.5,position[1],position[2]+toward[2]*distance*0.5];return SpatialCameraRigSchema.parse({...base2,kind:"dolly",from,to:position,target:target2})}case"crane":return SpatialCameraRigSchema.parse({...base2,kind:"crane",from:[position[0],position[1]+Math.min(4,distance),position[2]],to:position,target:target2});case"orbit":return SpatialCameraRigSchema.parse({...base2,kind:"orbit",center:targetPosition,radiusM:Math.max(distance,subject?.radiusM??1),startAngleRad:Math.PI,endAngleRad:Math.PI*2,heightM:subject===undefined?1.6:Math.min(Math.max(subject.radiusM,0.4),8),target:target2});case"rail":{const half=Math.max(distance*0.5,0.5);return SpatialCameraRigSchema.parse({...base2,kind:"rail",points:[[position[0]-half,position[1],position[2]],position,[position[0]+half,position[1],position[2]]],target:target2})}case"chase":return SpatialCameraRigSchema.parse({...base2,kind:"chase",target:target2,offset:[0,Math.min(Math.max(subject?.radiusM??1,0.4),8),-distance],...subject===undefined?{}:{toTarget:subject.positionEnd},shake:{seed:shakeSeed(coverage.id),amplitudeM:0.03,frequencyHz:2,layers:1}});case"target-tracking":{const half=Math.max(distance*0.5,0.5);return SpatialCameraRigSchema.parse({...base2,kind:"target-tracking",from:[position[0]-half,position[1],position[2]],to:[position[0]+half,position[1],position[2]],target:target2,...subject===undefined?{}:{targetEnd:subject.positionEnd}})}}throw new SpatialSceneError("invalid-data",`Unsupported coverage rig kind ${coverage.rigKind}.`,"coverage.rigKind")}catch(error){context.advisories.push(advisory("unresolved-reference",`Coverage ${coverage.id} rig ${coverage.rigKind} failed deterministic construction: ${error instanceof Error?error.message:String(error)}`,coverage.id));return}}var compileOptionsSchema=z15.strictObject({direction:z15.unknown(),scene:z15.unknown(),cameraId:z15.string().min(1).max(128).optional()});function compileSpatialDirection(input){const options=parseSpatialValue(compileOptionsSchema,input,"direction compilation");const direction=parseSpatialDirection(options.direction);const scene=parseSpatialValue(SpatialSceneV1Schema,options.scene,"scene");const sceneSha256=spatialValueSha256(scene);const advisories=[];const unresolvedIntents=[];if(direction.projectDigest!==sceneSha256){advisories.push(advisory("stale-digest",`Direction projectDigest ${direction.projectDigest} does not match the scene digest ${sceneSha256}.`))}if(resolveEntityId2(scene,direction.entityId)===undefined){advisories.push(advisory("unresolved-reference",`Directed entity ${direction.entityId} is not a scene entity.`,direction.entityId))}let cameraId;if(options.cameraId!==undefined){cameraId=scene.cameras.find((camera2)=>camera2.cameraId===options.cameraId)?.cameraId;if(cameraId===undefined)throw new SpatialSceneError("not-found",`Unknown camera ${options.cameraId}.`,"cameraId")}else if(scene.cameras.length===1){cameraId=scene.cameras[0].cameraId}else if(scene.cameras.length>1){cameraId=[...scene.cameras].map((camera2)=>camera2.cameraId).sort()[0];advisories.push(advisory("defaulted-camera",`Scene declares ${scene.cameras.length} cameras; coverage defaulted to ${cameraId}. Pass cameraId explicitly to silence this advisory.`))}else if(direction.coverage.length>0){advisories.push(advisory("missing-camera","Scene declares no cameras; coverage cannot resolve rigs or shots."))}const context={direction,scene,sceneSha256,cameraId,advisories,unresolvedIntents};const evaluation=cameraId===undefined?undefined:createSpatialEvaluationContext(scene);const checkInterval=(id,endUs)=>{if(endUs>scene.durationUs){advisories.push(advisory("interval-outside-scene",`Entry ${id} ends at ${endUs}us beyond scene duration ${scene.durationUs}us.`,id))}};const performance=[];for(const action of direction.actions){checkInterval(action.id,action.endUs);const characterEntityId=resolveEntityId2(scene,action.characterId);const targetEntityId=action.targetId===undefined?undefined:resolveEntityId2(scene,action.targetId);if(characterEntityId===undefined){advisories.push(advisory("unresolved-reference",`Action ${action.id} character ${action.characterId} is not a scene entity.`,action.id))}if(action.targetId!==undefined&&targetEntityId===undefined){advisories.push(advisory("unresolved-reference",`Action ${action.id} target ${action.targetId} is not a scene entity.`,action.id))}const intentId=proposalId("performance",action.id);const unresolved=["clip-digest","rig-digest","mapping-digest"];if(characterEntityId===undefined)unresolved.push("character-entity");if(action.targetId!==undefined&&targetEntityId===undefined)unresolved.push("target-entity");for(const slot of unresolved){unresolvedIntents.push(unresolvedSlot(intentId,"performance",action.id,slot,`Action ${action.id} cannot bind ${slot}; compile and admit a real clip, rig, and humanoid mapping first.`))}performance.push(deepFreezeJson({proposalId:intentId,actionId:action.id,characterId:action.characterId,action:action.action,clipKind:CLIP_KIND_BY_ACTION[action.action],startUs:action.startUs,endUs:action.endUs,...characterEntityId===undefined?{}:{characterEntityId},...targetEntityId===undefined?{}:{targetEntityId},unresolved}))}const beats=direction.beats.map((beat)=>({id:beat.id,startUs:beat.startUs,endUs:beat.endUs}));for(const beat of direction.beats)checkInterval(beat.id,beat.endUs);const cameraRigs=[];const shots=[];for(const coverage of direction.coverage){checkInterval(coverage.id,coverage.endUs);if(beats.length>0&&!beats.some((beat)=>beat.startUs<=coverage.startUs&&beat.endUs>=coverage.endUs)){advisories.push(advisory("coverage-ungrouped",`Coverage ${coverage.id} is not contained in any dramatic beat.`,coverage.id))}const subject=resolveSubject(context,coverage,evaluation);const rig=compileCoverageRig(context,coverage,subject);if(rig!==undefined){cameraRigs.push(rig);unresolvedIntents.push(unresolvedSlot(proposalId("camera",coverage.id),"camera",coverage.id,"camera-track",`Coverage ${coverage.id} rig is a proposal; compile it to a camera track before admission.`))}else if(cameraId!==undefined){unresolvedIntents.push(unresolvedSlot(proposalId("camera",coverage.id),"camera",coverage.id,"rig",`Coverage ${coverage.id} could not resolve a deterministic ${coverage.rigKind} rig.`))}if(cameraId!==undefined){const shotId=`shot_${spatialValueSha256({domain:"slopcamera.direction-shot.v1",coverageId:coverage.id}).slice(0,16)}`;shots.push(deepFreezeJson(SpatialShotV1Schema.parse({shotId,sceneSha256,cameraId,range:{startUs:coverage.startUs,endUs:coverage.endUs},sceneStartUs:coverage.startUs,playback:"once",overrides:[],...rig!==undefined&&(rig.kind==="tripod"||rig.kind==="handheld")?{cameraPoseOverride:rig.pose}:{}})));unresolvedIntents.push(unresolvedSlot(proposalId("shot",coverage.id),"shot",coverage.id,"render-plan",`Shot ${shotId} is unverified; bind a render plan and audit evidence before admission.`))}}const lookIntents=[];for(const look of direction.looks){checkInterval(look.id,look.endUs);const intentId=proposalId("look",look.id);for(const slot of["material-lighting","post-process"]){unresolvedIntents.push(unresolvedSlot(intentId,"look",look.id,slot,`Look ${look.id} carries authored text; compile ${slot} documents before admission.`))}lookIntents.push(deepFreezeJson({proposalId:intentId,lookId:look.id,startUs:look.startUs,endUs:look.endUs,lighting:look.lighting,atmosphere:look.atmosphere,unresolved:["material-lighting","post-process"]}))}return deepFreezeJson(SpatialDirectionCompilationSchema.parse({kind:"slopcamera.spatial-direction-compilation",schemaVersion:1,directionSha256:spatialDirectionSha256(direction),sceneSha256,compilerVersion:SPATIAL_DIRECTION_COMPILER_ID,verified:false,...cameraId===undefined?{}:{cameraId},proposals:{performance,cameraRigs,shots,lookIntents},advisories,unresolvedIntents}))}var checkOptionsSchema2=z15.strictObject({direction:z15.unknown(),scene:z15.unknown()});function checkSpatialDirection(input){const options=parseSpatialValue(checkOptionsSchema2,input,"direction check");const direction=parseSpatialDirection(options.direction);const scene=parseSpatialValue(SpatialSceneV1Schema,options.scene,"scene");const sceneSha256=spatialValueSha256(scene);const findings=[];const finding=(code,severity,detail,referenceId2)=>{findings.push(deepFreezeJson(referenceId2===undefined?{code,severity,detail}:{code,severity,referenceId:referenceId2,detail}))};if(direction.projectDigest!==sceneSha256){finding("stale-digest","error",`Direction projectDigest ${direction.projectDigest} does not match scene digest ${sceneSha256}; re-author or rebind the direction.`)}if(resolveEntityId2(scene,direction.entityId)===undefined){finding("unresolved-reference","error",`Directed entity ${direction.entityId} is not a scene entity.`,direction.entityId)}if(scene.cameras.length===0&&direction.coverage.length>0){finding("missing-camera","error","Direction declares camera coverage but the scene declares no cameras.")}for(const action of direction.actions){if(resolveEntityId2(scene,action.characterId)===undefined){finding("unresolved-reference","error",`Action ${action.id} character ${action.characterId} is not a scene entity.`,action.id)}if(action.targetId!==undefined&&resolveEntityId2(scene,action.targetId)===undefined){finding("unresolved-reference","error",`Action ${action.id} target ${action.targetId} is not a scene entity.`,action.id)}if(action.endUs>scene.durationUs){finding("interval-outside-scene","error",`Action ${action.id} ends at ${action.endUs}us beyond scene duration ${scene.durationUs}us.`,action.id)}}for(const coverage of direction.coverage){if(coverage.subjectId!==undefined&&resolveEntityId2(scene,coverage.subjectId)===undefined){finding("unresolved-reference","error",`Coverage ${coverage.id} subject ${coverage.subjectId} is not a scene entity.`,coverage.id)}if(coverage.endUs>scene.durationUs){finding("interval-outside-scene","error",`Coverage ${coverage.id} ends at ${coverage.endUs}us beyond scene duration ${scene.durationUs}us.`,coverage.id)}}const beats=direction.beats.map((beat)=>({id:beat.id,startUs:beat.startUs,endUs:beat.endUs}));for(const beat of direction.beats){if(beat.endUs>scene.durationUs){finding("interval-outside-scene","error",`Beat ${beat.id} ends at ${beat.endUs}us beyond scene duration ${scene.durationUs}us.`,beat.id)}}if(beats.length>0){for(const coverage of direction.coverage){if(!beats.some((beat)=>beat.startUs<=coverage.startUs&&beat.endUs>=coverage.endUs)){finding("coverage-ungrouped","warning",`Coverage ${coverage.id} is not contained in any dramatic beat.`,coverage.id)}}}for(const look of direction.looks){if(look.endUs>scene.durationUs){finding("interval-outside-scene","error",`Look ${look.id} ends at ${look.endUs}us beyond scene duration ${scene.durationUs}us.`,look.id)}}const errors=findings.filter((item)=>item.severity==="error").length;return deepFreezeJson(SpatialDirectionCheckReportSchema.parse({kind:"slopcamera.spatial-direction-check",schemaVersion:1,directionSha256:spatialDirectionSha256(direction),sceneSha256,findings,counts:{beats:direction.beats.length,actions:direction.actions.length,coverage:direction.coverage.length,looks:direction.looks.length,errors,warnings:findings.length-errors}}))}import{z as z16}from"zod";var SPATIAL_GALLERY_LIMITS=Object.freeze({candidates:6,previewSamples:8});var SpatialGalleryAxisSchema=z16.enum(["performance","camera","lighting","materials","effects","sequence"]);var SpatialGalleryCandidateSchema=z16.strictObject({candidateId:z16.string().min(1).max(96).regex(/^cand_[a-f0-9]{16}$/u),label:z16.string().min(1).max(128),parameter:z16.string().min(1).max(64),documentKind:z16.literal("slopcamera.spatial-direction-compilation"),documentSha256:SpatialDigestSchema,document:z16.unknown()});var SpatialGalleryPlanSchema=z16.strictObject({kind:z16.literal("slopcamera.spatial-gallery-plan"),schemaVersion:z16.literal(1),axis:SpatialGalleryAxisSchema,sourceSha256:SpatialDigestSchema,sceneSha256:SpatialDigestSchema,cameraId:SpatialCameraIdSchema.optional(),candidates:z16.array(SpatialGalleryCandidateSchema).max(SPATIAL_GALLERY_LIMITS.candidates),previewReel:z16.strictObject({sampleTimesUs:z16.array(SpatialTimeUsSchema).max(SPATIAL_GALLERY_LIMITS.previewSamples)}).optional(),selection:z16.strictObject({candidateId:z16.string().min(1).max(96),selectorDigest:SpatialDigestSchema.optional(),note:z16.string().min(1).max(256).optional()}).optional()});function spatialGalleryPlanSha256(plan){return spatialValueSha256(plan)}var CAMERA_VARIANT_RIGS=["tripod","dolly","orbit","rail","chase","handheld"];var PERFORMANCE_VARIANT_SCALE=[1,0.9,1.1,0.75,1.25,1.5];var LIGHTING_VARIANT_PRESETS=["neutral","low-key","high-key","night","dawn","storm"];var MATERIAL_VARIANT_PALETTES=["authored","warm","cool","monochrome","pastel","noir"];var SEQUENCE_VARIANT_STRIDE=[1,2,3,4,5,6];var EFFECTS_VARIANT_STACKS=[[],[{kind:"tone-map",exposure:1,whitePoint:4}],[{kind:"tone-map",exposure:1,whitePoint:4},{kind:"vignette",intensity:0.25,radius:0.5}],[{kind:"tone-map",exposure:1,whitePoint:4},{kind:"grain",intensity:0.08,seed:7}],[{kind:"tone-map",exposure:1,whitePoint:4},{kind:"bloom",threshold:0.85,intensity:0.35,radius:0.5}],[{kind:"tone-map",exposure:0.9,whitePoint:2},{kind:"vignette",intensity:0.35,radius:0.6},{kind:"grain",intensity:0.1,seed:11}]];var candidateId=(axis2,parameter,sourceSha256)=>`cand_${spatialValueSha256({domain:"slopcamera.gallery-candidate.v1",axis:axis2,parameter,sourceSha256}).slice(0,16)}`;function variantsForAxis(axis2,sceneDurationUs){switch(axis2){case"camera":return CAMERA_VARIANT_RIGS.map((rigKind)=>({parameter:rigKind,label:`All coverage on ${rigKind} rigs`,direction:(direction)=>deepFreezeJson({...direction,coverage:direction.coverage.map((coverage)=>({...coverage,rigKind}))})}));case"performance":return PERFORMANCE_VARIANT_SCALE.map((scale)=>({parameter:`pacing-${scale}`,label:`Action pacing scaled ${scale}\xD7`,direction:(direction)=>deepFreezeJson({...direction,actions:direction.actions.map((action)=>({...action,endUs:Math.min(action.startUs+Math.max(1,Math.round((action.endUs-action.startUs)*scale)),sceneDurationUs)}))})}));case"sequence":return SEQUENCE_VARIANT_STRIDE.map((stride)=>({parameter:`stride-${stride}`,label:stride===1?"Coverage-aligned shots":`Merge coverage in groups of ${stride}`,direction:(direction)=>{if(stride<=1)return direction;const coverage=[];for(let index2=0;index2<direction.coverage.length;index2+=stride){const group=direction.coverage.slice(index2,index2+stride);const first=group[0];const last=group[group.length-1];coverage.push({...first,endUs:last.endUs})}return deepFreezeJson({...direction,coverage})}}));case"lighting":return LIGHTING_VARIANT_PRESETS.map((preset)=>({parameter:preset,label:`Lighting preset ${preset}`,document:(compilation)=>SpatialDirectionCompilationSchema.parse(deepFreezeJson({...compilation,proposals:{...compilation.proposals,lookIntents:compilation.proposals.lookIntents.map((intent)=>({...intent,suggestedLightingPreset:preset}))}}))}));case"materials":return MATERIAL_VARIANT_PALETTES.map((palette)=>({parameter:palette,label:`Material palette ${palette}`,document:(compilation)=>SpatialDirectionCompilationSchema.parse(deepFreezeJson({...compilation,proposals:{...compilation.proposals,lookIntents:compilation.proposals.lookIntents.map((intent)=>({...intent,suggestedMaterialPalette:palette}))}}))}));case"effects":return EFFECTS_VARIANT_STACKS.map((stack,index2)=>({parameter:`stack-${index2}`,label:stack.length===0?"No post-process stack":`Post stack: ${stack.map((step)=>String(step.kind)).join(" \u2192 ")}`,document:(compilation)=>SpatialDirectionCompilationSchema.parse(deepFreezeJson({...compilation,proposals:{...compilation.proposals,lookIntents:compilation.proposals.lookIntents.map((intent)=>({...intent,suggestedPostProcess:stack}))}}))}))}}var galleryOptionsSchema=z16.strictObject({direction:z16.unknown(),scene:z16.unknown(),axis:SpatialGalleryAxisSchema,cameraId:z16.string().min(1).max(128).optional()});var compileVariant=(direction,scene,cameraId)=>compileSpatialDirection({direction,scene,...cameraId===undefined?{}:{cameraId}});function planSpatialDirectionGallery(input){const options=parseSpatialValue(galleryOptionsSchema,input,"direction gallery");const direction=parseSpatialValue(SpatialDirectionSchema,options.direction,"direction");const scene=parseSpatialValue(SpatialSceneV1Schema,options.scene,"scene");const base2=compileSpatialDirection({direction,scene,...options.cameraId===undefined?{}:{cameraId:options.cameraId}});const seen=new Set;const candidates=[];for(const variant of variantsForAxis(options.axis,scene.durationUs)){const document=variant.direction!==undefined?compileVariant(variant.direction(direction),scene,options.cameraId):variant.document(base2);const documentSha256=spatialDirectionCompilationSha256(document);if(seen.has(documentSha256))continue;seen.add(documentSha256);candidates.push(deepFreezeJson({candidateId:candidateId(options.axis,variant.parameter,base2.directionSha256),label:variant.label,parameter:variant.parameter,documentKind:"slopcamera.spatial-direction-compilation",documentSha256,document}));if(candidates.length>=SPATIAL_GALLERY_LIMITS.candidates)break}const sampleTimes=new Set;for(const beat of direction.beats){sampleTimes.add(Math.min(beat.startUs+Math.floor((beat.endUs-beat.startUs)/2),scene.durationUs))}for(const coverage of direction.coverage){sampleTimes.add(Math.min(coverage.startUs,scene.durationUs))}const previewReel=sampleTimes.size===0?undefined:{sampleTimesUs:[...sampleTimes].sort((a,b)=>a-b).slice(0,SPATIAL_GALLERY_LIMITS.previewSamples)};return deepFreezeJson(SpatialGalleryPlanSchema.parse({kind:"slopcamera.spatial-gallery-plan",schemaVersion:1,axis:options.axis,sourceSha256:base2.directionSha256,sceneSha256:base2.sceneSha256,...base2.cameraId===undefined?{}:{cameraId:base2.cameraId},candidates,...previewReel===undefined?{}:{previewReel}}))}function localBounds(entity){let half;if(entity.kind==="mesh"){switch(entity.geometry.kind){case"asset":return{status:"unknown",reason:"requires-asset-decoding"};case"box":half=entity.geometry.size.map((value)=>value/2);break;case"plane":half=[entity.geometry.width/2,entity.geometry.height/2,0];break;case"sphere":half=[entity.geometry.radius,entity.geometry.radius,entity.geometry.radius];break;case"cylinder":half=[entity.geometry.radius,entity.geometry.height/2,entity.geometry.radius];break}}else if(entity.kind==="image"||entity.kind==="diagram"||entity.kind==="video")half=[entity.width/2,entity.height/2,0];else return{status:"unknown",reason:entity.kind==="text"?"requires-text-layout":entity.kind==="splat"?"requires-asset-decoding":"no-surface"};return{min:[-half[0],-half[1],-half[2]],max:half}}function inspectSpatialScene(input){const scene=parseSpatialScene(input);const snapshot=evaluateSpatialScene(scene,{timeUs:0,cameraId:scene.cameras[0].cameraId});const digests=spatialAssetClosureDigests(scene.assets);return deepFreezeJson({sceneId:scene.sceneId,sceneSha256:spatialValueSha256(scene),durationUs:scene.durationUs,entities:snapshot.entities.map(({entity,worldMatrix})=>{const origin=entity.origin;const declared=origin.kind==="generated"?scene.generators.find((generator)=>generator.generatorId===origin.generatorId).editableKeys.find((item)=>item.key===origin.key)?.properties??[]:[...["color","opacity","transform"].filter((property)=>spatialPropertySupported(entity,property)),...entity.kind==="mesh"?[...(entity.material.kind==="standard"||entity.material.kind==="pbr")&&spatialPropertySupported(entity,"color")?["emissive"]:[],"instances","castShadow","receiveShadow"]:[],...entity.kind==="light"?[...entity.light==="spot"?["spot"]:[],...entity.light!=="ambient"?["shadow"]:[]]:[]];const animatedProperties=scene.animations.filter((channel)=>channel.targetId===entity.entityId).map((channel)=>channel.property);const editableControls=declared.filter((property)=>!animatedProperties.some((animated)=>animated===property||property==="transform"&&["position","rotation","scale"].includes(animated)));const local=localBounds(entity);const localDomains="status"in local?[]:entity.kind==="mesh"&&entity.instances!==undefined?entity.instances.map((instance)=>transformBounds(multiplyTransforms(worldMatrix,composeTransform(instance)),local)):[transformBounds(worldMatrix,local)];const bounds="status"in local?local:{status:"authored-enclosure",coordinateDomain:entity.placement,atTimeUs:0,bounds:localDomains.reduce((union,next)=>({min:union.min.map((value,axis2)=>Math.min(value,next.min[axis2])),max:union.max.map((value,axis2)=>Math.max(value,next.max[axis2]))}))};const meshMapIds=entity.kind==="mesh"?entity.material.kind==="pbr"?pbrMaterialMapAssetIds(entity.material):entity.material.map===undefined?[]:[entity.material.map]:[];const assetIds=entity.kind==="mesh"?[...entity.geometry.kind==="asset"?[entity.geometry.assetId]:[],...meshMapIds]:entity.kind==="text"?[entity.fontAssetId]:("assetId"in entity)?[entity.assetId]:[];return{entityId:entity.entityId,name:entity.name,kind:entity.kind,origin,parentId:entity.parentId,placement:entity.placement,editableControls,animatedProperties,assetIds,bounds}}),cameras:scene.cameras,assets:scene.assets.map((manifest)=>({assetId:manifest.assetId,manifestSha256:digests[manifest.assetId],manifest})),generators:scene.generators})}function diffCollection(collection,before,after,identify){const old=new Map(before.map((item)=>[identify(item),item]));const current=new Map(after.map((item)=>[identify(item),item]));const result=[];for(const id of[...new Set([...old.keys(),...current.keys()])].sort()){const a=old.get(id),b=current.get(id);if(a===undefined||b===undefined){result.push({kind:a===undefined?"added":"removed",collection,id,properties:Object.keys(a??b).sort()})}else{const aRecord=a,bRecord=b;const properties=[...new Set([...Object.keys(a),...Object.keys(b)])].sort().filter((key2)=>spatialValueSha256(Object.hasOwn(a,key2)?{value:aRecord[key2]}:{})!==spatialValueSha256(Object.hasOwn(b,key2)?{value:bRecord[key2]}:{}));if(properties.length)result.push({kind:"changed",collection,id,properties})}}return result}function diffSpatialScenes(beforeInput,afterInput){const before=parseSpatialScene(beforeInput);const after=parseSpatialScene(afterInput);return deepFreezeJson([...diffCollection("assets",before.assets,after.assets,(asset)=>asset.assetId),...diffCollection("entities",before.entities,after.entities,(entity)=>entity.entityId),...diffCollection("cameras",before.cameras,after.cameras,(camera2)=>camera2.cameraId),...diffCollection("animations",before.animations,after.animations,(channel)=>channel.channelId),...diffCollection("generators",before.generators,after.generators,(generator)=>generator.generatorId),...diffCollection("overrides",before.overrides,after.overrides,(override)=>`${override.entityId}:${override.property}`)])}function applySpatialScenePatch(sceneInput,patchInput){const original=parseSpatialScene(sceneInput);const patch=parseSpatialValue(SpatialScenePatchV1Schema,patchInput,"scene patch");if(patch.expectedSceneSha256!==spatialValueSha256(original))throw new SpatialSceneError("conflict","Scene revision changed; inspect and rebase the patch.","expectedSceneSha256");const entities=new Map(original.entities.map((entity)=>[entity.entityId,entity]));const assets=new Map(original.assets.map((asset)=>[asset.assetId,asset]));const addressedGeometry=new Set,replacedGenerators=new Set;const cameras=new Map(original.cameras.map((camera2)=>[camera2.cameraId,camera2]));const animations=new Map(original.animations.map((channel)=>[channel.channelId,channel]));const generators=new Map(original.generators.map((generator)=>[generator.generatorId,generator]));const overrides=new Map(original.overrides.map((override)=>[`${override.entityId}:${override.property}`,override]));function authored(id){const entity=entities.get(id);if(!entity)throw new SpatialSceneError("not-found",`Entity ${id} does not exist.`,"operations");if(entity.origin.kind!=="authored")throw new SpatialSceneError("conflict","Generated entities can be edited only through declared overrides or retained output replacement.","operations");return entity}for(const operation of patch.operations){switch(operation.kind){case"add-asset":if(assets.has(operation.asset.assetId))throw new SpatialSceneError("conflict",`Asset ${operation.asset.assetId} already exists.`);if(operation.asset.provenance.source==="generated")throw new SpatialSceneError("conflict","Generated assets enter only through retained generator output replacement.");assets.set(operation.asset.assetId,operation.asset);break;case"replace-asset":if(!assets.has(operation.asset.assetId))throw new SpatialSceneError("not-found",`Asset ${operation.asset.assetId} does not exist.`);if(operation.asset.provenance.source==="generated")throw new SpatialSceneError("conflict","Generated assets change only through retained generator output replacement.");if(original.generators.some((generator)=>generator.assets?.includes(operation.asset.assetId))){throw new SpatialSceneError("conflict",`Asset ${operation.asset.assetId} is owned by a generator; replace its retained output.`)}assets.set(operation.asset.assetId,operation.asset);break;case"set-mesh-geometry":{const entity=authored(operation.entityId);if(entity.kind!=="mesh")throw new SpatialSceneError("conflict","Geometry replacement requires an authored mesh wrapper.");entities.set(operation.entityId,{...entity,geometry:operation.geometry});addressedGeometry.add(operation.entityId);break}case"set-material":{const entity=authored(operation.entityId);if(entity.kind!=="mesh")throw new SpatialSceneError("conflict","Material replacement requires an authored mesh entity.");if(entity.geometry.kind==="asset"&&entity.geometry.materialMode==="source")throw new SpatialSceneError("conflict","Source-material meshes consume source materials only; the entity material is inert.");entities.set(operation.entityId,{...entity,material:operation.material});break}case"rename-entity":entities.set(operation.entityId,{...authored(operation.entityId),name:operation.name});break;case"reparent-entity":entities.set(operation.entityId,{...authored(operation.entityId),parentId:operation.parentId});break;case"set-transform":entities.set(operation.entityId,{...authored(operation.entityId),transform:operation.transform});break;case"set-color":entities.set(operation.entityId,applySpatialEntityOverride(authored(operation.entityId),{entityId:operation.entityId,property:"color",value:operation.color}));break;case"set-opacity":entities.set(operation.entityId,applySpatialEntityOverride(authored(operation.entityId),{entityId:operation.entityId,property:"opacity",value:operation.opacity}));break;case"set-emissive":{const entity=authored(operation.entityId);if(entity.kind!=="mesh"||entity.material.kind!=="standard"&&entity.material.kind!=="pbr")throw new SpatialSceneError("conflict","Emissive edits require an authored mesh with a standard or pbr material.","operations");if(!spatialPropertySupported(entity,"color"))throw new SpatialSceneError("conflict","Source-material mode leaves emissive control to the retained GLB material.","operations");if(entity.material.kind==="pbr"){const{emissive:_cleared,...material}=entity.material;entities.set(operation.entityId,{...entity,material:operation.emissive===null?material:{...material,emissive:{color:operation.emissive.color,intensity:operation.emissive.intensity}}})}else{const{emissive:_cleared,...material}=entity.material;entities.set(operation.entityId,{...entity,material:operation.emissive===null?material:{...material,emissive:operation.emissive}})}break}case"set-spot":{const entity=authored(operation.entityId);if(entity.kind!=="light"||entity.light!=="spot")throw new SpatialSceneError("conflict","Spot cone edits require an authored spot light.","operations");entities.set(operation.entityId,{...entity,spot:operation.spot});break}case"set-instances":{const entity=authored(operation.entityId);if(entity.kind!=="mesh")throw new SpatialSceneError("conflict","Instance edits apply to authored mesh entities.","operations");const{instances:_cleared,...rest}=entity;entities.set(operation.entityId,operation.instances===null?rest:{...rest,instances:operation.instances});break}case"set-mesh-shadow":{const entity=authored(operation.entityId);if(entity.kind!=="mesh")throw new SpatialSceneError("conflict","Mesh shadow flags apply to authored mesh entities.","operations");const{castShadow:_cast,receiveShadow:_receive,...rest}=entity;entities.set(operation.entityId,{...rest,...operation.castShadow===null?{}:{castShadow:operation.castShadow},...operation.receiveShadow===null?{}:{receiveShadow:operation.receiveShadow}});break}case"set-light-shadow":{const entity=authored(operation.entityId);if(entity.kind!=="light")throw new SpatialSceneError("conflict","Light shadow flags apply to authored light entities.","operations");if(entity.light==="ambient"&&operation.shadow!==null)throw new SpatialSceneError("conflict","Ambient lights cannot cast shadows.","operations");const{shadow:_shadow,...rest}=entity;entities.set(operation.entityId,operation.shadow===null?rest:{...rest,shadow:operation.shadow});break}case"set-camera":cameras.set(operation.camera.cameraId,operation.camera);break;case"set-channel":animations.set(operation.channel.channelId,operation.channel);break;case"remove-channel":if(!animations.delete(operation.channelId))throw new SpatialSceneError("not-found",`Channel ${operation.channelId} does not exist.`);break;case"add-entity":if(entities.has(operation.entity.entityId))throw new SpatialSceneError("conflict",`Entity ${operation.entity.entityId} already exists.`);if(operation.entity.origin.kind!=="authored")throw new SpatialSceneError("conflict","Add generated entities through retained generator output replacement.");entities.set(operation.entity.entityId,operation.entity);if(operation.entity.kind==="mesh")addressedGeometry.add(operation.entity.entityId);break;case"remove-entity":authored(operation.entityId);entities.delete(operation.entityId);break;case"set-override":overrides.set(`${operation.override.entityId}:${operation.override.property}`,operation.override);break;case"remove-override":if(!overrides.delete(`${operation.entityId}:${operation.property}`))throw new SpatialSceneError("not-found","Override does not exist.");break;case"replace-generator-output":{const generatorId=operation.generator.generatorId;replacedGenerators.add(generatorId);const previous=generators.get(generatorId)?.assets??[];const provided=operation.assets??[];const declared=operation.generator.assets??[];if([...provided.map((asset)=>asset.assetId)].sort().join("")!==[...declared].sort().join("")){throw new SpatialSceneError("conflict","Generator replacement must carry exactly the manifests its record declares.")}for(const asset of provided){if(asset.provenance.source!=="generated"&&asset.provenance.source!=="derived"){throw new SpatialSceneError("conflict","Generator-owned assets require generated or derived provenance.")}if(assets.has(asset.assetId)&&!previous.includes(asset.assetId))throw new SpatialSceneError("conflict",`Generator asset ${asset.assetId} collides with an existing asset.`)}for(const assetId2 of previous)assets.delete(assetId2);for(const entity of entities.values())if(entity.origin.kind==="generated"&&entity.origin.generatorId===generatorId)entities.delete(entity.entityId);for(const asset of provided)assets.set(asset.assetId,asset);const owned=new Set(provided.map((asset)=>asset.assetId));const remainingAssets=new Set(assets.keys());for(const entity of operation.entities){if(entity.origin.kind!=="generated"||entity.origin.generatorId!==generatorId)throw new SpatialSceneError("conflict","Generator replacement must contain only its own retained output.");if(entities.has(entity.entityId))throw new SpatialSceneError("conflict",`Generator output collides with ${entity.entityId}.`);const referenced=entity.kind==="mesh"&&entity.geometry.kind==="asset"?[entity.geometry.assetId]:entity.kind==="text"?[entity.fontAssetId]:("assetId"in entity)?[entity.assetId]:[];if(entity.kind==="mesh"&&entity.material.kind!=="pbr"&&entity.material.map!==undefined)referenced.push(entity.material.map);for(const assetId2 of referenced){if(!owned.has(assetId2)&&!remainingAssets.has(assetId2))throw new SpatialSceneError("conflict",`Generator output references missing asset ${assetId2}.`)}entities.set(entity.entityId,entity)}generators.set(generatorId,operation.generator);break}}}const scene=parseSpatialScene({...original,assets:[...assets.values()],entities:[...entities.values()],cameras:[...cameras.values()],animations:[...animations.values()],generators:[...generators.values()],overrides:[...overrides.values()]});const beforeAssets=new Map(original.assets.map((asset)=>[asset.assetId,asset]));const oldClosure=spatialAssetClosureDigests(original.assets),newClosure=spatialAssetClosureDigests(scene.assets);for(const entity of scene.entities){const referenced=entity.kind==="mesh"&&entity.geometry.kind==="asset"?[entity.geometry.assetId]:entity.kind==="text"?[entity.fontAssetId]:("assetId"in entity)?[entity.assetId]:[];if(entity.kind==="mesh"){if(entity.material.kind==="pbr")referenced.push(...pbrMaterialMapAssetIds(entity.material));else if(entity.material.map!==undefined)referenced.push(entity.material.map)}for(const assetId2 of referenced){if(entity.origin.kind==="generated"&&oldClosure[assetId2]!==undefined&&oldClosure[assetId2]!==newClosure[assetId2]&&!replacedGenerators.has(entity.origin.generatorId)){throw new SpatialSceneError("conflict","Changing a generated part's asset closure requires explicit retained generator output replacement.")}}if(entity.kind==="mesh"&&entity.geometry.kind==="asset"&&(entity.geometry.nodeIndex!==undefined||entity.geometry.clip!==undefined)&&beforeAssets.has(entity.geometry.assetId)&&beforeAssets.get(entity.geometry.assetId).payload.sha256!==assets.get(entity.geometry.assetId).payload.sha256&&!addressedGeometry.has(entity.entityId)&&!(entity.origin.kind==="generated"&&replacedGenerators.has(entity.origin.generatorId))){throw new SpatialSceneError("conflict","Replacing addressed GLB bytes requires explicit set-mesh-geometry with the new local node/clip addresses; internal correspondence is not inferred.")}}const diff=diffSpatialScenes(original,scene);return deepFreezeJson({scene,sceneSha256:spatialValueSha256(scene),diff})}import{z as z17}from"zod";var SPATIAL_PARTICLE_LIMITS=Object.freeze({collisionVolumes:16,curveKeys:16,durationUs:3600000000,emitters:64,final:1e6,forces:16,killVolumes:16,preview:1e5,splinePoints:64});var finiteCoordinate3=z17.number().finite().min(-1e6).max(1e6);var positiveDimension3=z17.number().finite().positive().max(1e6);var unit5=z17.number().finite().min(0).max(1);var vec34=z17.tuple([finiteCoordinate3,finiteCoordinate3,finiteCoordinate3]);var rgba=z17.tuple([unit5,unit5,unit5,unit5]);var particleId=z17.string().min(1).max(64).regex(/^[a-z][a-z0-9_-]*$/u);var scalarCurveKey=z17.strictObject({t:unit5,value:unit5});var scalarCurveKeys=z17.array(scalarCurveKey).min(2).max(SPATIAL_PARTICLE_LIMITS.curveKeys).superRefine((keys,context)=>{if(keys[0]?.t!==0||keys[keys.length-1]?.t!==1){context.addIssue({code:"custom",message:"Particle curves must cover normalized time from 0 through 1."})}for(let index2=1;index2<keys.length;index2+=1){if(keys[index2].t<=keys[index2-1].t){context.addIssue({code:"custom",path:[index2,"t"],message:"Particle curve keys must have strictly increasing time."})}}});var colorCurveKey=z17.strictObject({t:unit5,color:rgba});var keyedColorCurve=z17.array(colorCurveKey).min(2).max(SPATIAL_PARTICLE_LIMITS.curveKeys).superRefine((keys,context)=>{if(keys[0]?.t!==0||keys[keys.length-1]?.t!==1){context.addIssue({code:"custom",message:"Particle color curves must cover normalized time from 0 through 1."})}for(let index2=1;index2<keys.length;index2+=1){if(keys[index2].t<=keys[index2-1].t){context.addIssue({code:"custom",path:[index2,"t"],message:"Particle color keys must have strictly increasing time."})}}});var legacyColorCurve=z17.array(rgba).min(2).max(SPATIAL_PARTICLE_LIMITS.curveKeys).transform((colors)=>colors.map((color3,index2)=>({t:index2/(colors.length-1),color:color3})));var SpatialParticleEmitterShapeSchema=z17.discriminatedUnion("kind",[z17.strictObject({kind:z17.literal("point")}),z17.strictObject({kind:z17.literal("sphere"),radius:positiveDimension3,volume:z17.boolean().default(true)}),z17.strictObject({kind:z17.literal("box"),size:z17.tuple([positiveDimension3,positiveDimension3,positiveDimension3]),volume:z17.boolean().default(true)}),z17.strictObject({kind:z17.literal("disc"),radius:positiveDimension3}),z17.strictObject({kind:z17.literal("surface"),assetId:SpatialAssetIdSchema}),z17.strictObject({kind:z17.literal("spline"),controlPoints:z17.array(vec34).min(2).max(SPATIAL_PARTICLE_LIMITS.splinePoints)})]);var SpatialParticleForceSchema=z17.discriminatedUnion("kind",[z17.strictObject({kind:z17.literal("gravity"),acceleration:vec34}),z17.strictObject({kind:z17.literal("drag"),coefficient:unit5}),z17.strictObject({kind:z17.literal("vortex"),axis:vec34,strength:z17.number().finite().min(-1e6).max(1e6)}),z17.strictObject({kind:z17.literal("turbulence"),seed:z17.number().int().min(0).max(2147483647),scale:positiveDimension3,strength:positiveDimension3})]);var boxVolumeShape={kind:z17.literal("box"),max:vec34,min:vec34};var sphereVolumeShape={center:vec34,kind:z17.literal("sphere"),radius:positiveDimension3};var SpatialParticleKillVolumeSchema=z17.discriminatedUnion("kind",[z17.strictObject(boxVolumeShape),z17.strictObject(sphereVolumeShape)]);var SpatialParticleCollisionVolumeSchema=z17.discriminatedUnion("kind",[z17.strictObject({...boxVolumeShape,response:z17.enum(["bounce","slide"]),restitution:unit5}),z17.strictObject({...sphereVolumeShape,response:z17.enum(["bounce","slide"]),restitution:unit5})]);var SpatialParticleCurveSchema=z17.strictObject({keys:scalarCurveKeys});var SpatialParticleEmitterSchema=z17.strictObject({burst:z17.number().int().min(0).max(SPATIAL_PARTICLE_LIMITS.final).optional(),colorOverLife:z17.union([keyedColorCurve,legacyColorCurve]),enabled:z17.boolean().default(true),id:particleId,lifetimeUs:z17.tuple([SpatialTimeUsSchema.min(1).max(SPATIAL_PARTICLE_LIMITS.durationUs),SpatialTimeUsSchema.min(1).max(SPATIAL_PARTICLE_LIMITS.durationUs)]),opacityOverLife:SpatialParticleCurveSchema,rate:z17.number().int().min(0).max(SPATIAL_PARTICLE_LIMITS.final),seed:z17.number().int().min(0).max(2147483647),shape:SpatialParticleEmitterShapeSchema,sizeOverLife:SpatialParticleCurveSchema,velocity:vec34,velocitySpread:z17.tuple([unit5,unit5,unit5])}).superRefine((emitter,context)=>{if(emitter.lifetimeUs[1]<emitter.lifetimeUs[0]){context.addIssue({code:"custom",path:["lifetimeUs",1],message:"Maximum particle lifetime must not precede minimum lifetime."})}if(emitter.rate===0&&(emitter.burst??0)===0){context.addIssue({code:"custom",message:"An emitter must declare a positive rate or burst."})}if(emitter.shape.kind==="spline"){const distinct=new Set(emitter.shape.controlPoints.map((point)=>point.join(",")));if(distinct.size<2)context.addIssue({code:"custom",path:["shape","controlPoints"],message:"A spline emitter needs at least two distinct control points."})}});var SpatialParticleRendererSchema=z17.discriminatedUnion("kind",[z17.strictObject({kind:z17.literal("sprite"),assetId:SpatialAssetIdSchema.optional(),billboard:z17.boolean().default(true)}),z17.strictObject({kind:z17.literal("instanced-mesh"),assetId:SpatialAssetIdSchema})]);var SpatialParticleSystemSchema=z17.strictObject({collisionVolumes:z17.array(SpatialParticleCollisionVolumeSchema).max(SPATIAL_PARTICLE_LIMITS.collisionVolumes).default([]),countTier:z17.enum(["preview","final"]),emitters:z17.array(SpatialParticleEmitterSchema).min(1).max(SPATIAL_PARTICLE_LIMITS.emitters),entityId:SpatialEntityIdSchema,forces:z17.array(SpatialParticleForceSchema).max(SPATIAL_PARTICLE_LIMITS.forces),killVolumes:z17.array(SpatialParticleKillVolumeSchema).max(SPATIAL_PARTICLE_LIMITS.killVolumes),kind:z17.literal("slopcamera.spatial-particle-system"),maxCount:z17.number().int().min(1).max(SPATIAL_PARTICLE_LIMITS.final),preBake:z17.boolean().default(false),renderer:SpatialParticleRendererSchema.default({kind:"sprite",billboard:true}),schemaVersion:z17.literal(1)});function assertBoxVolume(volume,label){if(volume.kind!=="box"||volume.min===undefined||volume.max===undefined)return;if(volume.min.some((value,index2)=>value>=volume.max[index2])){throw new SpatialSceneError("invalid-data",`${label} box minimum coordinates must be below maximum coordinates.`,"particle-system")}}function parseSpatialParticleSystem(input){const system=parseSpatialValue(SpatialParticleSystemSchema,input,"particle system");const tierLimit=system.countTier==="preview"?SPATIAL_PARTICLE_LIMITS.preview:SPATIAL_PARTICLE_LIMITS.final;if(system.maxCount>tierLimit){throw new SpatialSceneError("invalid-data",`Particle system ${system.entityId} requests ${system.maxCount} particles, exceeding the ${system.countTier} tier limit of ${tierLimit}.`,"particle-system")}const emitterIds=system.emitters.map((emitter)=>emitter.id);if(new Set(emitterIds).size!==emitterIds.length){throw new SpatialSceneError("invalid-data",`Particle system ${system.entityId} has duplicate emitter IDs.`,"particle-system")}const simultaneousBound=system.emitters.reduce((sum,emitter)=>emitter.enabled?sum+(emitter.burst??0)+Math.ceil(emitter.rate*emitter.lifetimeUs[1]/1e6):sum,0);if(simultaneousBound>system.maxCount){throw new SpatialSceneError("invalid-data",`Particle system ${system.entityId} simultaneous bound (${simultaneousBound}) exceeds maxCount (${system.maxCount}).`,"particle-system")}for(const volume of system.killVolumes)assertBoxVolume(volume,"Kill volume");for(const volume of system.collisionVolumes)assertBoxVolume(volume,"Collision volume");for(const force of system.forces){if(force.kind==="vortex"&&force.axis.every((value)=>value===0)){throw new SpatialSceneError("invalid-data","Vortex axes must be nonzero.","particle-system")}}return deepFreezeJson(system)}function spatialParticleAssetIds(system){const ids=new Set;if("assetId"in system.renderer&&system.renderer.assetId!==undefined)ids.add(system.renderer.assetId);for(const emitter of system.emitters){if(emitter.shape.kind==="surface")ids.add(emitter.shape.assetId)}return Object.freeze([...ids].sort())}function spatialParticleSystemSha256(system){return spatialValueSha256(system)}import{z as z18}from"zod";var SPATIAL_SIMULATION_LIMITS=Object.freeze({bodies:256,constraints:256,durationUs:3600000000,outputBytes:1e9,steps:1e5,substeps:128});var positiveDimension4=z18.number().finite().positive().max(1e6);var unit6=z18.number().finite().min(0).max(1);var bodyId=z18.string().min(1).max(64).regex(/^[a-z][a-z0-9_-]*$/u);var constraintId=z18.string().min(1).max(64).regex(/^[a-z][a-z0-9_-]*$/u);var SpatialSimulationEngineSchema=z18.strictObject({identitySha256:SpatialDigestSchema,profile:z18.enum(["slopcamera-rigid-body-reference-v1","slopcamera-native-secondary-motion-v1"])});var SpatialRigidBodySchema=z18.strictObject({entityId:SpatialEntityIdSchema,friction:unit6,id:bodyId,initialAngularVelocity:SpatialVec3Schema,initialOrientation:SpatialQuaternionSchema,initialPosition:SpatialVec3Schema,initialVelocity:SpatialVec3Schema,mass:z18.number().finite().min(0).max(1e9),pinned:z18.boolean().default(false),restitution:unit6,shape:z18.discriminatedUnion("kind",[z18.strictObject({kind:z18.literal("sphere"),radius:positiveDimension4}),z18.strictObject({kind:z18.literal("box"),size:z18.tuple([positiveDimension4,positiveDimension4,positiveDimension4])}),z18.strictObject({height:positiveDimension4,kind:z18.literal("capsule"),radius:positiveDimension4})])}).superRefine((body,context)=>{if(!body.pinned&&body.mass<=0){context.addIssue({code:"custom",path:["mass"],message:"Unpinned rigid bodies require positive mass."})}});var constraintBase={bodyA:bodyId,bodyB:bodyId,constraintId};var SpatialConstraintSchema=z18.discriminatedUnion("kind",[z18.strictObject({...constraintBase,axis:SpatialVec3Schema,kind:z18.literal("hinge"),limits:z18.tuple([z18.number().finite(),z18.number().finite()]).optional()}),z18.strictObject({...constraintBase,damping:z18.number().finite().min(0).max(1e6),kind:z18.literal("spring"),stiffness:positiveDimension4}),z18.strictObject({...constraintBase,kind:z18.literal("fixed"),localA:SpatialVec3Schema,localB:SpatialVec3Schema})]);var SpatialSimulationPlanSchema=z18.strictObject({bodies:z18.array(SpatialRigidBodySchema).min(1).max(SPATIAL_SIMULATION_LIMITS.bodies),cacheId:z18.string().min(1).max(128).regex(/^cache_[a-z0-9][a-z0-9_-]*$/u),constraints:z18.array(SpatialConstraintSchema).max(SPATIAL_SIMULATION_LIMITS.constraints),engine:SpatialSimulationEngineSchema,entityId:SpatialEntityIdSchema,gravity:SpatialVec3Schema,kind:z18.literal("slopcamera.spatial-simulation-plan"),maxSubsteps:z18.number().int().min(1).max(SPATIAL_SIMULATION_LIMITS.substeps),maximumOutputBytes:z18.number().int().safe().positive().max(SPATIAL_SIMULATION_LIMITS.outputBytes).default(SPATIAL_SIMULATION_LIMITS.outputBytes),schemaVersion:z18.literal(1),seed:z18.number().int().min(0).max(2147483647),simulationKind:z18.enum(["rigid-body","secondary-motion"]).default("rigid-body"),sourceDigest:SpatialDigestSchema,stepCount:z18.number().int().min(1).max(SPATIAL_SIMULATION_LIMITS.steps),timeStepUs:SpatialTimeUsSchema.min(1).max(1e6)}).superRefine((plan,context)=>{if(plan.simulationKind==="rigid-body"&&plan.engine.profile!=="slopcamera-rigid-body-reference-v1"||plan.simulationKind==="secondary-motion"&&plan.engine.profile!=="slopcamera-native-secondary-motion-v1"){context.addIssue({code:"custom",path:["engine","profile"],message:"Simulation kind must match its closed engine profile."})}if(plan.timeStepUs*plan.stepCount>SPATIAL_SIMULATION_LIMITS.durationUs){context.addIssue({code:"custom",path:["stepCount"],message:"Simulation duration exceeds one hour."})}const bodyIds=new Set;const entityIds=new Set;for(const[index2,body]of plan.bodies.entries()){if(bodyIds.has(body.id))context.addIssue({code:"custom",path:["bodies",index2,"id"],message:`Duplicate rigid-body id ${body.id}.`});if(entityIds.has(body.entityId))context.addIssue({code:"custom",path:["bodies",index2,"entityId"],message:`Entity ${body.entityId} has more than one rigid body.`});bodyIds.add(body.id);entityIds.add(body.entityId)}const constraintIds=new Set;for(const[index2,constraint]of plan.constraints.entries()){if(constraintIds.has(constraint.constraintId))context.addIssue({code:"custom",path:["constraints",index2,"constraintId"],message:`Duplicate constraint id ${constraint.constraintId}.`});constraintIds.add(constraint.constraintId);const missingBodies=[constraint.bodyA,constraint.bodyB].filter((id)=>!bodyIds.has(id));if(missingBodies.length>0){context.addIssue({code:"custom",path:["constraints",index2],message:`Constraint ${constraint.constraintId} references unknown body ${missingBodies.join(", ")}.`})}if(constraint.bodyA===constraint.bodyB){context.addIssue({code:"custom",path:["constraints",index2],message:`Constraint ${constraint.constraintId} cannot connect a body to itself.`})}if(constraint.kind==="hinge"){if(constraint.axis.every((value)=>value===0))context.addIssue({code:"custom",path:["constraints",index2,"axis"],message:"Hinge axes must be nonzero."});if(constraint.limits!==undefined&&constraint.limits[1]<constraint.limits[0])context.addIssue({code:"custom",path:["constraints",index2,"limits"],message:"Hinge limits must be ordered."})}}const estimatedBytes=plan.bodies.length*plan.stepCount*10*Float64Array.BYTES_PER_ELEMENT;if(estimatedBytes>plan.maximumOutputBytes){context.addIssue({code:"custom",path:["maximumOutputBytes"],message:`Estimated ordinary-animation bytes (${estimatedBytes}) exceed maximumOutputBytes (${plan.maximumOutputBytes}).`})}});var simulationBakeReceiptBodySchema=z18.strictObject({cacheId:z18.string().min(1).max(128).regex(/^cache_[a-z0-9][a-z0-9_-]*$/u),engine:SpatialSimulationEngineSchema,kind:z18.literal("slopcamera.spatial-simulation-bake-receipt"),output:z18.strictObject({animationSha256:SpatialDigestSchema,bytes:z18.number().int().safe().positive().max(SPATIAL_SIMULATION_LIMITS.outputBytes),channelCount:z18.number().int().min(1).max(SPATIAL_SIMULATION_LIMITS.bodies*2),keyCount:z18.number().int().min(1).max(SPATIAL_SIMULATION_LIMITS.bodies*SPATIAL_SIMULATION_LIMITS.steps*2)}),planSha256:SpatialDigestSchema,schemaVersion:z18.literal(1),seed:z18.number().int().min(0).max(2147483647),sourceDigest:SpatialDigestSchema,stepCount:z18.number().int().min(1).max(SPATIAL_SIMULATION_LIMITS.steps),timeStepUs:SpatialTimeUsSchema.min(1).max(1e6)});var SpatialSimulationBakeReceiptSchema=simulationBakeReceiptBodySchema.extend({receiptSha256:SpatialDigestSchema});function parseSpatialSimulationPlan(input){return deepFreezeJson(parseSpatialValue(SpatialSimulationPlanSchema,input,"simulation plan"))}function spatialSimulationPlanSha256(plan){return spatialValueSha256(plan)}function createSpatialSimulationBakeReceipt(input){const body=simulationBakeReceiptBodySchema.parse(input);return deepFreezeJson(SpatialSimulationBakeReceiptSchema.parse({...body,receiptSha256:canonicalJsonSha256(body)}))}function parseSpatialSimulationBakeReceipt(input){const receipt=parseSpatialValue(SpatialSimulationBakeReceiptSchema,input,"simulation bake receipt");const{receiptSha256,...body}=receipt;if(canonicalJsonSha256(body)!==receiptSha256){throw new SpatialSceneError("conflict","Simulation bake receipt digest does not match its body.","simulation-bake")}return deepFreezeJson(receipt)}function reconcileSpatialSimulationBakeReceipt(planInput,receiptInput){const plan=parseSpatialSimulationPlan(planInput);const receipt=parseSpatialSimulationBakeReceipt(receiptInput);const planSha256=spatialSimulationPlanSha256(plan);if(receipt.planSha256!==planSha256||receipt.cacheId!==plan.cacheId||receipt.sourceDigest!==plan.sourceDigest||receipt.engine.profile!==plan.engine.profile||receipt.engine.identitySha256!==plan.engine.identitySha256||receipt.seed!==plan.seed||receipt.stepCount!==plan.stepCount||receipt.timeStepUs!==plan.timeStepUs){throw new SpatialSceneError("conflict","Simulation bake receipt is stale or belongs to a different plan, cache, source, engine, seed, or clock.","simulation-bake")}if(receipt.output.bytes>plan.maximumOutputBytes){throw new SpatialSceneError("invalid-data","Simulation bake output exceeds the plan output-byte budget.","simulation-bake")}return deepFreezeJson(receipt)}import{z as z19}from"zod";var SPATIAL_RENDER_EFFECTS_LIMITS=Object.freeze({particleSystems:64,simulationBakes:64});var particleBindingSchema=z19.strictObject({system:SpatialParticleSystemSchema,systemSha256:SpatialDigestSchema});var SpatialRenderEffectsDocumentSchema=z19.strictObject({kind:z19.literal("slopcamera.spatial-render-effects"),particleSystems:z19.array(particleBindingSchema).max(SPATIAL_RENDER_EFFECTS_LIMITS.particleSystems),renderPlan:SpatialRenderPlanSchema,renderPlanSha256:SpatialDigestSchema,sceneSha256:SpatialDigestSchema,schemaVersion:z19.literal(1),simulationBakes:z19.array(SpatialSimulationBakeReceiptSchema).max(SPATIAL_RENDER_EFFECTS_LIMITS.simulationBakes)}).superRefine((document,context)=>{if(spatialRenderPlanSha256(document.renderPlan)!==document.renderPlanSha256){context.addIssue({code:"custom",path:["renderPlanSha256"],message:"Render-plan digest does not match the canonical render plan."})}const particleEntities=new Set;for(const[index2,binding]of document.particleSystems.entries()){if(spatialParticleSystemSha256(binding.system)!==binding.systemSha256){context.addIssue({code:"custom",path:["particleSystems",index2,"systemSha256"],message:"Particle-system digest does not match its canonical system."})}if(particleEntities.has(binding.system.entityId)){context.addIssue({code:"custom",path:["particleSystems",index2,"system","entityId"],message:`Duplicate particle-system entity ${binding.system.entityId}.`})}particleEntities.add(binding.system.entityId)}const caches=new Set;for(const[index2,receipt]of document.simulationBakes.entries()){const{receiptSha256,...body}=receipt;if(canonicalJsonSha256(body)!==receiptSha256){context.addIssue({code:"custom",path:["simulationBakes",index2,"receiptSha256"],message:"Simulation bake receipt digest does not match its canonical body."})}if(receipt.sourceDigest!==document.sceneSha256){context.addIssue({code:"custom",path:["simulationBakes",index2,"sourceDigest"],message:"Simulation bake receipt belongs to a different scene source."})}if(caches.has(receipt.cacheId)){context.addIssue({code:"custom",path:["simulationBakes",index2,"cacheId"],message:`Duplicate simulation cache ${receipt.cacheId}.`})}caches.add(receipt.cacheId)}const particleCount=document.particleSystems.reduce((sum,binding)=>sum+binding.system.maxCount,0);if(document.renderPlan.quality.particleCount!==particleCount){context.addIssue({code:"custom",path:["renderPlan","quality","particleCount"],message:"Render quality must declare the exact aggregate particle-state count."})}const simulationSteps=document.simulationBakes.reduce((sum,receipt)=>sum+receipt.stepCount,0);if(document.renderPlan.quality.simulationSteps!==simulationSteps){context.addIssue({code:"custom",path:["renderPlan","quality","simulationSteps"],message:"Render quality must declare the exact aggregate simulation-step count."})}});var SpatialRenderEffectsBindingSchema=z19.strictObject({document:SpatialRenderEffectsDocumentSchema,documentSha256:SpatialDigestSchema}).superRefine((binding,context)=>{if(spatialRenderEffectsSha256(binding.document)!==binding.documentSha256){context.addIssue({code:"custom",path:["documentSha256"],message:"Render-effects digest does not match the canonical document."})}});function parseSpatialRenderEffectsDocument(input){return deepFreezeJson(parseSpatialValue(SpatialRenderEffectsDocumentSchema,input,"render effects"))}function spatialRenderEffectsAssetIds(document){return Object.freeze([...new Set([...spatialRenderPlanAssetIds(document.renderPlan),...document.particleSystems.flatMap((binding)=>spatialParticleAssetIds(binding.system))])].sort())}function spatialRenderEffectsSha256(document){return spatialValueSha256(document)}var SPATIAL_EFFECTS_CHECK_LIMITS=Object.freeze({findings:256});var SpatialEffectsCheckFindingSchema=z19.strictObject({code:z19.enum(["stale-scene","unresolved-entity","unresolved-asset"]),severity:z19.enum(["error","warning"]),referenceId:z19.string().min(1).max(128).optional(),detail:z19.string().min(1).max(240)});var SpatialEffectsCheckReportSchema=z19.strictObject({kind:z19.literal("slopcamera.spatial-render-effects-check"),schemaVersion:z19.literal(1),documentSha256:SpatialDigestSchema,sceneSha256:SpatialDigestSchema,findings:z19.array(SpatialEffectsCheckFindingSchema).max(SPATIAL_EFFECTS_CHECK_LIMITS.findings),counts:z19.strictObject({particleSystems:z19.number().int().min(0),simulationBakes:z19.number().int().min(0),postProcessSteps:z19.number().int().min(0),errors:z19.number().int().min(0),warnings:z19.number().int().min(0)})});var effectsCheckInputSchema=z19.strictObject({effects:z19.unknown(),scene:z19.unknown()});var parseEffectsInput=(input)=>{if(input!==null&&typeof input==="object"&&"document"in input){const binding=parseSpatialValue(SpatialRenderEffectsBindingSchema,input,"render effects binding");return{document:binding.document,documentSha256:binding.documentSha256}}const document=parseSpatialRenderEffectsDocument(input);return{document,documentSha256:spatialRenderEffectsSha256(document)}};function checkSpatialRenderEffects(input){const options=parseSpatialValue(effectsCheckInputSchema,input,"render effects check");const scene=parseSpatialValue(SpatialSceneV1Schema,options.scene,"scene");const sceneSha256=spatialValueSha256(scene);const{document,documentSha256}=parseEffectsInput(options.effects);const findings=[];const finding=(code,detail,referenceId2)=>{findings.push(deepFreezeJson(referenceId2===undefined?{code,severity:"error",detail}:{code,severity:"error",referenceId:referenceId2,detail}))};if(document.sceneSha256!==sceneSha256){finding("stale-scene",`Effects document binds scene ${document.sceneSha256} but the checked scene digests to ${sceneSha256}.`)}const entityIds=new Set(scene.entities.map((entity)=>entity.entityId));for(const binding of document.particleSystems){if(!entityIds.has(binding.system.entityId)){finding("unresolved-entity",`Particle system on ${binding.system.entityId} does not resolve to a scene entity.`,binding.system.entityId)}}const assetIds=new Set(scene.assets.map((asset)=>asset.assetId));for(const assetId2 of spatialRenderEffectsAssetIds(document)){if(!assetIds.has(assetId2)){finding("unresolved-asset",`Effects document references asset ${assetId2} absent from the scene manifest.`,assetId2)}}const errors=findings.filter((item)=>item.severity==="error").length;return deepFreezeJson(SpatialEffectsCheckReportSchema.parse({kind:"slopcamera.spatial-render-effects-check",schemaVersion:1,documentSha256,sceneSha256,findings,counts:{particleSystems:document.particleSystems.length,simulationBakes:document.simulationBakes.length,postProcessSteps:document.renderPlan.postProcess?.steps.length??0,errors,warnings:findings.length-errors}}))}var effectsPlanInputSchema=z19.strictObject({scene:z19.unknown(),renderPlan:z19.unknown(),particleSystems:z19.array(z19.unknown()).max(SPATIAL_RENDER_EFFECTS_LIMITS.particleSystems).default([]),simulationBakes:z19.array(z19.unknown()).max(SPATIAL_RENDER_EFFECTS_LIMITS.simulationBakes).default([])});function planSpatialRenderEffects(input){const options=parseSpatialValue(effectsPlanInputSchema,input,"render effects plan");const scene=parseSpatialValue(SpatialSceneV1Schema,options.scene,"scene");const sceneSha256=spatialValueSha256(scene);const renderPlan=parseSpatialValue(SpatialRenderPlanSchema,options.renderPlan,"render plan");const particleSystems=options.particleSystems.map((system)=>parseSpatialValue(SpatialParticleSystemSchema,system,"particle system"));const simulationBakes=options.simulationBakes.map((receipt)=>parseSpatialValue(SpatialSimulationBakeReceiptSchema,receipt,"simulation bake receipt"));const entityIds=new Set(scene.entities.map((entity)=>entity.entityId));for(const system of particleSystems){if(!entityIds.has(system.entityId)){throw new SpatialSceneError("invalid-data",`Particle system on ${system.entityId} does not resolve to a scene entity.`,"particleSystems")}}const assetIds=new Set(scene.assets.map((asset)=>asset.assetId));const referenced=[...spatialRenderPlanAssetIds(renderPlan),...particleSystems.flatMap((system)=>spatialParticleAssetIds(system))];for(const assetId2 of new Set(referenced)){if(!assetIds.has(assetId2)){throw new SpatialSceneError("invalid-data",`Effects input references asset ${assetId2} absent from the scene manifest.`,"effects")}}for(const receipt of simulationBakes){if(receipt.sourceDigest!==sceneSha256){throw new SpatialSceneError("invalid-data",`Simulation bake ${receipt.cacheId} belongs to scene ${receipt.sourceDigest}, not ${sceneSha256}.`,"simulationBakes")}}const document=parseSpatialRenderEffectsDocument({kind:"slopcamera.spatial-render-effects",schemaVersion:1,sceneSha256,renderPlan,renderPlanSha256:spatialRenderPlanSha256(renderPlan),particleSystems:particleSystems.map((system)=>({system,systemSha256:spatialParticleSystemSha256(system)})),simulationBakes});return deepFreezeJson(SpatialRenderEffectsBindingSchema.parse({document,documentSha256:spatialRenderEffectsSha256(document)}))}import{z as z20}from"zod";var SPATIAL_TEMPORAL_AUDIT_LIMITS=Object.freeze({samples:256,contacts:64,cutBoundaries:64,findings:512});var SpatialTemporalContactSchema=z20.strictObject({entityId:SpatialEntityIdSchema,groundY:z20.number().finite().min(-1e6).max(1e6),startUs:SpatialTimeUsSchema,endUs:SpatialTimeUsSchema}).superRefine((contact,context)=>{if(contact.endUs<=contact.startUs){context.addIssue({code:"custom",path:["endUs"],message:"Contact windows must have positive duration."})}});var SpatialTemporalContactsFileSchema=z20.strictObject({contacts:z20.array(SpatialTemporalContactSchema).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.contacts)});var SpatialTemporalAuditOptionsSchema=z20.strictObject({contacts:z20.array(SpatialTemporalContactSchema).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.contacts).default([]),cutBeforeUs:z20.array(SpatialTimeUsSchema).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.cutBoundaries).default([]),maxPositionJumpM:z20.number().finite().positive().max(1e6).default(5),maxFootSlideMps:z20.number().finite().positive().max(1000).default(0.05),maxCameraAccelerationMps2:z20.number().finite().positive().max(1e6).default(50),maxCameraJerkMps3:z20.number().finite().positive().max(1e9).default(400),maxAngularVelocityRadps:z20.number().finite().positive().max(1e5).default(4),maxExposureJumpEv:z20.number().finite().positive().max(64).default(1),maxFocusJumpM:z20.number().finite().positive().max(1e6).default(0.5),maxNewAssetsPerSample:z20.number().int().min(1).max(1024).default(8),maxEntityCountDelta:z20.number().int().min(1).max(1024).default(16)});var SpatialTemporalFindingKindSchema=z20.enum(["visibility-flicker","transform-discontinuity","foot-slide","camera-acceleration","camera-jerk","camera-angular-velocity","exposure-jump","focus-jump","resource-spike"]);var SpatialTemporalFindingSchema=z20.strictObject({kind:SpatialTemporalFindingKindSchema,sampleIndex:z20.number().int().min(0).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.samples-1),timeUs:SpatialTimeUsSchema,entityId:SpatialEntityIdSchema.optional(),cameraId:SpatialCameraIdSchema.optional(),measured:z20.number().finite(),limit:z20.number().finite(),detail:z20.string().min(1).max(240)});var SpatialTemporalAuditReportSchema=z20.strictObject({kind:z20.literal("slopcamera.spatial-temporal-audit-report"),schemaVersion:z20.literal(1),sceneSha256:SpatialDigestSchema,cameraId:SpatialCameraIdSchema,sampleCount:z20.number().int().min(2).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.samples),firstTimeUs:SpatialTimeUsSchema,lastTimeUs:SpatialTimeUsSchema,findings:z20.array(SpatialTemporalFindingSchema).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.findings),omittedFindings:z20.number().int().min(0),thresholds:SpatialTemporalAuditOptionsSchema.omit({contacts:true,cutBeforeUs:true}),contactCount:z20.number().int().min(0).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.contacts)});function spatialTemporalAuditReportSha256(report){return spatialValueSha256(report)}var auditInputSchema2=z20.strictObject({snapshots:z20.array(z20.unknown()).min(2).max(SPATIAL_TEMPORAL_AUDIT_LIMITS.samples),options:z20.unknown().optional()});var KIND_ORDER={"visibility-flicker":0,"transform-discontinuity":1,"foot-slide":2,"camera-acceleration":3,"camera-jerk":4,"camera-angular-velocity":5,"exposure-jump":6,"focus-jump":7,"resource-spike":8};var translation=(snapshot,entityId)=>{const evaluated=snapshot.entities.find((item)=>item.entity.entityId===entityId);if(evaluated===undefined)return;return[evaluated.worldMatrix[12],evaluated.worldMatrix[13],evaluated.worldMatrix[14]]};var distance=(a,b)=>Math.hypot(a[0]-b[0],a[1]-b[1],a[2]-b[2]);var horizontalDistance=(a,b)=>Math.hypot(a[0]-b[0],a[2]-b[2]);var seconds=(later,earlier)=>(later.timeUs-earlier.timeUs)/1e6;function quaternionAngleRadians(a,b){const dot=Math.min(1,Math.max(-1,Math.abs(a.reduce((sum,value,index2)=>sum+value*b[index2],0))));return 2*Math.acos(dot)}function auditSpatialTemporalEvidence(input){const value=parseSpatialValue(auditInputSchema2,input,"temporal audit");const snapshots=value.snapshots.map((snapshot)=>parseSpatialValue(EvaluatedSpatialSceneSchema,snapshot,"snapshot"));const options=parseSpatialValue(SpatialTemporalAuditOptionsSchema,value.options??{},"temporal audit options");const sceneSha256=snapshots[0].sceneSha256;const cameraId=snapshots[0].camera.cameraId;for(const[index2,snapshot]of snapshots.entries()){if(snapshot.sceneSha256!==sceneSha256){throw new SpatialSceneError("invalid-data",`Snapshot ${index2} belongs to a different scene digest.`,"snapshots")}if(snapshot.camera.cameraId!==cameraId){throw new SpatialSceneError("invalid-data",`Snapshot ${index2} uses a different camera.`,"snapshots")}if(index2>0&&snapshot.timeUs<=snapshots[index2-1].timeUs){throw new SpatialSceneError("invalid-data","Snapshots must be strictly increasing in time.","snapshots")}}const findings=[];const cutTimes=new Set(options.cutBeforeUs);const isCutBoundary=(snapshot)=>cutTimes.has(snapshot.timeUs);const add=(finding)=>{if(findings.length<SPATIAL_TEMPORAL_AUDIT_LIMITS.findings)findings.push(finding)};const entityIds=[...new Set(snapshots.flatMap((snapshot)=>snapshot.entities.map((item)=>item.entity.entityId)))].sort();for(const entityId of entityIds){const states=snapshots.map((snapshot)=>snapshot.entities.find((item)=>item.entity.entityId===entityId)?.visible);let flips=0;let firstFlipIndex=-1;for(let index2=1;index2<states.length;index2+=1){if(states[index2]!==undefined&&states[index2-1]!==undefined&&states[index2]!==states[index2-1]){flips+=1;if(firstFlipIndex===-1)firstFlipIndex=index2}}if(flips>=2){add({kind:"visibility-flicker",sampleIndex:firstFlipIndex,timeUs:snapshots[firstFlipIndex].timeUs,entityId,measured:flips,limit:1,detail:`Entity ${entityId} toggles visibility ${flips} times across the sampled run.`})}}for(const entityId of entityIds){for(let index2=1;index2<snapshots.length;index2+=1){const previous=translation(snapshots[index2-1],entityId);const current=translation(snapshots[index2],entityId);if(previous===undefined||current===undefined)continue;if(!isCutBoundary(snapshots[index2])){const jump=distance(previous,current);if(jump>options.maxPositionJumpM){add({kind:"transform-discontinuity",sampleIndex:index2,timeUs:snapshots[index2].timeUs,entityId,measured:jump,limit:options.maxPositionJumpM,detail:`Entity ${entityId} teleports ${jump.toFixed(3)}m between samples ${index2-1} and ${index2} outside a declared cut.`})}}const dt=seconds(snapshots[index2],snapshots[index2-1]);if(dt<=0)continue;for(const contact of options.contacts){if(contact.entityId!==entityId)continue;const inWindow=snapshots[index2-1].timeUs>=contact.startUs&&snapshots[index2].timeUs<=contact.endUs;if(!inWindow)continue;const slideMps=horizontalDistance(previous,current)/dt;if(slideMps>options.maxFootSlideMps){add({kind:"foot-slide",sampleIndex:index2,timeUs:snapshots[index2].timeUs,entityId,measured:slideMps,limit:options.maxFootSlideMps,detail:`Entity ${entityId} slides ${slideMps.toFixed(3)}m/s horizontally while planted near groundY ${contact.groundY} during [${contact.startUs}, ${contact.endUs}]us.`})}}}}for(let index2=1;index2<snapshots.length;index2+=1){const current=snapshots[index2];const previous=snapshots[index2-1];const dt=seconds(current,previous);if(dt>0){const angular=quaternionAngleRadians(current.camera.pose.rotation,previous.camera.pose.rotation)/dt;if(angular>options.maxAngularVelocityRadps){add({kind:"camera-angular-velocity",sampleIndex:index2,timeUs:current.timeUs,cameraId,measured:angular,limit:options.maxAngularVelocityRadps,detail:`Camera rotates at ${angular.toFixed(3)}rad/s between samples ${index2-1} and ${index2}.`})}const focusNow=current.camera.lens?.focusDistanceM;const focusBefore=previous.camera.lens?.focusDistanceM;if(focusNow!==undefined&&focusBefore!==undefined&&Math.abs(focusNow-focusBefore)>options.maxFocusJumpM){add({kind:"focus-jump",sampleIndex:index2,timeUs:current.timeUs,cameraId,measured:Math.abs(focusNow-focusBefore),limit:options.maxFocusJumpM,detail:`Focus distance jumps ${Math.abs(focusNow-focusBefore).toFixed(3)}m between samples ${index2-1} and ${index2}.`})}const evNow=current.camera.lens?.exposureEv;const evBefore=previous.camera.lens?.exposureEv;if(evNow!==undefined&&evBefore!==undefined&&Math.abs(evNow-evBefore)>options.maxExposureJumpEv){add({kind:"exposure-jump",sampleIndex:index2,timeUs:current.timeUs,cameraId,measured:Math.abs(evNow-evBefore),limit:options.maxExposureJumpEv,detail:`Exposure jumps ${Math.abs(evNow-evBefore).toFixed(3)}EV between samples ${index2-1} and ${index2}.`})}}if(index2>=2){const a=snapshots[index2-2],b=snapshots[index2-1];const dt0=seconds(b,a),dt1=seconds(current,b);if(dt0>0&&dt1>0){const acceleration=Math.hypot(...[0,1,2].map((axis2)=>(current.camera.pose.position[axis2]-b.camera.pose.position[axis2])/dt1-(b.camera.pose.position[axis2]-a.camera.pose.position[axis2])/dt0))/((dt0+dt1)/2);if(acceleration>options.maxCameraAccelerationMps2){add({kind:"camera-acceleration",sampleIndex:index2,timeUs:current.timeUs,cameraId,measured:acceleration,limit:options.maxCameraAccelerationMps2,detail:`Camera accelerates at ${acceleration.toFixed(3)}m/s\xB2 at sample ${index2}.`})}}}if(index2>=3){const a=snapshots[index2-3],b=snapshots[index2-2],c=snapshots[index2-1];const dta=seconds(b,a),dtb=seconds(c,b),dtc=seconds(current,c);if(dta>0&&dtb>0&&dtc>0){const accel=(p1,p0,q1,q0,d1,d0)=>[0,1,2].map((axis2)=>((p1.camera.pose.position[axis2]-p0.camera.pose.position[axis2])/d1-(q1.camera.pose.position[axis2]-q0.camera.pose.position[axis2])/d0)/((d0+d1)/2));const a0=accel(c,b,b,a,dtb,dta);const a1=accel(current,c,c,b,dtc,dtb);const jerk=Math.hypot(a1[0]-a0[0],a1[1]-a0[1],a1[2]-a0[2])/((dtb+dtc)/2);if(jerk>options.maxCameraJerkMps3){add({kind:"camera-jerk",sampleIndex:index2,timeUs:current.timeUs,cameraId,measured:jerk,limit:options.maxCameraJerkMps3,detail:`Camera jerk reaches ${jerk.toFixed(3)}m/s\xB3 at sample ${index2}.`})}}}}for(let index2=1;index2<snapshots.length;index2+=1){const previous=snapshots[index2-1];const current=snapshots[index2];const previousAssets=new Set(previous.assets.map((asset)=>asset.assetId));const newAssets=current.assets.filter((asset)=>!previousAssets.has(asset.assetId)).length;if(newAssets>options.maxNewAssetsPerSample){add({kind:"resource-spike",sampleIndex:index2,timeUs:current.timeUs,measured:newAssets,limit:options.maxNewAssetsPerSample,detail:`${newAssets} assets enter the scene between samples ${index2-1} and ${index2}.`})}const entityDelta=Math.abs(current.entities.length-previous.entities.length);if(entityDelta>options.maxEntityCountDelta){add({kind:"resource-spike",sampleIndex:index2,timeUs:current.timeUs,measured:entityDelta,limit:options.maxEntityCountDelta,detail:`Entity count changes by ${entityDelta} between samples ${index2-1} and ${index2}.`})}}const all=findings.slice();all.sort((a,b)=>a.sampleIndex-b.sampleIndex||KIND_ORDER[a.kind]-KIND_ORDER[b.kind]||(a.entityId??"").localeCompare(b.entityId??"")||(a.cameraId??"").localeCompare(b.cameraId??""));const returned=all.slice(0,SPATIAL_TEMPORAL_AUDIT_LIMITS.findings);const{contacts:_contacts,cutBeforeUs:_cutBeforeUs,...thresholds}=options;return deepFreezeJson(SpatialTemporalAuditReportSchema.parse({kind:"slopcamera.spatial-temporal-audit-report",schemaVersion:1,sceneSha256,cameraId,sampleCount:snapshots.length,firstTimeUs:snapshots[0].timeUs,lastTimeUs:snapshots[snapshots.length-1].timeUs,findings:returned,omittedFindings:all.length-returned.length,thresholds,contactCount:options.contacts.length}))}
3
- export{SpatialMapChannelSchema,SpatialMapColorSpaceSchema,SpatialUvTransformSchema,SpatialPbrMapSchema,SpatialPbrEmissiveSchema,SpatialPbrClearcoatSchema,SpatialPbrTransmissionSchema,SpatialPbrSheenSchema,SpatialPbrAnisotropySchema,SpatialPbrMaterialSchema,pbrMaterialMapAssetIds,SpatialDerivationMethodSchema,SpatialDerivationCandidateSchema,pbrDerivationCandidates,SpatialFogSchema,SpatialLightingRigTypeSchema,lightingRig,lightingRigDescription,SpatialProbeGeometrySchema,ORIGINAL_MATERIAL_HERO_FIXTURE,planMaterialProbeGallery,validatePbrMaterial,SPATIAL_SCENE_LIMITS,SpatialDigestSchema,SpatialSceneIdSchema,SpatialEntityIdSchema,SpatialCameraIdSchema,SpatialAssetIdSchema,SpatialGeneratorIdSchema,SpatialChannelIdSchema,SpatialShotIdSchema,SpatialTimeUsSchema,SpatialVec3Schema,SpatialQuaternionSchema,SpatialTransformSchema,SpatialPoseSchema,SpatialFrameRateSchema,SpatialProjectionSchema,SpatialCameraLensSchema,SpatialCameraSchema,SpatialPayloadSchema,SpatialAssetInterpretationSchema,SpatialAssetManifestSchema,SpatialEmissiveSchema,SpatialMaterialSchema,SpatialGeometrySchema,SpatialSpotLightSchema,SpatialOriginSchema,SpatialPlacementSchema,SpatialEntitySchema,SpatialAnimationSchema,SpatialOverrideSchema,SpatialGeneratorSchema,SpatialSceneV1Schema,SpatialPatchOperationSchema,SpatialScenePatchV1Schema,SpatialShotV1Schema,SpatialMatrixSchema,EvaluatedSpatialSceneSchema,SpatialSceneError,parseSpatialValue,spatialValueSha256,spatialStateValueSha256,sortSpatialBy,spatialTopologicalIds,generatedSpatialEntityId,spatialGeneratorOutputSha256,spatialAssetManifestSha256,spatialAssetClosureDigests,spatialPropertySupported,validateSpatialOverrides,parseSpatialScene,spatialSceneSha256,MAX_ABS_COMPONENT,MAX_IMAGE_DIMENSION,IDENTITY_MATRIX,normalizeQuaternion,composeTransform,multiplyTransforms,invertTransform,transformPoint,transformDirection,slerpQuaternion,prepareCameraView,projectPreparedPoint,projectPoint,unprojectPixel,pixelRay,transformBounds,cameraMathView,SPATIAL_GLB_PROFILE,SPATIAL_GLB_PROFILE_V1,SPATIAL_GLB_RIGGED_PROFILE,SPATIAL_GLB_LIMITS,SpatialGlbModel,parseSpatialGlb,evaluateSpatialGlb,spatialGlbBounds,SPATIAL_GEOMETRY_LIMITS,SPATIAL_GEOMETRY_GRAPH_KIND,SPATIAL_GEOMETRY_PROFILE,SpatialGeometryNodeSchema,SpatialGeometryGraphSchema,parseSpatialGeometryGraph,estimateSpatialGeometryGraph,evaluateSpatialGeometry,emitSpatialGeometryGlb,SpatialBoundsSchema,SpatialAssetMaterialFactSchema,SpatialAssetLodSchema,SpatialCollisionProxySchema,SpatialRetainedArtifactSchema,SpatialAssetGeneratorFactsSchema,SpatialAssetFactsV1Schema,SpatialPublishedArtifactSchema,SpatialAssetAdmissionV1Schema,mergeSpatialOverrides,applySpatialEntityOverride,validateSpatialShot,createSpatialEvaluationContext,evaluateSpatialSceneInContext,evaluateSpatialScene,SPATIAL_AUDIT_LIMITS,SpatialAuditBoundsSchema,SpatialAuditOptionsSchema,SpatialAuditFrustumSchema,SpatialAuditSampleSchema,SpatialAuditEntitySchema,SpatialAuditFindingSchema,SpatialAuditReportSchema,spatialEntityLocalBounds,spatialAuditDefaultTimesUs,auditSpatialScene,auditSpatialSceneInContext,normalizeSpatialAuditAssetBounds,SPATIAL_BEHAVIOR_LIMITS,SpatialBehaviorPortTypeSchema,SpatialBehaviorPortMapSchema,SpatialBehaviorCellSchema,SpatialBehaviorEdgeSchema,SpatialBehaviorOrganismSchema,SpatialBehaviorSchema,parseSpatialBehavior,spatialBehaviorSha256,behaviorOrganismCanonicalValue,behaviorOrganismSha256,SpatialBehaviorFindingCodeSchema,SpatialBehaviorCheckFindingSchema,SpatialBehaviorCheckReportSchema,checkSpatialBehavior,SPATIAL_BEHAVIOR_AUDIT_LIMITS,SpatialBehaviorAuditFindingKindSchema,SpatialBehaviorAuditFindingSchema,SpatialBehaviorAuditOptionsSchema,SpatialBehaviorAuditReportSchema,spatialBehaviorAuditReportSha256,auditSpatialBehaviorTrace,SPATIAL_BEHAVIOR_FN_LIMITS,SpatialBehaviorFnError,SPATIAL_BEHAVIOR_FNS,spatialBehaviorFnSignatures,reduceSpatialFrameRate,spatialFrameCount,spatialFrameSample,spatialOutputDuration,SPATIAL_CAMERA_TRACK_MAX_FRAMES,SpatialCameraTrackSchema,parseSpatialCameraTrack,sampleSpatialCameraTrack,SpatialCameraRigSchema,SpatialRackFocusSchema,compileSpatialCameraRig,SpatialFramingGoalSchema,solveSpatialFraming,auditSpatialCameraTrack,SPATIAL_DIRECTION_LIMITS,SpatialDramaticBeatSchema,SpatialCharacterActionSchema,SpatialCameraCoverageSchema,SpatialLookIntentSchema,SpatialDirectionSchema,parseSpatialDirection,spatialDirectionSha256,positiveDimension2 as positiveDimension,unit4 as unit,SPATIAL_EFFECT_LIMITS,SpatialRenderQualitySchema,SpatialBloomSchema,SpatialDepthOfFieldSchema,SpatialMotionBlurSchema,SpatialToneMapSchema,SpatialVignetteSchema,SpatialChromaticAberrationSchema,SpatialGrainSchema,SpatialFlareSchema,SpatialLutGradeSchema,SpatialPostProcessStepSchema,SpatialPostProcessStackSchema,SpatialRenderPlanSchema,parseSpatialRenderPlan,spatialRenderPlanAssetIds,spatialRenderPlanSha256,SPATIAL_DIRECTION_COMPILER_ID,SPATIAL_DIRECTION_COMPILATION_LIMITS,SpatialDirectionAdvisoryCodeSchema,SpatialDirectionAdvisorySchema,SpatialUnresolvedIntentDomainSchema,SpatialUnresolvedIntentSchema,SpatialPerformanceClipKindSchema,SpatialPerformanceProposalSchema,SpatialLookProposalSchema,SpatialDirectionProposalsSchema,SpatialDirectionCompilationSchema,SpatialDirectionCheckFindingSchema,SpatialDirectionCheckReportSchema,spatialDirectionCompilationSha256,compileSpatialDirection,checkSpatialDirection,SPATIAL_GALLERY_LIMITS,SpatialGalleryAxisSchema,SpatialGalleryCandidateSchema,SpatialGalleryPlanSchema,spatialGalleryPlanSha256,planSpatialDirectionGallery,inspectSpatialScene,diffSpatialScenes,applySpatialScenePatch,SPATIAL_PARTICLE_LIMITS,SpatialParticleEmitterShapeSchema,SpatialParticleForceSchema,SpatialParticleKillVolumeSchema,SpatialParticleCollisionVolumeSchema,SpatialParticleCurveSchema,SpatialParticleEmitterSchema,SpatialParticleRendererSchema,SpatialParticleSystemSchema,parseSpatialParticleSystem,spatialParticleAssetIds,spatialParticleSystemSha256,SPATIAL_SIMULATION_LIMITS,SpatialSimulationEngineSchema,SpatialRigidBodySchema,SpatialConstraintSchema,SpatialSimulationPlanSchema,SpatialSimulationBakeReceiptSchema,parseSpatialSimulationPlan,spatialSimulationPlanSha256,createSpatialSimulationBakeReceipt,parseSpatialSimulationBakeReceipt,reconcileSpatialSimulationBakeReceipt,SPATIAL_RENDER_EFFECTS_LIMITS,SpatialRenderEffectsDocumentSchema,SpatialRenderEffectsBindingSchema,parseSpatialRenderEffectsDocument,spatialRenderEffectsAssetIds,spatialRenderEffectsSha256,SPATIAL_EFFECTS_CHECK_LIMITS,SpatialEffectsCheckFindingSchema,SpatialEffectsCheckReportSchema,checkSpatialRenderEffects,planSpatialRenderEffects,SPATIAL_TEMPORAL_AUDIT_LIMITS,SpatialTemporalContactSchema,SpatialTemporalContactsFileSchema,SpatialTemporalAuditOptionsSchema,SpatialTemporalFindingKindSchema,SpatialTemporalFindingSchema,SpatialTemporalAuditReportSchema,spatialTemporalAuditReportSha256,auditSpatialTemporalEvidence};