Add path-related commands and update selection handling

This commit is contained in:
2026-04-13 21:21:40 +02:00
parent 0eac096de5
commit 3f4e951f41
11 changed files with 778 additions and 2 deletions

View File

@@ -48,6 +48,10 @@ import {
HOURS_PER_DAY,
type ProjectTimeSettings
} from "./project-time-settings";
import {
MIN_SCENE_PATH_POINT_COUNT,
type ScenePath
} from "./paths";
import {
isAdvancedRenderingWaterReflectionMode,
isAdvancedRenderingShadowMapSize,
@@ -1513,6 +1517,102 @@ function validateEntityName(
}
}
function validateScenePath(pathValue: ScenePath, path: string, diagnostics: SceneDiagnostic[]) {
if (!isBoolean(pathValue.visible)) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-visible",
"Path visible must remain a boolean.",
`${path}.visible`
)
);
}
if (!isBoolean(pathValue.enabled)) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-enabled",
"Path enabled must remain a boolean.",
`${path}.enabled`
)
);
}
if (pathValue.name !== undefined && pathValue.name.trim().length === 0) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-name",
"Path names must be non-empty when authored.",
`${path}.name`
)
);
}
if (!isBoolean(pathValue.loop)) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-loop",
"Path loop must remain a boolean.",
`${path}.loop`
)
);
}
if (pathValue.points.length < MIN_SCENE_PATH_POINT_COUNT) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-point-count",
`Paths must define at least ${MIN_SCENE_PATH_POINT_COUNT} points.`,
`${path}.points`
)
);
}
const seenPointIds = new Set<string>();
for (const [pointIndex, point] of pathValue.points.entries()) {
const pointPath = `${path}.points.${pointIndex}`;
if (point.id.trim().length === 0) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-point-id",
"Path point ids must be non-empty strings.",
`${pointPath}.id`
)
);
} else if (seenPointIds.has(point.id)) {
diagnostics.push(
createDiagnostic(
"error",
"duplicate-path-point-id",
`Path point id ${point.id} is already used within this path.`,
`${pointPath}.id`
)
);
} else {
seenPointIds.add(point.id);
}
if (!isFiniteVec3(point.position)) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-path-point-position",
"Path point positions must remain finite on every axis.",
`${pointPath}.position`
)
);
}
}
}
function validateAuthoredEntityState(
entity: EntityInstance,
path: string,
@@ -3454,6 +3554,26 @@ export function validateSceneDocument(
}
}
for (const [modelInstanceKey, modelInstance] of Object.entries(
document.paths
)) {
const path = `paths.${modelInstanceKey}`;
if (modelInstance.id !== modelInstanceKey) {
diagnostics.push(
createDiagnostic(
"error",
"path-id-mismatch",
"Path ids must match their registry key.",
`${path}.id`
)
);
}
registerAuthoredId(modelInstance.id, path, seenIds, diagnostics);
validateScenePath(modelInstance, path, diagnostics);
}
for (const [modelInstanceKey, modelInstance] of Object.entries(
document.modelInstances
)) {