diagnostics.push(createDiagnostic("error","invalid-world-background-color","Solid world backgrounds must use #RRGGBB colors.","world.background.colorHex"));
diagnostics.push(createDiagnostic("error","invalid-world-background-top-color","Gradient world backgrounds must use #RRGGBB colors for the top color.","world.background.topColorHex"));
diagnostics.push(createDiagnostic("error","invalid-world-background-bottom-color","Gradient world backgrounds must use #RRGGBB colors for the bottom color.","world.background.bottomColorHex"));
diagnostics.push(createDiagnostic("error","invalid-world-background-asset-id","World background images must reference a non-empty asset id.","world.background.assetId"));
diagnostics.push(createDiagnostic("error","missing-world-background-asset",`World background image asset ${world.background.assetId} does not exist.`,"world.background.assetId"));
}
elseif(backgroundAsset.kind!=="image"){
diagnostics.push(createDiagnostic("error","invalid-world-background-asset-kind","World background images must reference image assets.","world.background.assetId"));
diagnostics.push(createDiagnostic("error","invalid-world-background-environment-intensity","World background environment intensity must be a non-negative finite number.","world.background.environmentIntensity"));
diagnostics.push(createDiagnostic("error","invalid-world-ambient-color","World ambient light must use a #RRGGBB color.","world.ambientLight.colorHex"));
diagnostics.push(createDiagnostic("error","invalid-world-ambient-intensity","World ambient light intensity must remain finite and zero or greater.","world.ambientLight.intensity"));
}
if(!isHexColorString(world.sunLight.colorHex)){
diagnostics.push(createDiagnostic("error","invalid-world-sun-color","World sun color must use a #RRGGBB color.","world.sunLight.colorHex"));
diagnostics.push(createDiagnostic("error","invalid-world-sun-intensity","World sun intensity must remain finite and zero or greater.","world.sunLight.intensity"));
diagnostics.push(createDiagnostic("error","invalid-world-sun-direction","World sun direction must remain finite and must not be the zero vector.","world.sunLight.direction"));
}
constadvancedRendering=world.advancedRendering;
if(!isBoolean(advancedRendering.enabled)){
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-enabled","Advanced rendering enabled must be a boolean.","world.advancedRendering.enabled"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-shadows-enabled","Advanced rendering shadow enabled must be a boolean.","world.advancedRendering.shadows.enabled"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-shadow-map-size","Advanced rendering shadow map size must be one of 512, 1024, 2048, or 4096.","world.advancedRendering.shadows.mapSize"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-shadow-type","Advanced rendering shadow type must be basic, pcf, or pcfSoft.","world.advancedRendering.shadows.type"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-shadow-bias","Advanced rendering shadow bias must be a finite number.","world.advancedRendering.shadows.bias"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-ao-enabled","Advanced rendering ambient occlusion enabled must be a boolean.","world.advancedRendering.ambientOcclusion.enabled"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-ao-intensity","Advanced rendering ambient occlusion intensity must be a non-negative finite number.","world.advancedRendering.ambientOcclusion.intensity"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-ao-radius","Advanced rendering ambient occlusion radius must be a non-negative finite number.","world.advancedRendering.ambientOcclusion.radius"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-ao-samples","Advanced rendering ambient occlusion samples must be a positive integer.","world.advancedRendering.ambientOcclusion.samples"));
}
if(!isBoolean(advancedRendering.bloom.enabled)){
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-bloom-enabled","Advanced rendering bloom enabled must be a boolean.","world.advancedRendering.bloom.enabled"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-bloom-intensity","Advanced rendering bloom intensity must be a non-negative finite number.","world.advancedRendering.bloom.intensity"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-bloom-threshold","Advanced rendering bloom threshold must be a non-negative finite number.","world.advancedRendering.bloom.threshold"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-bloom-radius","Advanced rendering bloom radius must be a non-negative finite number.","world.advancedRendering.bloom.radius"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-tone-mapping-mode","Advanced rendering tone mapping mode must be none, linear, reinhard, cineon, or acesFilmic.","world.advancedRendering.toneMapping.mode"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-tone-mapping-exposure","Advanced rendering tone mapping exposure must be a positive finite number.","world.advancedRendering.toneMapping.exposure"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-dof-enabled","Advanced rendering depth of field enabled must be a boolean.","world.advancedRendering.depthOfField.enabled"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-dof-focus-distance","Advanced rendering depth of field focus distance must be a non-negative finite number.","world.advancedRendering.depthOfField.focusDistance"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-dof-focal-length","Advanced rendering depth of field focal length must be a positive finite number.","world.advancedRendering.depthOfField.focalLength"));
diagnostics.push(createDiagnostic("error","invalid-advanced-rendering-dof-bokeh-scale","Advanced rendering depth of field bokeh scale must be a positive finite number.","world.advancedRendering.depthOfField.bokehScale"));
diagnostics.push(createDiagnostic("error","invalid-point-light-position","Point Light position must remain finite on every axis.",`${path}.position`));
}
if(!isHexColorString(entity.colorHex)){
diagnostics.push(createDiagnostic("error","invalid-point-light-color","Point Light color must use a #RRGGBB color.",`${path}.colorHex`));
}
if(!isNonNegativeFiniteNumber(entity.intensity)){
diagnostics.push(createDiagnostic("error","invalid-point-light-intensity","Point Light intensity must remain finite and zero or greater.",`${path}.intensity`));
}
if(!isPositiveFiniteNumber(entity.distance)){
diagnostics.push(createDiagnostic("error","invalid-point-light-distance","Point Light distance must remain finite and greater than zero.",`${path}.distance`));
diagnostics.push(createDiagnostic("error","invalid-spot-light-direction","Spot Light direction must remain finite and must not be the zero vector.",`${path}.direction`));
}
if(!isHexColorString(entity.colorHex)){
diagnostics.push(createDiagnostic("error","invalid-spot-light-color","Spot Light color must use a #RRGGBB color.",`${path}.colorHex`));
}
if(!isNonNegativeFiniteNumber(entity.intensity)){
diagnostics.push(createDiagnostic("error","invalid-spot-light-intensity","Spot Light intensity must remain finite and zero or greater.",`${path}.intensity`));
}
if(!isPositiveFiniteNumber(entity.distance)){
diagnostics.push(createDiagnostic("error","invalid-spot-light-distance","Spot Light distance must remain finite and greater than zero.",`${path}.distance`));
diagnostics.push(createDiagnostic("error","invalid-spot-light-angle","Spot Light angle must remain a finite degree value between 0 and 180.",`${path}.angleDegrees`));
diagnostics.push(createDiagnostic("error","invalid-asset-bounding-box-min","Model asset bounding boxes must have finite minimum coordinates.",`${path}.min`));
}
if(!isFiniteVec3(boundingBox.max)){
diagnostics.push(createDiagnostic("error","invalid-asset-bounding-box-max","Model asset bounding boxes must have finite maximum coordinates.",`${path}.max`));
diagnostics.push(createDiagnostic("error","invalid-asset-bounding-box-size","Model asset bounding boxes must have finite, zero-or-greater size values.",`${path}.size`));
diagnostics.push(createDiagnostic("error","invalid-model-asset-scene-name","Model asset scene names must be non-empty when authored.",`${path}.sceneName`));
diagnostics.push(createDiagnostic("error","invalid-model-asset-node-count","Model asset node counts must be finite and zero or greater.",`${path}.nodeCount`));
diagnostics.push(createDiagnostic("error","invalid-model-asset-mesh-count","Model asset mesh counts must be finite and zero or greater.",`${path}.meshCount`));
diagnostics.push(createDiagnostic("error","invalid-model-asset-material-names","Model asset material names must be string arrays.",`${path}.materialNames`));
diagnostics.push(createDiagnostic("error","invalid-model-asset-texture-names","Model asset texture names must be string arrays.",`${path}.textureNames`));
diagnostics.push(createDiagnostic("error","invalid-model-asset-animation-names","Model asset animation names must be string arrays.",`${path}.animationNames`));
diagnostics.push(createDiagnostic("error","invalid-audio-asset-duration","Audio asset durations must be finite and zero or greater when authored.",`${path}.durationSeconds`));
diagnostics.push(createDiagnostic("error","invalid-audio-asset-channel-count","Audio asset channel counts must be finite and greater than zero when authored.",`${path}.channelCount`));
diagnostics.push(createDiagnostic("error","invalid-audio-asset-sample-rate","Audio asset sample rates must be finite and greater than zero when authored.",`${path}.sampleRateHz`));
diagnostics.push(createDiagnostic("error","invalid-asset-source-name","Asset source names must be non-empty strings.",`${path}.sourceName`));
}
if(asset.mimeType.trim().length===0){
diagnostics.push(createDiagnostic("error","invalid-asset-mime-type","Asset mime types must be non-empty strings.",`${path}.mimeType`));
}
if(asset.storageKey.trim().length===0){
diagnostics.push(createDiagnostic("error","invalid-asset-storage-key","Asset storage keys must be non-empty strings.",`${path}.storageKey`));
}
if(!isPositiveFiniteNumber(asset.byteLength)){
diagnostics.push(createDiagnostic("error","invalid-asset-byte-length","Asset byte lengths must be finite and greater than zero.",`${path}.byteLength`));
diagnostics.push(createDiagnostic("error","invalid-model-instance-name","Model instance names must be non-empty when authored.",`${path}.name`));
}
if(!isFiniteVec3(modelInstance.position)){
diagnostics.push(createDiagnostic("error","invalid-model-instance-position","Model instance positions must remain finite on every axis.",`${path}.position`));
}
if(!isFiniteVec3(modelInstance.rotationDegrees)){
diagnostics.push(createDiagnostic("error","invalid-model-instance-rotation","Model instance rotations must remain finite on every axis.",`${path}.rotationDegrees`));
}
if(!hasPositiveFiniteVec3(modelInstance.scale)){
diagnostics.push(createDiagnostic("error","invalid-model-instance-scale","Model instance scales must remain finite and positive on every axis.",`${path}.scale`));
diagnostics.push(createDiagnostic("error","invalid-model-instance-collision-mode","Model instance collision mode must be one of none, terrain, static, dynamic, or simple.",`${path}.collision.mode`));
}
if(!isBoolean(modelInstance.collision.visible)){
diagnostics.push(createDiagnostic("error","invalid-model-instance-collision-visibility","Model instance collision visibility must be a boolean.",`${path}.collision.visible`));
diagnostics.push(createDiagnostic("error","missing-model-instance-asset",`Model instance asset ${modelInstance.assetId} does not exist.`,`${path}.assetId`));
return;
}
if(asset.kind!=="model"){
diagnostics.push(createDiagnostic("error","invalid-model-instance-asset-kind","Model instances may only reference model assets.",`${path}.assetId`));
diagnostics.push(createDiagnostic("error","invalid-player-start-position","Player Start position must remain finite on every axis.",`${path}.position`));
}
if(!isFiniteNumber(entity.yawDegrees)){
diagnostics.push(createDiagnostic("error","invalid-player-start-yaw","Player Start yaw must remain a finite number.",`${path}.yawDegrees`));
diagnostics.push(createDiagnostic("error","invalid-player-start-collider-mode","Player Start collider mode must be capsule, box, or none.",`${path}.collider.mode`));
diagnostics.push(createDiagnostic("error","invalid-player-start-eye-height","Player Start eye height must remain a finite number greater than zero.",`${path}.collider.eyeHeight`));
diagnostics.push(createDiagnostic("error","invalid-player-start-capsule-radius","Player Start capsule radius must remain a finite number greater than zero.",`${path}.collider.capsuleRadius`));
diagnostics.push(createDiagnostic("error","invalid-player-start-capsule-height","Player Start capsule height must remain a finite number greater than zero.",`${path}.collider.capsuleHeight`));
}
if(!isFiniteVec3(entity.collider.boxSize)||
entity.collider.boxSize.x<=0||
entity.collider.boxSize.y<=0||
entity.collider.boxSize.z<=0){
diagnostics.push(createDiagnostic("error","invalid-player-start-box-size","Player Start box size must remain finite and positive on every axis.",`${path}.collider.boxSize`));
diagnostics.push(createDiagnostic("error","invalid-player-start-capsule-proportions","Player Start capsule height must be at least twice the capsule radius.",`${path}.collider.capsuleHeight`));
diagnostics.push(createDiagnostic("error","invalid-player-start-eye-height","Player Start eye height must fit within the authored collider height.",`${path}.collider.eyeHeight`));
?"Sound Emitter autoplay requires an assigned audio asset."
:"Sound Emitter has no audio asset assigned yet.",`${path}.audioAssetId`));
returnnull;
}
constasset=document.assets[entity.audioAssetId];
if(asset===undefined){
diagnostics.push(createDiagnostic("error","missing-sound-emitter-audio-asset",`Sound Emitter audio asset ${entity.audioAssetId} does not exist.`,`${path}.audioAssetId`));
returnnull;
}
if(asset.kind!=="audio"){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-audio-asset-kind","Sound Emitter audioAssetId must reference an audio asset.",`${path}.audioAssetId`));
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-position","Sound Emitter position must remain finite on every axis.",`${path}.position`));
}
if(!isNonNegativeFiniteNumber(entity.volume)){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-volume","Sound Emitter volume must remain finite and zero or greater.",`${path}.volume`));
}
if(!isPositiveFiniteNumber(entity.refDistance)){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-ref-distance","Sound Emitter ref distance must remain finite and greater than zero.",`${path}.refDistance`));
}
if(!isPositiveFiniteNumber(entity.maxDistance)){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-max-distance","Sound Emitter max distance must remain finite and greater than zero.",`${path}.maxDistance`));
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-distance-order","Sound Emitter max distance must be greater than or equal to ref distance.",`${path}.maxDistance`));
}
if(!isBoolean(entity.autoplay)){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-autoplay","Sound Emitter autoplay must remain a boolean.",`${path}.autoplay`));
}
if(!isBoolean(entity.loop)){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-loop","Sound Emitter loop must remain a boolean.",`${path}.loop`));
diagnostics.push(createDiagnostic("error","invalid-trigger-volume-position","Trigger Volume position must remain finite on every axis.",`${path}.position`));
}
if(!hasPositiveFiniteVec3(entity.size)){
diagnostics.push(createDiagnostic("error","invalid-trigger-volume-size","Trigger Volume size must remain finite and positive on every axis.",`${path}.size`));
}
if(!isBoolean(entity.triggerOnEnter)){
diagnostics.push(createDiagnostic("error","invalid-trigger-volume-enter-flag","Trigger Volume triggerOnEnter must remain a boolean.",`${path}.triggerOnEnter`));
}
if(!isBoolean(entity.triggerOnExit)){
diagnostics.push(createDiagnostic("error","invalid-trigger-volume-exit-flag","Trigger Volume triggerOnExit must remain a boolean.",`${path}.triggerOnExit`));
diagnostics.push(createDiagnostic("error","invalid-teleport-target-position","Teleport Target position must remain finite on every axis.",`${path}.position`));
}
if(!isFiniteNumber(entity.yawDegrees)){
diagnostics.push(createDiagnostic("error","invalid-teleport-target-yaw","Teleport Target yaw must remain a finite number.",`${path}.yawDegrees`));
diagnostics.push(createDiagnostic("error","invalid-interactable-position","Interactable position must remain finite on every axis.",`${path}.position`));
}
if(!isPositiveFiniteNumber(entity.radius)){
diagnostics.push(createDiagnostic("error","invalid-interactable-radius","Interactable radius must remain finite and greater than zero.",`${path}.radius`));
diagnostics.push(createDiagnostic("error","missing-interaction-source-entity",`Interaction source entity ${link.sourceEntityId} does not exist.`,`${path}.sourceEntityId`));
diagnostics.push(createDiagnostic("error","invalid-interaction-source-kind","Interaction links may only source from Trigger Volume or Interactable entities in the current slice.",`${path}.sourceEntityId`));
diagnostics.push(createDiagnostic("error","unsupported-interaction-trigger","Trigger Volume links may only use enter or exit triggers.",`${path}.trigger`));
}
}
elseif(sourceEntity.kind==="interactable"){
if(link.trigger!=="click"){
diagnostics.push(createDiagnostic("error","unsupported-interaction-trigger","Interactable links may only use the click trigger.",`${path}.trigger`));
diagnostics.push(createDiagnostic("error","missing-teleport-target-entity",`Teleport target entity ${link.action.targetEntityId} does not exist.`,`${path}.action.targetEntityId`));
return;
}
if(targetEntity.kind!=="teleportTarget"){
diagnostics.push(createDiagnostic("error","invalid-teleport-target-kind","Teleport player actions must target a Teleport Target entity.",`${path}.action.targetEntityId`));
diagnostics.push(createDiagnostic("error","missing-visibility-target-brush",`Visibility target brush ${link.action.targetBrushId} does not exist.`,`${path}.action.targetBrushId`));
diagnostics.push(createDiagnostic("error","invalid-visibility-action-visible","Visibility actions must use a boolean visible value when authored.",`${path}.action.visible`));
diagnostics.push(createDiagnostic("error","missing-play-animation-target-instance",`Play animation target model instance ${link.action.targetModelInstanceId} does not exist.`,`${path}.action.targetModelInstanceId`));
return;
}
if(link.action.clipName.trim().length===0){
diagnostics.push(createDiagnostic("error","invalid-play-animation-clip-name","Play animation clip name must be non-empty.",`${path}.action.clipName`));
diagnostics.push(createDiagnostic("error","missing-play-animation-clip",`Play animation clip ${link.action.clipName} does not exist on model asset ${targetAsset.id}.`,`${path}.action.clipName`));
}
break;
}
case"stopAnimation":
// Validate that the target model instance exists in the document
diagnostics.push(createDiagnostic("error","missing-stop-animation-target-instance",`Stop animation target model instance ${link.action.targetModelInstanceId} does not exist.`,`${path}.action.targetModelInstanceId`));
diagnostics.push(createDiagnostic("error","missing-sound-emitter-entity",`Sound emitter entity ${link.action.targetSoundEmitterId} does not exist.`,`${path}.action.targetSoundEmitterId`));
break;
}
if(targetEntity.kind!=="soundEmitter"){
diagnostics.push(createDiagnostic("error","invalid-sound-emitter-kind","Sound playback actions must target a Sound Emitter entity.",`${path}.action.targetSoundEmitterId`));
break;
}
if(targetEntity.audioAssetId===null){
diagnostics.push(createDiagnostic("error","missing-sound-emitter-audio-asset","Sound playback actions require a Sound Emitter that references an audio asset.",`${path}.action.targetSoundEmitterId`));
diagnostics.push(createDiagnostic("error","invalid-box-geometry-vertex","Box brush geometry vertices must remain finite on every axis.",`${path}.geometry.vertices.${vertexId}`));
diagnostics.push(createDiagnostic("error","missing-material-ref",`Face material reference ${materialId} does not exist in the document material registry.`,`${path}.faces.${faceId}.materialId`));