Introduce ProjectScene and ProjectDocument interfaces with utility functions

This commit is contained in:
2026-04-11 03:46:30 +02:00
parent 2b3e5858f4
commit f1ab5f8282

View File

@@ -1,3 +1,4 @@
import { createOpaqueId } from "../core/ids";
import type { Brush } from "./brushes"; import type { Brush } from "./brushes";
import type { ModelInstance } from "../assets/model-instances"; import type { ModelInstance } from "../assets/model-instances";
import type { ProjectAssetRecord } from "../assets/project-assets"; import type { ProjectAssetRecord } from "../assets/project-assets";
@@ -6,7 +7,8 @@ import type { InteractionLink } from "../interactions/interaction-links";
import { cloneMaterialRegistry, createStarterMaterialRegistry, type MaterialDef } from "../materials/starter-material-library"; import { cloneMaterialRegistry, createStarterMaterialRegistry, type MaterialDef } from "../materials/starter-material-library";
import { createDefaultWorldSettings, type WorldSettings } from "./world-settings"; import { createDefaultWorldSettings, type WorldSettings } from "./world-settings";
export const SCENE_DOCUMENT_VERSION = 21 as const; export const SCENE_DOCUMENT_VERSION = 22 as const;
export const MULTI_SCENE_FOUNDATION_SCENE_DOCUMENT_VERSION = 22 as const;
export const WATER_SURFACE_DISPLACEMENT_SCENE_DOCUMENT_VERSION = 21 as const; export const WATER_SURFACE_DISPLACEMENT_SCENE_DOCUMENT_VERSION = 21 as const;
export const WHITEBOX_BOX_VOLUME_SCENE_DOCUMENT_VERSION = 20 as const; export const WHITEBOX_BOX_VOLUME_SCENE_DOCUMENT_VERSION = 20 as const;
export const WHITEBOX_GEOMETRY_SCENE_DOCUMENT_VERSION = 19 as const; export const WHITEBOX_GEOMETRY_SCENE_DOCUMENT_VERSION = 19 as const;
@@ -27,6 +29,27 @@ export const WORLD_ENVIRONMENT_SCENE_DOCUMENT_VERSION = 6 as const;
export const ENTITY_SYSTEM_FOUNDATION_SCENE_DOCUMENT_VERSION = 7 as const; export const ENTITY_SYSTEM_FOUNDATION_SCENE_DOCUMENT_VERSION = 7 as const;
export const TRIGGER_ACTION_TARGET_FOUNDATION_SCENE_DOCUMENT_VERSION = 8 as const; export const TRIGGER_ACTION_TARGET_FOUNDATION_SCENE_DOCUMENT_VERSION = 8 as const;
export const DEFAULT_PROJECT_SCENE_ID = "scene-main" as const;
export interface ProjectScene {
id: string;
name: string;
world: WorldSettings;
brushes: Record<string, Brush>;
modelInstances: Record<string, ModelInstance>;
entities: Record<string, EntityInstance>;
interactionLinks: Record<string, InteractionLink>;
}
export interface ProjectDocument {
version: typeof SCENE_DOCUMENT_VERSION;
activeSceneId: string;
scenes: Record<string, ProjectScene>;
materials: Record<string, MaterialDef>;
textures: Record<string, never>;
assets: Record<string, ProjectAssetRecord>;
}
export interface SceneDocument { export interface SceneDocument {
version: typeof SCENE_DOCUMENT_VERSION; version: typeof SCENE_DOCUMENT_VERSION;
name: string; name: string;
@@ -54,3 +77,131 @@ export function createEmptySceneDocument(overrides: Partial<Pick<SceneDocument,
interactionLinks: {} interactionLinks: {}
}; };
} }
export function createEmptyProjectScene(
overrides: Partial<Pick<ProjectScene, "id" | "name" | "world">> = {}
): ProjectScene {
return {
id: overrides.id ?? createOpaqueId("scene"),
name: overrides.name ?? "Untitled Scene",
world: overrides.world ?? createDefaultWorldSettings(),
brushes: {},
modelInstances: {},
entities: {},
interactionLinks: {}
};
}
export function createEmptyProjectDocument(
overrides: Partial<
Pick<ProjectDocument, "activeSceneId" | "materials" | "textures" | "assets">
> & {
sceneId?: string;
sceneName?: string;
world?: WorldSettings;
} = {}
): ProjectDocument {
const initialScene = createEmptyProjectScene({
id: overrides.sceneId ?? overrides.activeSceneId ?? DEFAULT_PROJECT_SCENE_ID,
name: overrides.sceneName,
world: overrides.world
});
return {
version: SCENE_DOCUMENT_VERSION,
activeSceneId: initialScene.id,
scenes: {
[initialScene.id]: initialScene
},
materials: cloneMaterialRegistry(
overrides.materials ?? createStarterMaterialRegistry()
),
textures: overrides.textures ?? {},
assets: overrides.assets ?? {}
};
}
export function getProjectScene(
projectDocument: ProjectDocument,
sceneId = projectDocument.activeSceneId
): ProjectScene {
const scene = projectDocument.scenes[sceneId];
if (scene === undefined) {
throw new Error(`Project scene ${sceneId} does not exist.`);
}
return scene;
}
export function createSceneDocumentFromProject(
projectDocument: ProjectDocument,
sceneId = projectDocument.activeSceneId
): SceneDocument {
const scene = getProjectScene(projectDocument, sceneId);
return {
version: projectDocument.version,
name: scene.name,
world: scene.world,
materials: projectDocument.materials,
textures: projectDocument.textures,
assets: projectDocument.assets,
brushes: scene.brushes,
modelInstances: scene.modelInstances,
entities: scene.entities,
interactionLinks: scene.interactionLinks
};
}
export function createProjectDocumentFromSceneDocument(
sceneDocument: SceneDocument,
sceneId = DEFAULT_PROJECT_SCENE_ID
): ProjectDocument {
return {
version: SCENE_DOCUMENT_VERSION,
activeSceneId: sceneId,
scenes: {
[sceneId]: {
id: sceneId,
name: sceneDocument.name,
world: sceneDocument.world,
brushes: sceneDocument.brushes,
modelInstances: sceneDocument.modelInstances,
entities: sceneDocument.entities,
interactionLinks: sceneDocument.interactionLinks
}
},
materials: sceneDocument.materials,
textures: sceneDocument.textures,
assets: sceneDocument.assets
};
}
export function applySceneDocumentToProject(
projectDocument: ProjectDocument,
sceneId: string,
sceneDocument: SceneDocument
): ProjectDocument {
const previousScene = getProjectScene(projectDocument, sceneId);
return {
...projectDocument,
version: SCENE_DOCUMENT_VERSION,
materials: sceneDocument.materials,
textures: sceneDocument.textures,
assets: sceneDocument.assets,
scenes: {
...projectDocument.scenes,
[sceneId]: {
...previousScene,
name: sceneDocument.name,
world: sceneDocument.world,
brushes: sceneDocument.brushes,
modelInstances: sceneDocument.modelInstances,
entities: sceneDocument.entities,
interactionLinks: sceneDocument.interactionLinks
}
}
};
}