@skenora/editor 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +51 -0
  2. package/dist/commands/annotation-commands.d.ts +12 -0
  3. package/dist/commands/annotation-commands.d.ts.map +1 -0
  4. package/dist/commands/annotation-commands.js +37 -0
  5. package/dist/commands/annotation-commands.js.map +1 -0
  6. package/dist/commands/camera-entity-commands.d.ts +12 -0
  7. package/dist/commands/camera-entity-commands.d.ts.map +1 -0
  8. package/dist/commands/camera-entity-commands.js +60 -0
  9. package/dist/commands/camera-entity-commands.js.map +1 -0
  10. package/dist/commands/camera-path-commands.d.ts +9 -0
  11. package/dist/commands/camera-path-commands.d.ts.map +1 -0
  12. package/dist/commands/camera-path-commands.js +95 -0
  13. package/dist/commands/camera-path-commands.js.map +1 -0
  14. package/dist/commands/flow-commands.d.ts +10 -0
  15. package/dist/commands/flow-commands.d.ts.map +1 -0
  16. package/dist/commands/flow-commands.js +86 -0
  17. package/dist/commands/flow-commands.js.map +1 -0
  18. package/dist/commands/geometry-commands.d.ts +8 -0
  19. package/dist/commands/geometry-commands.d.ts.map +1 -0
  20. package/dist/commands/geometry-commands.js +85 -0
  21. package/dist/commands/geometry-commands.js.map +1 -0
  22. package/dist/commands/material-assignment.d.ts +7 -0
  23. package/dist/commands/material-assignment.d.ts.map +1 -0
  24. package/dist/commands/material-assignment.js +69 -0
  25. package/dist/commands/material-assignment.js.map +1 -0
  26. package/dist/commands/material-commands.d.ts +13 -0
  27. package/dist/commands/material-commands.d.ts.map +1 -0
  28. package/dist/commands/material-commands.js +182 -0
  29. package/dist/commands/material-commands.js.map +1 -0
  30. package/dist/commands/model-import-commands.d.ts +6 -0
  31. package/dist/commands/model-import-commands.d.ts.map +1 -0
  32. package/dist/commands/model-import-commands.js +120 -0
  33. package/dist/commands/model-import-commands.js.map +1 -0
  34. package/dist/commands/particle-commands.d.ts +13 -0
  35. package/dist/commands/particle-commands.d.ts.map +1 -0
  36. package/dist/commands/particle-commands.js +47 -0
  37. package/dist/commands/particle-commands.js.map +1 -0
  38. package/dist/commands/primitive-commands.d.ts +18 -0
  39. package/dist/commands/primitive-commands.d.ts.map +1 -0
  40. package/dist/commands/primitive-commands.js +24 -0
  41. package/dist/commands/primitive-commands.js.map +1 -0
  42. package/dist/commands/procedural-commands.d.ts +13 -0
  43. package/dist/commands/procedural-commands.d.ts.map +1 -0
  44. package/dist/commands/procedural-commands.js +20 -0
  45. package/dist/commands/procedural-commands.js.map +1 -0
  46. package/dist/commands/scene-commands.d.ts +16 -0
  47. package/dist/commands/scene-commands.d.ts.map +1 -0
  48. package/dist/commands/scene-commands.js +146 -0
  49. package/dist/commands/scene-commands.js.map +1 -0
  50. package/dist/commands/shape-commands.d.ts +24 -0
  51. package/dist/commands/shape-commands.d.ts.map +1 -0
  52. package/dist/commands/shape-commands.js +95 -0
  53. package/dist/commands/shape-commands.js.map +1 -0
  54. package/dist/commands/texture-animation-commands.d.ts +5 -0
  55. package/dist/commands/texture-animation-commands.d.ts.map +1 -0
  56. package/dist/commands/texture-animation-commands.js +23 -0
  57. package/dist/commands/texture-animation-commands.js.map +1 -0
  58. package/dist/core/candidate-commit.d.ts +59 -0
  59. package/dist/core/candidate-commit.d.ts.map +1 -0
  60. package/dist/core/candidate-commit.js +54 -0
  61. package/dist/core/candidate-commit.js.map +1 -0
  62. package/dist/core/commands.d.ts +20 -0
  63. package/dist/core/commands.d.ts.map +1 -0
  64. package/dist/core/commands.js +282 -0
  65. package/dist/core/commands.js.map +1 -0
  66. package/dist/core/editor-session.d.ts +92 -0
  67. package/dist/core/editor-session.d.ts.map +1 -0
  68. package/dist/core/editor-session.js +496 -0
  69. package/dist/core/editor-session.js.map +1 -0
  70. package/dist/index.d.ts +18 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +18 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/properties/property-descriptors.d.ts +58 -0
  75. package/dist/properties/property-descriptors.d.ts.map +1 -0
  76. package/dist/properties/property-descriptors.js +832 -0
  77. package/dist/properties/property-descriptors.js.map +1 -0
  78. package/package.json +34 -0
