@volter/editor-threejs 0.5.65 → 0.5.67
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.
- package/NOTICE +2 -0
- package/contributions/animation-mixers.service.ts +20 -0
- package/contributions/animation-timeline.utility.tsx +44 -0
- package/contributions/three-integration.service.ts +13 -0
- package/dist-node/serving.mjs +405 -0
- package/package.json +113 -5
- package/serving/animation-live-module.ts +70 -0
- package/serving/animation-stamp.ts +88 -0
- package/serving/index.ts +14 -0
- package/serving/model-import-conversion.ts +344 -0
- package/src/adapter/ingest/scene-capture.ts +1 -23
- package/src/adapter/renderer-config.ts +3 -4
- package/src/adapter/three-contract.ts +72 -0
- package/src/animation/live-mixers.ts +55 -0
- package/src/ecs/object-marks.ts +1 -1
- package/src/ecs/user-data.ts +0 -16
- package/src/host-hierarchy-objects.ts +31 -0
- package/src/kit/animation/three-clips-subject.ts +190 -0
- package/src/kit/asset-compare.ts +294 -0
- package/src/kit/asset-preview-command.ts +265 -0
- package/src/kit/asset-preview-framing.ts +357 -0
- package/src/kit/asset-preview.ts +2802 -0
- package/src/kit/asset-workflow/model-inspection.ts +830 -0
- package/src/kit/authoring/component-instance-root.ts +171 -0
- package/src/kit/authoring/design-time-settle.ts +343 -0
- package/src/kit/authoring/live-object-transform.ts +62 -0
- package/src/kit/authoring/object3d-document-session-registry.ts +154 -0
- package/src/kit/authoring/object3d-document-session.ts +1965 -0
- package/src/kit/authoring/object3d-gesture-controller.ts +113 -0
- package/src/kit/authoring/quarks-particle-systems.ts +19 -0
- package/src/kit/authoring/shell-viewport-policy.ts +48 -0
- package/src/kit/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/kit/authoring/three-projection-core.ts +226 -0
- package/src/kit/authoring/viewport-pick-context.ts +39 -0
- package/src/kit/authoring/viewport-raycast.ts +240 -0
- package/src/kit/authoring/world-hidden-viewport.ts +95 -0
- package/src/kit/camera-authoring.ts +175 -0
- package/src/kit/components/CameraInfo.tsx +56 -0
- package/src/kit/components/InspectorObjectPreview.tsx +57 -0
- package/src/kit/components/Object3DDocumentToolbar.tsx +549 -0
- package/src/kit/components/Object3DDocumentViewport.tsx +58 -0
- package/src/kit/components/StageHost.tsx +2547 -0
- package/src/kit/components/StageOverlays.tsx +21 -0
- package/src/kit/components/StatsOverlay.tsx +78 -0
- package/src/kit/components/ToolObject3DPreview.tsx +39 -0
- package/src/kit/components/ViewportFurniture.tsx +655 -0
- package/src/kit/components/ViewportOverlay.tsx +215 -0
- package/src/kit/components/ViewportShadingMenu.tsx +340 -0
- package/src/kit/components/ViewportViewMenu.tsx +155 -0
- package/src/kit/components/asset-viewers/EntityModelDocument.tsx +121 -0
- package/src/kit/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/kit/components/asset-viewers/LiveModuleDocument.tsx +395 -0
- package/src/kit/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/kit/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/kit/components/asset-viewers/Object3DPreview.tsx +356 -0
- package/src/kit/components/asset-viewers/QuarksAssetDocument.tsx +527 -0
- package/src/kit/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/kit/components/asset-viewers/three-asset-viewers.tsx +132 -0
- package/src/kit/components/object3d-contribution-surfaces.tsx +33 -0
- package/src/kit/components/stage-keyboard.tsx +40 -0
- package/src/kit/components/stage-overlay-set.tsx +105 -0
- package/src/kit/components/stage-presence-markers.ts +482 -0
- package/src/kit/components/stage-transform-chrome.ts +30 -0
- package/src/kit/components/stage-transform-tools.tsx +73 -0
- package/src/kit/components/stage-view-name.ts +30 -0
- package/src/kit/components/standard-viewport-dressing.ts +1042 -0
- package/src/kit/components/world-root-binding.ts +64 -0
- package/src/kit/constraint-helper.ts +338 -0
- package/src/kit/editor-shell-store.ts +814 -0
- package/src/kit/editor-viewport.ts +6621 -0
- package/src/kit/entity-lod.ts +31 -0
- package/src/kit/entity-object.ts +92 -0
- package/src/kit/hierarchy-mark-reader.ts +74 -0
- package/src/kit/instanced-presentation.ts +164 -0
- package/src/kit/live-module-source.ts +230 -0
- package/src/kit/model-thumbnail.ts +539 -0
- package/src/kit/play-camera-flight.ts +300 -0
- package/src/kit/projection/three.ts +898 -0
- package/src/kit/reflection-probe-helper.ts +142 -0
- package/src/kit/scene-document-viewport.ts +51 -0
- package/src/kit/scene-framing.ts +315 -0
- package/src/kit/scene-view-fog.ts +89 -0
- package/src/kit/spatial-handle-visuals.ts +332 -0
- package/src/kit/stories/three-story-model.ts +66 -0
- package/src/kit/three-canvas-render.ts +44 -0
- package/src/kit/three-hierarchy-row-media.ts +26 -0
- package/src/kit/three-inspection-media.ts +73 -0
- package/src/kit/three-integration.ts +86 -0
- package/src/kit/three-state.ts +33 -0
- package/src/kit/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/kit/three-viewport/camera-fit.ts +41 -0
- package/src/kit/three-viewport/interactive-renderer.ts +132 -0
- package/src/kit/three-viewport/selection-brackets.ts +355 -0
- package/src/kit/three-viewport/selection-outline.ts +333 -0
- package/src/kit/three-viewport/skeleton-helper.ts +61 -0
- package/src/kit/three-viewport/source-color.ts +197 -0
- package/src/kit/three-viewport/studio-environment.ts +96 -0
- package/src/kit/trigger-volume-helper.ts +116 -0
- package/src/kit/viewport-actions.ts +128 -0
- package/src/kit/viewport-authoring-policy.ts +154 -0
- package/src/kit/viewport-commands.ts +318 -0
- package/src/kit/viewport-hotkeys.ts +119 -0
- package/src/kit/viewport-shading-boundary.ts +12 -0
- package/src/kit/viewport-status-facet.ts +53 -0
- package/src/object3d-contributions.ts +494 -0
- package/src/render/viewport-shading.ts +6 -2
- package/src/viewport/content-bounds.ts +38 -4
- package/src/viewport/environment.ts +16 -0
- package/src/viewport-api.ts +92 -0
- package/src/viewport-door.ts +237 -0
- package/src/animation/animation-clock.ts +0 -479
- package/src/animation/runtime-inspection.ts +0 -45
package/NOTICE
CHANGED
|
@@ -2,6 +2,8 @@ Copyright 2026 Volter AI, Inc.
|
|
|
2
2
|
|
|
3
3
|
Modules under src/viewport and src/capture were imported from the
|
|
4
4
|
AGPL-3.0-only @vgai/threejs package; LICENSE contains that license.
|
|
5
|
+
serving/model-import-conversion.ts was imported from the AGPL-3.0-only
|
|
6
|
+
@vgai/editor package's server and retains that license.
|
|
5
7
|
|
|
6
8
|
Modules under src/adapter, src/animation, src/ecs and src/render, together
|
|
7
9
|
with src/asset-loaders.ts, src/asset-parse-error.ts and src/loader.ts, were
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The animation stamp's status facet (`@volter/editor-sdk/services`, a `workspace.service`
|
|
3
|
+
* contribution): `vgai status` reports the mixers the running world's own code made, with the
|
|
4
|
+
* clips it has played through each and the objects each animates, so "the timeline found
|
|
5
|
+
* nothing" is answerable from the session.
|
|
6
|
+
*/
|
|
7
|
+
import { editorHost } from '@volter/editor-sdk/host';
|
|
8
|
+
import { liveMixers } from '../src/animation/live-mixers';
|
|
9
|
+
|
|
10
|
+
export const point = 'workspace.service';
|
|
11
|
+
|
|
12
|
+
export function start(): () => void {
|
|
13
|
+
return editorHost().session.reportFacet(() => ({
|
|
14
|
+
liveMixers: liveMixers().map((entry) => ({
|
|
15
|
+
site: entry.key,
|
|
16
|
+
clips: [...entry.clips.keys()],
|
|
17
|
+
animates: [...entry.roots].map((root) => (root as { name?: string }).name || '(unnamed)'),
|
|
18
|
+
})),
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE ANIMATION PANEL (`workspace.utility`): the active document's stage transport, drawn by the
|
|
3
|
+
* kit's own strip. A world document's stage attaches every clip its scene can show — a GLTF's
|
|
4
|
+
* own `animations`, and the mixers the game's code made (`animation-mixers.service.ts`) — and
|
|
5
|
+
* this is where a person scrubs and plays them in Edit, as Unity's Animation window does beside
|
|
6
|
+
* its Scene view. While Play drives time the strip goes read-only and says why.
|
|
7
|
+
*/
|
|
8
|
+
import { editorHost } from '@volter/editor-sdk/host';
|
|
9
|
+
import { TransportStrip } from '@volter/editor-sdk/kit/transport-strip';
|
|
10
|
+
import { Text } from '@volter/editor-sdk/widgets';
|
|
11
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
12
|
+
|
|
13
|
+
export const point = 'workspace.utility';
|
|
14
|
+
export const title = 'Animation';
|
|
15
|
+
|
|
16
|
+
export default function AnimationTimeline() {
|
|
17
|
+
const { documents, transport } = editorHost();
|
|
18
|
+
const activeId = useSyncExternalStore(documents.subscribe, documents.activeId, documents.activeId);
|
|
19
|
+
const handle = useSyncExternalStore(
|
|
20
|
+
transport.subscribe,
|
|
21
|
+
useCallback(() => (activeId ? transport.for(activeId) : null), [activeId, transport]),
|
|
22
|
+
);
|
|
23
|
+
const snapshot = useSyncExternalStore(
|
|
24
|
+
useCallback((listener: () => void) => (handle ? handle.subscribe(listener) : () => {}), [handle]),
|
|
25
|
+
useCallback(() => handle?.snapshot() ?? null, [handle]),
|
|
26
|
+
);
|
|
27
|
+
if (!handle || !snapshot || snapshot.activeSubject === null) {
|
|
28
|
+
return (
|
|
29
|
+
<Text
|
|
30
|
+
as="p"
|
|
31
|
+
variant="caption"
|
|
32
|
+
data-testid="animation-timeline-empty"
|
|
33
|
+
data-document={activeId ?? ''}
|
|
34
|
+
data-transport={handle ? 'yes' : 'no'}
|
|
35
|
+
style={{ padding: 'var(--vgai-space-2) var(--vgai-space-3)' }}
|
|
36
|
+
>
|
|
37
|
+
{handle
|
|
38
|
+
? 'Nothing in the active document plays an animation.'
|
|
39
|
+
: 'The active document has no stage to animate.'}
|
|
40
|
+
</Text>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return <TransportStrip transport={handle} />;
|
|
44
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Three integration, installed at boot (`workspace.service`): the Object3D surfaces
|
|
3
|
+
* contributions mount, the viewport's relay verbs, Asset Lab viewers, inspection and hierarchy
|
|
4
|
+
* media, captures, the authoring policy and the session's view-state persistence
|
|
5
|
+
* (`src/kit/three-integration.ts`). Every viewport also ensures it before it mounts.
|
|
6
|
+
*/
|
|
7
|
+
import { ensureThreeIntegration } from '../src/kit/three-integration';
|
|
8
|
+
|
|
9
|
+
export const point = 'workspace.service';
|
|
10
|
+
|
|
11
|
+
export function start(): () => void {
|
|
12
|
+
return ensureThreeIntegration();
|
|
13
|
+
}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
// serving/animation-stamp.ts
|
|
2
|
+
import { relative, sep } from "node:path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
|
|
5
|
+
// serving/animation-live-module.ts
|
|
6
|
+
var ANIMATION_LIVE_MODULE_ID = "virtual:vgai-three-animation-live";
|
|
7
|
+
var animationLiveModuleSource = `
|
|
8
|
+
const live = (globalThis[Symbol.for('volter.three.animation.live')] ??= {
|
|
9
|
+
mixers: new Map(),
|
|
10
|
+
listeners: new Set(),
|
|
11
|
+
version: 0,
|
|
12
|
+
});
|
|
13
|
+
function notify() {
|
|
14
|
+
live.version++;
|
|
15
|
+
for (const listener of live.listeners) {
|
|
16
|
+
try { listener(); } catch (error) { console.error(error); }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function __vgaiMixer(mixer, key) {
|
|
20
|
+
if (!mixer || typeof mixer.clipAction !== 'function') return mixer;
|
|
21
|
+
if (mixer.__vgaiMixerKey) return mixer;
|
|
22
|
+
Object.defineProperty(mixer, '__vgaiMixerKey', { value: key });
|
|
23
|
+
const entry = { key, mixer, clips: new Map(), roots: new Set() };
|
|
24
|
+
live.mixers.set(mixer, entry);
|
|
25
|
+
const clipAction = mixer.clipAction;
|
|
26
|
+
mixer.clipAction = function (clip, root, blendMode) {
|
|
27
|
+
const action = clipAction.call(this, clip, root, blendMode);
|
|
28
|
+
if (action) {
|
|
29
|
+
const played = action.getClip();
|
|
30
|
+
const target = action.getRoot();
|
|
31
|
+
let changed = false;
|
|
32
|
+
if (played && !entry.clips.has(played.name)) { entry.clips.set(played.name, played); changed = true; }
|
|
33
|
+
if (target && !entry.roots.has(target)) { entry.roots.add(target); changed = true; }
|
|
34
|
+
if (changed) notify();
|
|
35
|
+
}
|
|
36
|
+
return action;
|
|
37
|
+
};
|
|
38
|
+
const uncacheRoot = mixer.uncacheRoot;
|
|
39
|
+
mixer.uncacheRoot = function (root) {
|
|
40
|
+
const result = uncacheRoot.call(this, root);
|
|
41
|
+
entry.roots.delete(root);
|
|
42
|
+
if (root === this.getRoot()) live.mixers.delete(this);
|
|
43
|
+
notify();
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
notify();
|
|
47
|
+
return mixer;
|
|
48
|
+
}
|
|
49
|
+
/** drei's \`useAnimations\` result: its mixer, and the clips it was handed. */
|
|
50
|
+
export function __vgaiAnimations(result, key) {
|
|
51
|
+
if (!result || !result.mixer) return result;
|
|
52
|
+
__vgaiMixer(result.mixer, key);
|
|
53
|
+
const entry = live.mixers.get(result.mixer);
|
|
54
|
+
if (entry && Array.isArray(result.clips)) {
|
|
55
|
+
let changed = false;
|
|
56
|
+
for (const clip of result.clips) {
|
|
57
|
+
if (clip && clip.name && !entry.clips.has(clip.name)) { entry.clips.set(clip.name, clip); changed = true; }
|
|
58
|
+
}
|
|
59
|
+
if (changed) notify();
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
// serving/animation-stamp.ts
|
|
66
|
+
var VIRTUAL_ID = `\0${ANIMATION_LIVE_MODULE_ID}`;
|
|
67
|
+
var NODE_MODULES = /[\\/]node_modules[\\/]/;
|
|
68
|
+
var SCRIPT = /\.[cm]?[jt]sx?$/;
|
|
69
|
+
function isMixerConstruction(node) {
|
|
70
|
+
if (!ts.isNewExpression(node)) return false;
|
|
71
|
+
const callee = node.expression;
|
|
72
|
+
if (ts.isIdentifier(callee)) return callee.text === "AnimationMixer";
|
|
73
|
+
return ts.isPropertyAccessExpression(callee) && callee.name.text === "AnimationMixer";
|
|
74
|
+
}
|
|
75
|
+
function isUseAnimations(node) {
|
|
76
|
+
return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "useAnimations";
|
|
77
|
+
}
|
|
78
|
+
function stampAnimation(code, file, relativeFile) {
|
|
79
|
+
if (!code.includes("AnimationMixer") && !code.includes("useAnimations")) return null;
|
|
80
|
+
const kind = file.endsWith(".tsx") ? ts.ScriptKind.TSX : file.endsWith(".jsx") ? ts.ScriptKind.JSX : ts.ScriptKind.TS;
|
|
81
|
+
const source = ts.createSourceFile(file, code, ts.ScriptTarget.Latest, true, kind);
|
|
82
|
+
const sites = [];
|
|
83
|
+
const visit = (node) => {
|
|
84
|
+
if (isMixerConstruction(node)) sites.push({ start: node.getStart(source), end: node.getEnd(), wrapper: "__vgaiMixer" });
|
|
85
|
+
else if (isUseAnimations(node)) sites.push({ start: node.getStart(source), end: node.getEnd(), wrapper: "__vgaiAnimations" });
|
|
86
|
+
ts.forEachChild(node, visit);
|
|
87
|
+
};
|
|
88
|
+
visit(source);
|
|
89
|
+
if (sites.length === 0) return null;
|
|
90
|
+
let out = code;
|
|
91
|
+
for (const site of [...sites].sort((a, b) => b.start - a.start)) {
|
|
92
|
+
const { line, character } = source.getLineAndCharacterOfPosition(site.start);
|
|
93
|
+
const key = `${relativeFile}:${line + 1}:${character + 1}`;
|
|
94
|
+
out = `${out.slice(0, site.start)}${site.wrapper}(${out.slice(site.start, site.end)}, ${JSON.stringify(key)})${out.slice(site.end)}`;
|
|
95
|
+
}
|
|
96
|
+
return `import { __vgaiMixer, __vgaiAnimations } from ${JSON.stringify(ANIMATION_LIVE_MODULE_ID)};
|
|
97
|
+
${out}`;
|
|
98
|
+
}
|
|
99
|
+
function animationStampPlugin(services) {
|
|
100
|
+
let serverRoot = process.cwd();
|
|
101
|
+
const isProjectFile = (file) => {
|
|
102
|
+
if (NODE_MODULES.test(file) || !SCRIPT.test(file)) return false;
|
|
103
|
+
const roots = [...services.projectRoots(), services.currentProjectRoot()].filter((root) => !!root);
|
|
104
|
+
return roots.some((root) => file.startsWith(root + sep) || file.startsWith(root + "/"));
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
name: "vgai-three-animation",
|
|
108
|
+
enforce: "pre",
|
|
109
|
+
resolveId(id) {
|
|
110
|
+
return id === ANIMATION_LIVE_MODULE_ID ? VIRTUAL_ID : null;
|
|
111
|
+
},
|
|
112
|
+
load(id) {
|
|
113
|
+
return id === VIRTUAL_ID ? animationLiveModuleSource : null;
|
|
114
|
+
},
|
|
115
|
+
configureServer(server) {
|
|
116
|
+
serverRoot = server.config.root;
|
|
117
|
+
},
|
|
118
|
+
transform(code, id) {
|
|
119
|
+
if (id.startsWith("\0")) return null;
|
|
120
|
+
const file = id.split("?")[0] ?? id;
|
|
121
|
+
if (!isProjectFile(file)) return null;
|
|
122
|
+
const root = services.currentProjectRoot() ?? serverRoot;
|
|
123
|
+
const stamped = stampAnimation(code, file, relative(root, file).split(sep).join("/"));
|
|
124
|
+
return stamped === null ? null : { code: stamped, map: null };
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// serving/model-import-conversion.ts
|
|
130
|
+
import { readFile } from "node:fs/promises";
|
|
131
|
+
import { createRequire } from "node:module";
|
|
132
|
+
import { dirname, extname } from "node:path";
|
|
133
|
+
import * as THREE from "three";
|
|
134
|
+
import { GLTFExporter } from "three/addons/exporters/GLTFExporter.js";
|
|
135
|
+
import { ColladaLoader } from "three/addons/loaders/ColladaLoader.js";
|
|
136
|
+
import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
|
|
137
|
+
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
138
|
+
import { MTLLoader } from "three/addons/loaders/MTLLoader.js";
|
|
139
|
+
import { OBJLoader } from "three/addons/loaders/OBJLoader.js";
|
|
140
|
+
import { PLYLoader } from "three/addons/loaders/PLYLoader.js";
|
|
141
|
+
import { STLLoader } from "three/addons/loaders/STLLoader.js";
|
|
142
|
+
import { TDSLoader } from "three/addons/loaders/TDSLoader.js";
|
|
143
|
+
import { mergeVertices } from "three/addons/utils/BufferGeometryUtils.js";
|
|
144
|
+
var threeModelConverter = {
|
|
145
|
+
formats: ["fbx", "obj", "dae", "stl", "ply", "3ds"],
|
|
146
|
+
convert: (primaryPath, format, settings) => convertStagedModelToGlb(primaryPath, format, settings)
|
|
147
|
+
};
|
|
148
|
+
async function convertStagedModelToGlb(primaryPath, format, settings) {
|
|
149
|
+
installNodeDom();
|
|
150
|
+
const bytes = new Uint8Array(await readFile(primaryPath));
|
|
151
|
+
const object = await parseSourceModel(primaryPath, format.toLowerCase(), bytes);
|
|
152
|
+
discardUnloadedTextures(object);
|
|
153
|
+
applyModelImportSettings(object, settings);
|
|
154
|
+
installNodeFileReader();
|
|
155
|
+
try {
|
|
156
|
+
const result = await new Promise((resolve, reject) => {
|
|
157
|
+
new GLTFExporter().parse(
|
|
158
|
+
object,
|
|
159
|
+
(output2) => output2 instanceof ArrayBuffer ? resolve(output2) : reject(new Error("Model conversion produced JSON instead of binary GLB.")),
|
|
160
|
+
reject,
|
|
161
|
+
{ binary: true, animations: object.animations, onlyVisible: false }
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
const output = new Uint8Array(result);
|
|
165
|
+
await validateConvertedGlb(output);
|
|
166
|
+
return output;
|
|
167
|
+
} finally {
|
|
168
|
+
disposeObject(object);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
var materialTextureSlots = [
|
|
172
|
+
"map",
|
|
173
|
+
"alphaMap",
|
|
174
|
+
"aoMap",
|
|
175
|
+
"bumpMap",
|
|
176
|
+
"displacementMap",
|
|
177
|
+
"emissiveMap",
|
|
178
|
+
"envMap",
|
|
179
|
+
"lightMap",
|
|
180
|
+
"metalnessMap",
|
|
181
|
+
"normalMap",
|
|
182
|
+
"roughnessMap",
|
|
183
|
+
"specularMap"
|
|
184
|
+
];
|
|
185
|
+
function applyModelImportSettings(object, settings) {
|
|
186
|
+
object.scale.multiplyScalar(settings.scale * sourceUnitScale(settings.sourceUnits));
|
|
187
|
+
object.quaternion.premultiply(importAxisRotation(settings.upAxis, settings.forwardAxis));
|
|
188
|
+
const discardedTextures = /* @__PURE__ */ new Set();
|
|
189
|
+
object.traverse((node) => {
|
|
190
|
+
const mesh = node;
|
|
191
|
+
if (!mesh.geometry) return;
|
|
192
|
+
let geometry = mesh.geometry;
|
|
193
|
+
if (settings.meshOptimization !== "none") {
|
|
194
|
+
const optimized = mergeVertices(
|
|
195
|
+
geometry,
|
|
196
|
+
settings.meshOptimization === "aggressive" ? 1e-3 : 1e-6
|
|
197
|
+
);
|
|
198
|
+
if (optimized !== geometry) {
|
|
199
|
+
mesh.geometry = optimized;
|
|
200
|
+
geometry.dispose();
|
|
201
|
+
geometry = optimized;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (settings.normals !== "preserve") {
|
|
205
|
+
geometry.deleteAttribute("normal");
|
|
206
|
+
geometry.computeVertexNormals();
|
|
207
|
+
}
|
|
208
|
+
if (settings.tangents === "discard") geometry.deleteAttribute("tangent");
|
|
209
|
+
if (settings.tangents === "generate" && geometry.index && geometry.hasAttribute("position") && geometry.hasAttribute("normal") && geometry.hasAttribute("uv")) {
|
|
210
|
+
geometry.computeTangents();
|
|
211
|
+
}
|
|
212
|
+
geometry.computeBoundingBox();
|
|
213
|
+
geometry.computeBoundingSphere();
|
|
214
|
+
const priorMaterials = Array.isArray(mesh.material) ? mesh.material : mesh.material ? [mesh.material] : [];
|
|
215
|
+
if (settings.materials === "discard") {
|
|
216
|
+
mesh.material = Array.isArray(mesh.material) ? priorMaterials.map(() => new THREE.MeshStandardMaterial()) : new THREE.MeshStandardMaterial();
|
|
217
|
+
for (const material of priorMaterials) material.dispose();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (settings.textures !== "discard") return;
|
|
221
|
+
for (const material of priorMaterials) {
|
|
222
|
+
const textured = material;
|
|
223
|
+
for (const slot of materialTextureSlots) {
|
|
224
|
+
const texture = textured[slot];
|
|
225
|
+
if (texture instanceof THREE.Texture) discardedTextures.add(texture);
|
|
226
|
+
textured[slot] = null;
|
|
227
|
+
}
|
|
228
|
+
material.needsUpdate = true;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
for (const texture of discardedTextures) texture.dispose();
|
|
232
|
+
if (settings.animations.length > 0) {
|
|
233
|
+
const requested = new Set(settings.animations);
|
|
234
|
+
const selected = object.animations.filter((clip) => requested.has(clip.name));
|
|
235
|
+
const missing = settings.animations.filter(
|
|
236
|
+
(name) => !selected.some((clip) => clip.name === name)
|
|
237
|
+
);
|
|
238
|
+
if (missing.length > 0) throw new Error(`Animation clips not found: ${missing.join(", ")}.`);
|
|
239
|
+
object.animations = selected;
|
|
240
|
+
}
|
|
241
|
+
object.updateWorldMatrix(true, true);
|
|
242
|
+
}
|
|
243
|
+
function sourceUnitScale(units) {
|
|
244
|
+
return { auto: 1, mm: 1e-3, cm: 0.01, m: 1, in: 0.0254, ft: 0.3048 }[units];
|
|
245
|
+
}
|
|
246
|
+
function importAxisRotation(upAxis, forwardAxis) {
|
|
247
|
+
const up = upAxis === "auto" ? null : axisVector(upAxis);
|
|
248
|
+
const forward = forwardAxis === "auto" ? null : axisVector(forwardAxis);
|
|
249
|
+
if (up && forward) {
|
|
250
|
+
if (Math.abs(up.dot(forward)) > 1e-3)
|
|
251
|
+
throw new Error("Import up and forward axes must be perpendicular.");
|
|
252
|
+
const right = new THREE.Vector3().crossVectors(forward, up).normalize();
|
|
253
|
+
const correctedForward = new THREE.Vector3().crossVectors(up, right).normalize();
|
|
254
|
+
const sourceBasis = new THREE.Matrix4().makeBasis(right, up, correctedForward.clone().negate());
|
|
255
|
+
return new THREE.Quaternion().setFromRotationMatrix(sourceBasis.invert());
|
|
256
|
+
}
|
|
257
|
+
if (up) return new THREE.Quaternion().setFromUnitVectors(up, new THREE.Vector3(0, 1, 0));
|
|
258
|
+
if (forward)
|
|
259
|
+
return new THREE.Quaternion().setFromUnitVectors(forward, new THREE.Vector3(0, 0, -1));
|
|
260
|
+
return new THREE.Quaternion();
|
|
261
|
+
}
|
|
262
|
+
function axisVector(axis) {
|
|
263
|
+
const sign = axis.startsWith("-") ? -1 : 1;
|
|
264
|
+
const name = axis.replace("-", "");
|
|
265
|
+
return new THREE.Vector3(
|
|
266
|
+
name === "x" ? sign : 0,
|
|
267
|
+
name === "y" ? sign : 0,
|
|
268
|
+
name === "z" ? sign : 0
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
async function parseSourceModel(primaryPath, format, bytes) {
|
|
272
|
+
const resourcePath = `${dirname(primaryPath)}/`;
|
|
273
|
+
switch (format) {
|
|
274
|
+
case "fbx":
|
|
275
|
+
return new FBXLoader().parse(bytes.buffer, resourcePath);
|
|
276
|
+
case "obj": {
|
|
277
|
+
const loader = new OBJLoader();
|
|
278
|
+
const materialPath = primaryPath.replace(/\.obj$/i, ".mtl");
|
|
279
|
+
try {
|
|
280
|
+
const materials = new MTLLoader().parse(await readFile(materialPath, "utf8"), resourcePath);
|
|
281
|
+
materials.preload();
|
|
282
|
+
loader.setMaterials(materials);
|
|
283
|
+
} catch {
|
|
284
|
+
}
|
|
285
|
+
return loader.parse(new TextDecoder().decode(bytes));
|
|
286
|
+
}
|
|
287
|
+
case "dae": {
|
|
288
|
+
return new ColladaLoader().parse(new TextDecoder().decode(bytes), resourcePath).scene;
|
|
289
|
+
}
|
|
290
|
+
case "stl": {
|
|
291
|
+
const geometry = new STLLoader().parse(bytes.buffer);
|
|
292
|
+
return new THREE.Mesh(
|
|
293
|
+
geometry,
|
|
294
|
+
new THREE.MeshStandardMaterial({ color: 9418202, roughness: 0.75 })
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
case "ply": {
|
|
298
|
+
const geometry = new PLYLoader().parse(bytes.buffer);
|
|
299
|
+
if (!geometry.hasAttribute("normal")) geometry.computeVertexNormals();
|
|
300
|
+
return new THREE.Mesh(
|
|
301
|
+
geometry,
|
|
302
|
+
new THREE.MeshStandardMaterial({
|
|
303
|
+
color: geometry.hasAttribute("color") ? 16777215 : 12112027,
|
|
304
|
+
vertexColors: geometry.hasAttribute("color"),
|
|
305
|
+
roughness: 0.8,
|
|
306
|
+
side: THREE.DoubleSide
|
|
307
|
+
})
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
case "3ds":
|
|
311
|
+
return new TDSLoader().parse(bytes.buffer, resourcePath);
|
|
312
|
+
default:
|
|
313
|
+
throw new Error(`Built-in conversion does not support ${format || extname(primaryPath)}.`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
function installNodeDom() {
|
|
317
|
+
if (typeof document !== "undefined" && typeof DOMParser !== "undefined") return;
|
|
318
|
+
const { JSDOM } = createRequire(import.meta.url)("jsdom");
|
|
319
|
+
const window = new JSDOM().window;
|
|
320
|
+
Object.assign(globalThis, {
|
|
321
|
+
document: window.document,
|
|
322
|
+
DOMParser: window.DOMParser,
|
|
323
|
+
HTMLImageElement: window.HTMLImageElement,
|
|
324
|
+
HTMLCanvasElement: window.HTMLCanvasElement,
|
|
325
|
+
Image: window.Image
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
function discardUnloadedTextures(root) {
|
|
329
|
+
root.traverse((object) => {
|
|
330
|
+
const mesh = object;
|
|
331
|
+
const materials = Array.isArray(mesh.material) ? mesh.material : mesh.material ? [mesh.material] : [];
|
|
332
|
+
for (const material of materials) {
|
|
333
|
+
const textured = material;
|
|
334
|
+
for (const slot of materialTextureSlots) {
|
|
335
|
+
const value = textured[slot];
|
|
336
|
+
if (!(value instanceof THREE.Texture)) continue;
|
|
337
|
+
const image = value.image;
|
|
338
|
+
if (image && (image.width ?? 0) > 0 && (image.height ?? 0) > 0) continue;
|
|
339
|
+
textured[slot] = null;
|
|
340
|
+
value.dispose();
|
|
341
|
+
}
|
|
342
|
+
material.needsUpdate = true;
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
async function validateConvertedGlb(bytes) {
|
|
347
|
+
const parsed = await new GLTFLoader().parseAsync(Uint8Array.from(bytes).buffer, "");
|
|
348
|
+
let renderable = false;
|
|
349
|
+
parsed.scene.traverse((object) => {
|
|
350
|
+
renderable ||= Boolean(object.isMesh || object.isPoints);
|
|
351
|
+
});
|
|
352
|
+
disposeObject(parsed.scene);
|
|
353
|
+
if (!renderable && parsed.animations.length === 0) {
|
|
354
|
+
throw new Error("Converted GLB contains neither renderable geometry nor animation clips.");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function installNodeFileReader() {
|
|
358
|
+
if (typeof FileReader !== "undefined") return;
|
|
359
|
+
class NodeFileReader {
|
|
360
|
+
result = null;
|
|
361
|
+
error = null;
|
|
362
|
+
onloadend = null;
|
|
363
|
+
onerror = null;
|
|
364
|
+
readAsArrayBuffer(blob) {
|
|
365
|
+
void blob.arrayBuffer().then(
|
|
366
|
+
(result) => {
|
|
367
|
+
this.result = result;
|
|
368
|
+
this.onloadend?.({ target: this });
|
|
369
|
+
},
|
|
370
|
+
(error) => {
|
|
371
|
+
this.error = error instanceof Error ? error : new Error(String(error));
|
|
372
|
+
this.onerror?.({ target: this });
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
readAsDataURL(blob) {
|
|
377
|
+
void blob.arrayBuffer().then((result) => {
|
|
378
|
+
this.result = `data:${blob.type || "application/octet-stream"};base64,${Buffer.from(result).toString("base64")}`;
|
|
379
|
+
this.onloadend?.({ target: this });
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
Object.assign(globalThis, { FileReader: NodeFileReader });
|
|
384
|
+
}
|
|
385
|
+
function disposeObject(root) {
|
|
386
|
+
root.traverse((object) => {
|
|
387
|
+
const renderable = object;
|
|
388
|
+
renderable.geometry?.dispose();
|
|
389
|
+
const materials = Array.isArray(renderable.material) ? renderable.material : renderable.material ? [renderable.material] : [];
|
|
390
|
+
for (const material of materials) {
|
|
391
|
+
for (const value of Object.values(material))
|
|
392
|
+
if (value instanceof THREE.Texture) value.dispose();
|
|
393
|
+
material.dispose();
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// serving/index.ts
|
|
399
|
+
var servingPlugins = (services) => {
|
|
400
|
+
services.registerModelConverter(threeModelConverter);
|
|
401
|
+
return [animationStampPlugin(services)];
|
|
402
|
+
};
|
|
403
|
+
export {
|
|
404
|
+
servingPlugins
|
|
405
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/editor-threejs",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.67",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -15,29 +15,137 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"src",
|
|
18
|
+
"serving",
|
|
19
|
+
"contributions",
|
|
20
|
+
"dist-node",
|
|
18
21
|
"LICENSE",
|
|
19
22
|
"NOTICE",
|
|
20
23
|
"LICENSE-APACHE"
|
|
21
24
|
],
|
|
22
25
|
"exports": {
|
|
23
26
|
"./package.json": "./package.json",
|
|
27
|
+
"./contributions/*": "./contributions/*",
|
|
24
28
|
"./*": {
|
|
25
29
|
"types": "./src/*.ts",
|
|
26
30
|
"default": "./src/*"
|
|
27
31
|
},
|
|
28
32
|
"./asset-parse-error": "./src/asset-parse-error.ts",
|
|
29
|
-
"./loader": "./src/loader.ts"
|
|
33
|
+
"./loader": "./src/loader.ts",
|
|
34
|
+
"./kit/animation/three-clips-subject": "./src/kit/animation/three-clips-subject.ts",
|
|
35
|
+
"./kit/asset-compare": "./src/kit/asset-compare.ts",
|
|
36
|
+
"./kit/asset-preview-command": "./src/kit/asset-preview-command.ts",
|
|
37
|
+
"./kit/asset-preview-framing": "./src/kit/asset-preview-framing.ts",
|
|
38
|
+
"./kit/asset-preview": "./src/kit/asset-preview.ts",
|
|
39
|
+
"./kit/asset-workflow/model-inspection": "./src/kit/asset-workflow/model-inspection.ts",
|
|
40
|
+
"./kit/authoring/component-instance-root": "./src/kit/authoring/component-instance-root.ts",
|
|
41
|
+
"./kit/authoring/design-time-settle": "./src/kit/authoring/design-time-settle.ts",
|
|
42
|
+
"./kit/authoring/live-object-transform": "./src/kit/authoring/live-object-transform.ts",
|
|
43
|
+
"./kit/authoring/object3d-document-session-registry": "./src/kit/authoring/object3d-document-session-registry.ts",
|
|
44
|
+
"./kit/authoring/object3d-document-session": "./src/kit/authoring/object3d-document-session.ts",
|
|
45
|
+
"./kit/authoring/quarks-particle-systems": "./src/kit/authoring/quarks-particle-systems.ts",
|
|
46
|
+
"./kit/authoring/shell-viewport-policy": "./src/kit/authoring/shell-viewport-policy.ts",
|
|
47
|
+
"./kit/authoring/source-object3d-authoring-adapter": "./src/kit/authoring/source-object3d-authoring-adapter.ts",
|
|
48
|
+
"./kit/authoring/three-projection-core": "./src/kit/authoring/three-projection-core.ts",
|
|
49
|
+
"./kit/authoring/viewport-pick-context": "./src/kit/authoring/viewport-pick-context.ts",
|
|
50
|
+
"./kit/authoring/viewport-raycast": "./src/kit/authoring/viewport-raycast.ts",
|
|
51
|
+
"./kit/authoring/world-hidden-viewport": "./src/kit/authoring/world-hidden-viewport.ts",
|
|
52
|
+
"./kit/camera-authoring": "./src/kit/camera-authoring.ts",
|
|
53
|
+
"./kit/components/CameraInfo": "./src/kit/components/CameraInfo.tsx",
|
|
54
|
+
"./kit/components/InspectorObjectPreview": "./src/kit/components/InspectorObjectPreview.tsx",
|
|
55
|
+
"./kit/components/Object3DDocumentToolbar": "./src/kit/components/Object3DDocumentToolbar.tsx",
|
|
56
|
+
"./kit/components/Object3DDocumentViewport": "./src/kit/components/Object3DDocumentViewport.tsx",
|
|
57
|
+
"./kit/components/StageHost": "./src/kit/components/StageHost.tsx",
|
|
58
|
+
"./kit/components/StageOverlays": "./src/kit/components/StageOverlays.tsx",
|
|
59
|
+
"./kit/components/StatsOverlay": "./src/kit/components/StatsOverlay.tsx",
|
|
60
|
+
"./kit/components/ToolObject3DPreview": "./src/kit/components/ToolObject3DPreview.tsx",
|
|
61
|
+
"./kit/components/ViewportFurniture": "./src/kit/components/ViewportFurniture.tsx",
|
|
62
|
+
"./kit/components/ViewportOverlay": "./src/kit/components/ViewportOverlay.tsx",
|
|
63
|
+
"./kit/components/ViewportShadingMenu": "./src/kit/components/ViewportShadingMenu.tsx",
|
|
64
|
+
"./kit/components/ViewportViewMenu": "./src/kit/components/ViewportViewMenu.tsx",
|
|
65
|
+
"./kit/components/asset-viewers/EntityModelDocument": "./src/kit/components/asset-viewers/EntityModelDocument.tsx",
|
|
66
|
+
"./kit/components/asset-viewers/EnvironmentAssetDocument": "./src/kit/components/asset-viewers/EnvironmentAssetDocument.tsx",
|
|
67
|
+
"./kit/components/asset-viewers/LiveModuleDocument": "./src/kit/components/asset-viewers/LiveModuleDocument.tsx",
|
|
68
|
+
"./kit/components/asset-viewers/LutAssetDocument": "./src/kit/components/asset-viewers/LutAssetDocument.tsx",
|
|
69
|
+
"./kit/components/asset-viewers/ModelAssetDocument": "./src/kit/components/asset-viewers/ModelAssetDocument.tsx",
|
|
70
|
+
"./kit/components/asset-viewers/Object3DPreview": "./src/kit/components/asset-viewers/Object3DPreview.tsx",
|
|
71
|
+
"./kit/components/asset-viewers/QuarksAssetDocument": "./src/kit/components/asset-viewers/QuarksAssetDocument.tsx",
|
|
72
|
+
"./kit/components/asset-viewers/ShaderAssetDocument": "./src/kit/components/asset-viewers/ShaderAssetDocument.tsx",
|
|
73
|
+
"./kit/components/asset-viewers/three-asset-viewers": "./src/kit/components/asset-viewers/three-asset-viewers.tsx",
|
|
74
|
+
"./kit/components/stage-keyboard": "./src/kit/components/stage-keyboard.tsx",
|
|
75
|
+
"./kit/components/stage-overlay-set": "./src/kit/components/stage-overlay-set.tsx",
|
|
76
|
+
"./kit/components/stage-presence-markers": "./src/kit/components/stage-presence-markers.ts",
|
|
77
|
+
"./kit/components/stage-transform-chrome": "./src/kit/components/stage-transform-chrome.ts",
|
|
78
|
+
"./kit/components/stage-transform-tools": "./src/kit/components/stage-transform-tools.tsx",
|
|
79
|
+
"./kit/components/standard-viewport-dressing": "./src/kit/components/standard-viewport-dressing.ts",
|
|
80
|
+
"./kit/components/world-root-binding": "./src/kit/components/world-root-binding.ts",
|
|
81
|
+
"./kit/constraint-helper": "./src/kit/constraint-helper.ts",
|
|
82
|
+
"./kit/editor-shell-store": "./src/kit/editor-shell-store.ts",
|
|
83
|
+
"./kit/editor-viewport": "./src/kit/editor-viewport.ts",
|
|
84
|
+
"./kit/entity-lod": "./src/kit/entity-lod.ts",
|
|
85
|
+
"./kit/entity-object": "./src/kit/entity-object.ts",
|
|
86
|
+
"./kit/hierarchy-mark-reader": "./src/kit/hierarchy-mark-reader.ts",
|
|
87
|
+
"./kit/instanced-presentation": "./src/kit/instanced-presentation.ts",
|
|
88
|
+
"./kit/live-module-source": "./src/kit/live-module-source.ts",
|
|
89
|
+
"./kit/model-thumbnail": "./src/kit/model-thumbnail.ts",
|
|
90
|
+
"./kit/projection/three": "./src/kit/projection/three.ts",
|
|
91
|
+
"./kit/reflection-probe-helper": "./src/kit/reflection-probe-helper.ts",
|
|
92
|
+
"./kit/scene-document-viewport": "./src/kit/scene-document-viewport.ts",
|
|
93
|
+
"./kit/scene-framing": "./src/kit/scene-framing.ts",
|
|
94
|
+
"./kit/scene-view-fog": "./src/kit/scene-view-fog.ts",
|
|
95
|
+
"./kit/spatial-handle-visuals": "./src/kit/spatial-handle-visuals.ts",
|
|
96
|
+
"./kit/stories/three-story-model": "./src/kit/stories/three-story-model.ts",
|
|
97
|
+
"./kit/three-canvas-render": "./src/kit/three-canvas-render.ts",
|
|
98
|
+
"./kit/three-hierarchy-row-media": "./src/kit/three-hierarchy-row-media.ts",
|
|
99
|
+
"./kit/three-inspection-media": "./src/kit/three-inspection-media.ts",
|
|
100
|
+
"./kit/three-integration": "./src/kit/three-integration.ts",
|
|
101
|
+
"./kit/three-state": "./src/kit/three-state.ts",
|
|
102
|
+
"./kit/three-viewport/bone-selection-highlight": "./src/kit/three-viewport/bone-selection-highlight.ts",
|
|
103
|
+
"./kit/three-viewport/camera-fit": "./src/kit/three-viewport/camera-fit.ts",
|
|
104
|
+
"./kit/three-viewport/interactive-renderer": "./src/kit/three-viewport/interactive-renderer.ts",
|
|
105
|
+
"./kit/three-viewport/selection-brackets": "./src/kit/three-viewport/selection-brackets.ts",
|
|
106
|
+
"./kit/three-viewport/selection-outline": "./src/kit/three-viewport/selection-outline.ts",
|
|
107
|
+
"./kit/three-viewport/skeleton-helper": "./src/kit/three-viewport/skeleton-helper.ts",
|
|
108
|
+
"./kit/three-viewport/source-color": "./src/kit/three-viewport/source-color.ts",
|
|
109
|
+
"./kit/three-viewport/studio-environment": "./src/kit/three-viewport/studio-environment.ts",
|
|
110
|
+
"./kit/trigger-volume-helper": "./src/kit/trigger-volume-helper.ts",
|
|
111
|
+
"./kit/viewport-actions": "./src/kit/viewport-actions.ts",
|
|
112
|
+
"./kit/viewport-authoring-policy": "./src/kit/viewport-authoring-policy.ts",
|
|
113
|
+
"./kit/viewport-commands": "./src/kit/viewport-commands.ts",
|
|
114
|
+
"./kit/viewport-hotkeys": "./src/kit/viewport-hotkeys.ts",
|
|
115
|
+
"./kit/viewport-shading-boundary": "./src/kit/viewport-shading-boundary.ts",
|
|
116
|
+
"./kit/viewport-status-facet": "./src/kit/viewport-status-facet.ts"
|
|
30
117
|
},
|
|
31
118
|
"peerDependencies": {
|
|
32
|
-
"three": "^0.180.0"
|
|
119
|
+
"three": "^0.180.0",
|
|
120
|
+
"vite": "^6.4.3",
|
|
121
|
+
"react": "^19.0.0",
|
|
122
|
+
"react-dom": "^19.0.0"
|
|
33
123
|
},
|
|
34
124
|
"scripts": {
|
|
125
|
+
"build": "node scripts/build-serving.mjs",
|
|
126
|
+
"prepack": "npm run build",
|
|
35
127
|
"typecheck": "tsc -p tsconfig.json"
|
|
36
128
|
},
|
|
129
|
+
"vgai": {
|
|
130
|
+
"contributions": [
|
|
131
|
+
"./contributions/three-integration.service.ts",
|
|
132
|
+
"./contributions/animation-mixers.service.ts",
|
|
133
|
+
"./contributions/animation-timeline.utility.tsx"
|
|
134
|
+
],
|
|
135
|
+
"serving": "./dist-node/serving.mjs"
|
|
136
|
+
},
|
|
37
137
|
"dependencies": {
|
|
38
|
-
"@volter/editor-project": "0.5.
|
|
138
|
+
"@volter/editor-project": "0.5.67",
|
|
39
139
|
"@sparkjsdev/spark": "^2.1.0",
|
|
40
140
|
"three.quarks": "^0.16.0",
|
|
41
|
-
"zod": "^4.3.6"
|
|
141
|
+
"zod": "^4.3.6",
|
|
142
|
+
"typescript": "5.9.3",
|
|
143
|
+
"@volter/editor-sdk": "0.5.67",
|
|
144
|
+
"postprocessing": "6.38.3",
|
|
145
|
+
"quarks.core": "0.16.0",
|
|
146
|
+
"@fortawesome/free-solid-svg-icons": "^7.2.0"
|
|
147
|
+
},
|
|
148
|
+
"devDependencies": {
|
|
149
|
+
"esbuild": "0.25.12"
|
|
42
150
|
}
|
|
43
151
|
}
|