package/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @skenora/editor
2
+
3
+ Headless SceneDocument authoring for Skenora.
4
+
5
+ > This package is not currently published to npm; the install command below is
6
+ > intended release syntax. The procedural V1 sections describe current
7
+ > repository source and are not covered by the 2026-08-28 package/browser
8
+ > evidence.
9
+
10
+ ```bash
11
+ pnpm add @skenora/editor
12
+ ```
13
+
14
+ The package provides `EditorSession`, public `EditorCommand` factories,
15
+ transactions, history, undo/redo, selection, and editable property
16
+ descriptors. It has no DOM and does not project documents into Babylon.js.
17
+
18
+ Session lifecycle additions use `EditorPlugin` and the dependency-free
19
+ `@skenora/plugins` host. `EditorExtension` remains as a compatibility alias.
20
+ Plugins may register event listeners or other owned effects, and all effects
21
+ are released when the plugin or session is disposed.
22
+
23
+ ```ts
24
+ import { EditorSession, setEnvironmentCommand } from "@skenora/editor";
25
+
26
+ const editor = new EditorSession(document);
27
+ editor.execute(setEnvironmentCommand(nextEnvironment));
28
+ ```
29
+
30
+ Create programmatic geometry through the same undoable command boundary:
31
+
32
+ ```ts
33
+ import { createProceduralEntityCommand } from "@skenora/editor";
34
+
35
+ editor.execute(
36
+ createProceduralEntityCommand({
37
+ id: "generated-stage",
38
+ program: geometryProgram,
39
+ }),
40
+ );
41
+ ```
42
+
43
+ The command stores a validated `skenora.geometry.program@1` in the document;
44
+ Runtime owns generated mesh data and GPU projection. Owned material programs
45
+ continue to use the existing material commands and explicit bindings.
46
+
47
+ Persistent scene changes should pass through commands. Use `@skenora/sdk` for
48
+ the ready-made workspace + editor + runtime composition.
49
+
50
+ See the [repository](https://github.com/zhangjiadi225/skenora); the current
51
+ working-tree guides are `docs/EDITOR.md` and `docs/PROCEDURAL_AI.md`.
@@ -0,0 +1,12 @@
1
+ import { type AnnotationEntityProperties, type TransformValue } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export interface AnnotationOptions {
4
+ id: string;
5
+ text: string;
6
+ name?: string;
7
+ parentId?: string | null;
8
+ transform?: TransformValue;
9
+ properties?: Partial<AnnotationEntityProperties>;
10
+ }
11
+ export declare function createAnnotationCommand(options: AnnotationOptions): EditorCommand;
12
+ //# sourceMappingURL=annotation-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-commands.d.ts","sourceRoot":"","sources":["../../src/commands/annotation-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAE/B,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAClD;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,GACzB,aAAa,CAiCf"}
@@ -0,0 +1,37 @@
1
+ import { createIdentityTransform, } from "@skenora/contracts";
2
+ import { addEntityCommand } from "../core/commands.js";
3
+ export function createAnnotationCommand(options) {
4
+ const properties = {
5
+ text: options.text,
6
+ color: options.properties?.color ?? "#ffffff",
7
+ offset: options.properties?.offset ?? { x: 0, y: 0, z: 0 },
8
+ priority: options.properties?.priority ?? 0,
9
+ ...(options.properties?.minDistance === undefined
10
+ ? {}
11
+ : { minDistance: options.properties.minDistance }),
12
+ ...(options.properties?.maxDistance === undefined
13
+ ? {}
14
+ : { maxDistance: options.properties.maxDistance }),
15
+ ...(options.properties?.occlusion === undefined
16
+ ? {}
17
+ : { occlusion: options.properties.occlusion }),
18
+ ...(options.properties?.occlusionTolerance === undefined
19
+ ? {}
20
+ : { occlusionTolerance: options.properties.occlusionTolerance }),
21
+ ...(options.properties?.payload === undefined
22
+ ? {}
23
+ : { payload: options.properties.payload }),
24
+ };
25
+ const entity = {
26
+ id: options.id,
27
+ name: options.name ?? options.text,
28
+ type: "annotation",
29
+ parentId: options.parentId ?? null,
30
+ enabled: true,
31
+ visible: true,
32
+ transform: options.transform ?? createIdentityTransform(),
33
+ properties,
34
+ };
35
+ return addEntityCommand(entity);
36
+ }
37
+ //# sourceMappingURL=annotation-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-commands.js","sourceRoot":"","sources":["../../src/commands/annotation-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAIxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAsB,MAAM,kBAAkB,CAAC;AAWxE,MAAM,UAAU,uBAAuB,CACrC,OAA0B;IAE1B,MAAM,UAAU,GAA+B;QAC7C,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE,KAAK,IAAI,SAAS;QAC7C,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;QAC1D,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,IAAI,CAAC;QAC3C,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS;YAC/C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QACpD,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS;YAC/C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;QACpD,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,KAAK,SAAS;YAC7C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC;QAChD,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,kBAAkB,KAAK,SAAS;YACtD,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,UAAU,CAAC,kBAAkB,EAAE,CAAC;QAClE,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,KAAK,SAAS;YAC3C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;KAC7C,CAAC;IACF,MAAM,MAAM,GAAiB;QAC3B,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;QAClC,IAAI,EAAE,YAAY;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;QAClC,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,uBAAuB,EAAE;QACzD,UAAU;KACX,CAAC;IACF,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type CameraEntityProperties, type TransformValue } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export interface CameraEntityOptions {
4
+ id: string;
5
+ name?: string;
6
+ parentId?: string | null;
7
+ transform?: TransformValue;
8
+ properties?: Partial<CameraEntityProperties>;
9
+ }
10
+ export declare function createCameraEntityCommand(options: CameraEntityOptions): EditorCommand;
11
+ export declare function updateCameraEntityCommand(entityId: string, properties: Partial<CameraEntityProperties>): EditorCommand;
12
+ //# sourceMappingURL=camera-entity-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-entity-commands.d.ts","sourceRoot":"","sources":["../../src/commands/camera-entity-commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,sBAAsB,EAE3B,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC9C;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,mBAAmB,GAC3B,aAAa,CAsBf;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,OAAO,CAAC,sBAAsB,CAAC,GAC1C,aAAa,CAmBf"}
@@ -0,0 +1,60 @@
1
+ import { createIdentityTransform, } from "@skenora/contracts";
2
+ import { addEntityCommand, createCommandId, setPropertyCommand, } from "../core/commands.js";
3
+ export function createCameraEntityCommand(options) {
4
+ const properties = {
5
+ projection: options.properties?.projection ?? "perspective",
6
+ fov: options.properties?.fov ?? 0.8,
7
+ minZ: options.properties?.minZ ?? 0.01,
8
+ maxZ: options.properties?.maxZ ?? 10_000,
9
+ speed: options.properties?.speed ?? 1,
10
+ ...(options.properties?.orthographicSize === undefined
11
+ ? {}
12
+ : { orthographicSize: options.properties.orthographicSize }),
13
+ };
14
+ const entity = {
15
+ id: options.id,
16
+ name: options.name ?? "Camera",
17
+ type: "camera",
18
+ parentId: options.parentId ?? null,
19
+ enabled: true,
20
+ visible: true,
21
+ transform: options.transform ?? createIdentityTransform(),
22
+ properties,
23
+ };
24
+ return addEntityCommand(entity);
25
+ }
26
+ export function updateCameraEntityCommand(entityId, properties) {
27
+ return {
28
+ id: createCommandId("camera-entity"),
29
+ label: "Update camera entity",
30
+ createPatches(document) {
31
+ const entity = document.entities[entityId];
32
+ if (!entity || entity.type !== "camera") {
33
+ throw new Error(`Camera entity not found: ${entityId}`);
34
+ }
35
+ const previous = entity.properties;
36
+ const next = { ...previous, ...properties };
37
+ assertCameraProperties(next);
38
+ return setPropertyCommand(["entities", entityId, "properties"], next, "Update camera entity").createPatches(document);
39
+ },
40
+ };
41
+ }
42
+ function assertCameraProperties(value) {
43
+ if (!Number.isFinite(value.fov) || value.fov <= 0 || value.fov >= Math.PI) {
44
+ throw new Error("Camera FOV must be between 0 and PI");
45
+ }
46
+ if (!Number.isFinite(value.minZ) ||
47
+ !Number.isFinite(value.maxZ) ||
48
+ value.minZ <= 0 ||
49
+ value.maxZ <= value.minZ) {
50
+ throw new Error("Camera clipping planes are invalid");
51
+ }
52
+ if (!Number.isFinite(value.speed) || value.speed < 0) {
53
+ throw new Error("Camera speed must be a finite non-negative number");
54
+ }
55
+ if (value.orthographicSize !== undefined &&
56
+ (!Number.isFinite(value.orthographicSize) || value.orthographicSize <= 0)) {
57
+ throw new Error("Orthographic camera size must be positive");
58
+ }
59
+ }
60
+ //# sourceMappingURL=camera-entity-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-entity-commands.js","sourceRoot":"","sources":["../../src/commands/camera-entity-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { CameraPathKeyframe, CameraPathRecord } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export declare function upsertCameraPathCommand(path: CameraPathRecord): EditorCommand;
4
+ export declare function removeCameraPathCommand(pathId: string): EditorCommand;
5
+ export declare function addCameraKeyframeCommand(pathId: string, keyframe: CameraPathKeyframe): EditorCommand;
6
+ export declare function removeCameraKeyframeCommand(pathId: string, keyframeId: string): EditorCommand;
7
+ export declare function updateCameraKeyframeCommand(pathId: string, keyframeId: string, update: Partial<Omit<CameraPathKeyframe, "id">>): EditorCommand;
8
+ export declare function setCameraPathDurationCommand(pathId: string, durationMs: number, scaleKeyframes?: boolean): EditorCommand;
9
+ //# sourceMappingURL=camera-path-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-path-commands.d.ts","sourceRoot":"","sources":["../../src/commands/camera-path-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,gBAAgB,GAAG,aAAa,CAM7E;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAiBrE;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,kBAAkB,GAC3B,aAAa,CAOf;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,aAAa,CAKf;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC,GAC9C,aAAa,CAaf;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,cAAc,UAAQ,GACrB,aAAa,CAkBf"}
@@ -0,0 +1,95 @@
1
+ import { createCommandId, setPropertyCommand, } from "../core/commands.js";
2
+ export function upsertCameraPathCommand(path) {
3
+ return setPropertyCommand(["cameraPaths", path.id], normalizePath(path), "Add or update camera path");
4
+ }
5
+ export function removeCameraPathCommand(pathId) {
6
+ return {
7
+ id: createCommandId("remove-camera-path"),
8
+ label: "Remove camera path",
9
+ createPatches(document) {
10
+ const path = document.cameraPaths[pathId];
11
+ return path
12
+ ? [
13
+ {
14
+ op: "delete",
15
+ path: ["cameraPaths", pathId],
16
+ previousValue: path,
17
+ },
18
+ ]
19
+ : [];
20
+ },
21
+ };
22
+ }
23
+ export function addCameraKeyframeCommand(pathId, keyframe) {
24
+ return updatePath(pathId, "Add camera keyframe", (path) => ({
25
+ ...path,
26
+ keyframes: [...path.keyframes, keyframe].sort((left, right) => left.timeMs - right.timeMs),
27
+ }));
28
+ }
29
+ export function removeCameraKeyframeCommand(pathId, keyframeId) {
30
+ return updatePath(pathId, "Remove camera keyframe", (path) => ({
31
+ ...path,
32
+ keyframes: path.keyframes.filter((keyframe) => keyframe.id !== keyframeId),
33
+ }));
34
+ }
35
+ export function updateCameraKeyframeCommand(pathId, keyframeId, update) {
36
+ return updatePath(pathId, "Update camera keyframe", (path) => {
37
+ let found = false;
38
+ const keyframes = path.keyframes.map((keyframe) => {
39
+ if (keyframe.id !== keyframeId)
40
+ return keyframe;
41
+ found = true;
42
+ return { ...keyframe, ...update, id: keyframe.id };
43
+ });
44
+ if (!found) {
45
+ throw new Error(`Camera keyframe not found: ${pathId}/${keyframeId}`);
46
+ }
47
+ return { ...path, keyframes };
48
+ });
49
+ }
50
+ export function setCameraPathDurationCommand(pathId, durationMs, scaleKeyframes = false) {
51
+ return updatePath(pathId, "Update camera path duration", (path) => {
52
+ const nextDuration = Math.max(durationMs, 1);
53
+ const ratio = nextDuration / path.durationMs;
54
+ return {
55
+ ...path,
56
+ durationMs: nextDuration,
57
+ keyframes: scaleKeyframes
58
+ ? path.keyframes.map((keyframe) => ({
59
+ ...keyframe,
60
+ timeMs: keyframe.timeMs * ratio,
61
+ }))
62
+ : path.keyframes.map((keyframe) => ({
63
+ ...keyframe,
64
+ timeMs: Math.min(keyframe.timeMs, nextDuration),
65
+ })),
66
+ };
67
+ });
68
+ }
69
+ function updatePath(pathId, label, update) {
70
+ return {
71
+ id: createCommandId("camera-path"),
72
+ label,
73
+ createPatches(document) {
74
+ const path = document.cameraPaths[pathId];
75
+ if (!path)
76
+ throw new Error(`Camera path not found: ${pathId}`);
77
+ return [
78
+ {
79
+ op: "set",
80
+ path: ["cameraPaths", pathId],
81
+ value: normalizePath(update(path)),
82
+ previousValue: path,
83
+ },
84
+ ];
85
+ },
86
+ };
87
+ }
88
+ function normalizePath(path) {
89
+ return {
90
+ ...path,
91
+ durationMs: Math.max(path.durationMs, 1),
92
+ keyframes: [...path.keyframes].sort((left, right) => left.timeMs - right.timeMs),
93
+ };
94
+ }
95
+ //# sourceMappingURL=camera-path-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"camera-path-commands.js","sourceRoot":"","sources":["../../src/commands/camera-path-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { FlowEdgeRecord, FlowGraphRecord, FlowNodeRecord } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export declare function upsertFlowGraphCommand(graph: FlowGraphRecord): EditorCommand;
4
+ export declare function removeFlowGraphCommand(flowId: string): EditorCommand;
5
+ export declare function addFlowNodeCommand(flowId: string, node: FlowNodeRecord): EditorCommand;
6
+ export declare function updateFlowNodeCommand(flowId: string, nodeId: string, update: Partial<Omit<FlowNodeRecord, "id">>): EditorCommand;
7
+ export declare function removeFlowNodeCommand(flowId: string, nodeId: string): EditorCommand;
8
+ export declare function connectFlowNodesCommand(flowId: string, edge: FlowEdgeRecord): EditorCommand;
9
+ export declare function disconnectFlowEdgeCommand(flowId: string, edgeId: string): EditorCommand;
10
+ //# sourceMappingURL=flow-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-commands.d.ts","sourceRoot":"","sources":["../../src/commands/flow-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,cAAc,EACf,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,eAAe,GAAG,aAAa,CAE5E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAiBpE;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,cAAc,GACnB,aAAa,CAOf;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,GAC1C,aAAa,CAYf;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,aAAa,CAQf;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,cAAc,GACnB,aAAa,CAaf;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,aAAa,CAKf"}
@@ -0,0 +1,86 @@
1
+ import { createCommandId, setPropertyCommand, } from "../core/commands.js";
2
+ export function upsertFlowGraphCommand(graph) {
3
+ return setPropertyCommand(["flows", graph.id], graph, "Add or update Flow");
4
+ }
5
+ export function removeFlowGraphCommand(flowId) {
6
+ return {
7
+ id: createCommandId("remove-flow"),
8
+ label: "Remove Flow",
9
+ createPatches(document) {
10
+ const graph = document.flows[flowId];
11
+ return graph
12
+ ? [
13
+ {
14
+ op: "delete",
15
+ path: ["flows", flowId],
16
+ previousValue: graph,
17
+ },
18
+ ]
19
+ : [];
20
+ },
21
+ };
22
+ }
23
+ export function addFlowNodeCommand(flowId, node) {
24
+ return updateFlowCommand(flowId, "Add Flow node", (graph) => {
25
+ if (graph.nodes.some((item) => item.id === node.id)) {
26
+ throw new Error(`Flow node already exists: ${node.id}`);
27
+ }
28
+ return { ...graph, nodes: [...graph.nodes, node] };
29
+ });
30
+ }
31
+ export function updateFlowNodeCommand(flowId, nodeId, update) {
32
+ return updateFlowCommand(flowId, "Update Flow node", (graph) => {
33
+ if (!graph.nodes.some((item) => item.id === nodeId)) {
34
+ throw new Error(`Flow node not found: ${nodeId}`);
35
+ }
36
+ return {
37
+ ...graph,
38
+ nodes: graph.nodes.map((node) => node.id === nodeId ? { ...node, ...update, id: nodeId } : node),
39
+ };
40
+ });
41
+ }
42
+ export function removeFlowNodeCommand(flowId, nodeId) {
43
+ return updateFlowCommand(flowId, "Remove Flow node", (graph) => ({
44
+ ...graph,
45
+ nodes: graph.nodes.filter((node) => node.id !== nodeId),
46
+ edges: graph.edges.filter((edge) => edge.sourceNodeId !== nodeId && edge.targetNodeId !== nodeId),
47
+ }));
48
+ }
49
+ export function connectFlowNodesCommand(flowId, edge) {
50
+ return updateFlowCommand(flowId, "Connect Flow nodes", (graph) => {
51
+ if (!graph.nodes.some((node) => node.id === edge.sourceNodeId) ||
52
+ !graph.nodes.some((node) => node.id === edge.targetNodeId)) {
53
+ throw new Error("A Flow edge must connect existing nodes");
54
+ }
55
+ if (graph.edges.some((item) => item.id === edge.id)) {
56
+ throw new Error(`Flow edge already exists: ${edge.id}`);
57
+ }
58
+ return { ...graph, edges: [...graph.edges, edge] };
59
+ });
60
+ }
61
+ export function disconnectFlowEdgeCommand(flowId, edgeId) {
62
+ return updateFlowCommand(flowId, "Disconnect Flow edge", (graph) => ({
63
+ ...graph,
64
+ edges: graph.edges.filter((edge) => edge.id !== edgeId),
65
+ }));
66
+ }
67
+ function updateFlowCommand(flowId, label, update) {
68
+ return {
69
+ id: createCommandId("flow"),
70
+ label,
71
+ createPatches(document) {
72
+ const graph = document.flows[flowId];
73
+ if (!graph)
74
+ throw new Error(`Flow not found: ${flowId}`);
75
+ const next = update(graph);
76
+ const patch = {
77
+ op: "set",
78
+ path: ["flows", flowId],
79
+ value: next,
80
+ previousValue: graph,
81
+ };
82
+ return [patch];
83
+ },
84
+ };
85
+ }
86
+ //# sourceMappingURL=flow-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-commands.js","sourceRoot":"","sources":["../../src/commands/flow-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Vector3Value } from "@skenora/contracts";
2
+ import { type EditorCommand } from "../core/commands.js";
3
+ export type Axis = "x" | "y" | "z";
4
+ export type Alignment = "min" | "center" | "max";
5
+ export declare function translateEntitiesCommand(entityIds: readonly string[], delta: Vector3Value): EditorCommand;
6
+ export declare function alignEntitiesCommand(entityIds: readonly string[], axis: Axis, alignment?: Alignment): EditorCommand;
7
+ export declare function distributeEntitiesCommand(entityIds: readonly string[], axis: Axis): EditorCommand;
8
+ //# sourceMappingURL=geometry-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry-commands.d.ts","sourceRoot":"","sources":["../../src/commands/geometry-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE1E,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEvE,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AACnC,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjD,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,EAAE,YAAY,GAClB,aAAa,CAwBf;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,IAAI,EAAE,IAAI,EACV,SAAS,GAAE,SAAoB,GAC9B,aAAa,CAsBf;AAED,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,IAAI,EAAE,IAAI,GACT,aAAa,CA4Bf"}
@@ -0,0 +1,85 @@
1
+ import { createCommandId } from "../core/commands.js";
2
+ export function translateEntitiesCommand(entityIds, delta) {
3
+ return {
4
+ id: createCommandId("translate"),
5
+ label: "Translate entities",
6
+ createPatches(document) {
7
+ return entityIds.flatMap((entityId) => {
8
+ const entity = document.entities[entityId];
9
+ if (!entity)
10
+ return [];
11
+ const previousValue = entity.transform.position;
12
+ return [
13
+ {
14
+ op: "set",
15
+ path: ["entities", entityId, "transform", "position"],
16
+ previousValue,
17
+ value: {
18
+ x: previousValue.x + delta.x,
19
+ y: previousValue.y + delta.y,
20
+ z: previousValue.z + delta.z,
21
+ },
22
+ },
23
+ ];
24
+ });
25
+ },
26
+ };
27
+ }
28
+ export function alignEntitiesCommand(entityIds, axis, alignment = "center") {
29
+ return {
30
+ id: createCommandId("align"),
31
+ label: `Align ${axis.toUpperCase()}`,
32
+ createPatches(document) {
33
+ const entities = selectedEntities(document, entityIds);
34
+ if (entities.length < 2)
35
+ return [];
36
+ const coordinates = entities.map((entity) => entity.transform.position[axis]);
37
+ const target = alignment === "min"
38
+ ? Math.min(...coordinates)
39
+ : alignment === "max"
40
+ ? Math.max(...coordinates)
41
+ : coordinates.reduce((sum, value) => sum + value, 0) /
42
+ coordinates.length;
43
+ return entities.flatMap((entity) => positionPatch(entity.id, entity.transform.position, axis, target));
44
+ },
45
+ };
46
+ }
47
+ export function distributeEntitiesCommand(entityIds, axis) {
48
+ return {
49
+ id: createCommandId("distribute"),
50
+ label: `Distribute ${axis.toUpperCase()}`,
51
+ createPatches(document) {
52
+ const entities = selectedEntities(document, entityIds).sort((left, right) => left.transform.position[axis] - right.transform.position[axis]);
53
+ if (entities.length < 3)
54
+ return [];
55
+ const first = entities[0];
56
+ const last = entities.at(-1);
57
+ if (!first || !last)
58
+ return [];
59
+ const interval = (last.transform.position[axis] - first.transform.position[axis]) /
60
+ (entities.length - 1);
61
+ return entities
62
+ .slice(1, -1)
63
+ .flatMap((entity, index) => positionPatch(entity.id, entity.transform.position, axis, first.transform.position[axis] + interval * (index + 1)));
64
+ },
65
+ };
66
+ }
67
+ function selectedEntities(document, entityIds) {
68
+ return [...new Set(entityIds)].flatMap((id) => {
69
+ const entity = document.entities[id];
70
+ return entity ? [entity] : [];
71
+ });
72
+ }
73
+ function positionPatch(entityId, previousValue, axis, value) {
74
+ if (Object.is(previousValue[axis], value))
75
+ return [];
76
+ return [
77
+ {
78
+ op: "set",
79
+ path: ["entities", entityId, "transform", "position"],
80
+ previousValue,
81
+ value: { ...previousValue, [axis]: value },
82
+ },
83
+ ];
84
+ }
85
+ //# sourceMappingURL=geometry-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geometry-commands.js","sourceRoot":"","sources":["../../src/commands/geometry-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type SceneDocumentData } from "@skenora/contracts";
2
+ import type { DocumentPatch } from "@skenora/document";
3
+ export declare function synchronizeEntityMaterialIds(document: Readonly<SceneDocumentData>, materialId: string, targetEntityId: string | null): DocumentPatch[];
4
+ export declare function synchronizeEntityMaterialAssignments(document: Readonly<SceneDocumentData>, materialIds: readonly string[], targetEntityId: string | null): DocumentPatch[];
5
+ export declare function synchronizeMaterialBindings(document: Readonly<SceneDocumentData>, materialIds: readonly string[], targetEntityId: string | null, targetNames?: Readonly<Record<string, string | undefined>>): DocumentPatch[];
6
+ export declare function unassignMaterialBinding(document: Readonly<SceneDocumentData>, materialId: string, entityId: string): DocumentPatch[];
7
+ //# sourceMappingURL=material-assignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-assignment.d.ts","sourceRoot":"","sources":["../../src/commands/material-assignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACrC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,aAAa,EAAE,CAMjB;AAED,wBAAgB,oCAAoC,CAClD,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACrC,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,GAC5B,aAAa,EAAE,CAEjB;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACrC,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,WAAW,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAM,GAC7D,aAAa,EAAE,CAkDjB;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,EACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,aAAa,EAAE,CAQjB"}
@@ -0,0 +1,69 @@
1
+ import { createMaterialBindingId, getMaterialBindingsForMaterial, } from "@skenora/contracts";
2
+ export function synchronizeEntityMaterialIds(document, materialId, targetEntityId) {
3
+ return synchronizeEntityMaterialAssignments(document, [materialId], targetEntityId);
4
+ }
5
+ export function synchronizeEntityMaterialAssignments(document, materialIds, targetEntityId) {
6
+ return synchronizeMaterialBindings(document, materialIds, targetEntityId);
7
+ }
8
+ export function synchronizeMaterialBindings(document, materialIds, targetEntityId, targetNames = {}) {
9
+ const uniqueMaterialIds = [...new Set(materialIds)];
10
+ const patches = [];
11
+ const occupied = new Set(Object.keys(document.materialBindings));
12
+ for (const materialId of uniqueMaterialIds) {
13
+ if (document.materials[materialId]?.creation) {
14
+ throw new Error("Owned materials require explicit binding commands; legacy synchronization would discard other bindings");
15
+ }
16
+ const existing = getMaterialBindingsForMaterial(document, materialId);
17
+ if (!targetEntityId) {
18
+ patches.push(...existing.map((binding) => ({
19
+ op: "delete",
20
+ path: ["materialBindings", binding.id],
21
+ previousValue: binding,
22
+ })));
23
+ continue;
24
+ }
25
+ const retained = existing[0];
26
+ for (const binding of existing.slice(1)) {
27
+ patches.push({
28
+ op: "delete",
29
+ path: ["materialBindings", binding.id],
30
+ previousValue: binding,
31
+ });
32
+ }
33
+ const targetName = targetNames[materialId] ?? retained?.targetName;
34
+ const bindingId = retained?.id ??
35
+ createMaterialBindingId(materialId, targetEntityId, targetName, occupied);
36
+ occupied.add(bindingId);
37
+ const next = {
38
+ id: bindingId,
39
+ materialId,
40
+ entityId: targetEntityId,
41
+ ...(targetName ? { targetName } : {}),
42
+ };
43
+ if (retained && sameBinding(retained, next))
44
+ continue;
45
+ patches.push({
46
+ op: "set",
47
+ path: ["materialBindings", bindingId],
48
+ value: next,
49
+ previousValue: retained,
50
+ });
51
+ }
52
+ return patches;
53
+ }
54
+ export function unassignMaterialBinding(document, materialId, entityId) {
55
+ return getMaterialBindingsForMaterial(document, materialId)
56
+ .filter((binding) => binding.entityId === entityId)
57
+ .map((binding) => ({
58
+ op: "delete",
59
+ path: ["materialBindings", binding.id],
60
+ previousValue: binding,
61
+ }));
62
+ }
63
+ function sameBinding(left, right) {
64
+ return (left.id === right.id &&
65
+ left.materialId === right.materialId &&
66
+ left.entityId === right.entityId &&
67
+ left.targetName === right.targetName);
68
+ }
69
+ //# sourceMappingURL=material-assignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-assignment.js","sourceRoot":"","sources":["../../src/commands/material-assignment.ts"],"names":[],"mappings":"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"}