@jfk-solutions/demo3d-file-format 1.8.0 → 1.10.0
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/README.md +225 -0
- package/dist/examples/export-embedded-viewer-standalone.html +1 -1
- package/dist/examples/three-render-smoke-standalone.html +295 -231
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/model.d.ts +1 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +6 -0
- package/dist/model.js.map +1 -1
- package/dist/raw3d-animation.d.ts +63 -0
- package/dist/raw3d-animation.d.ts.map +1 -0
- package/dist/raw3d-animation.js +200 -0
- package/dist/raw3d-animation.js.map +1 -0
- package/dist/raw3d-effects.d.ts +66 -0
- package/dist/raw3d-effects.d.ts.map +1 -0
- package/dist/raw3d-effects.js +172 -0
- package/dist/raw3d-effects.js.map +1 -0
- package/dist/raw3d-skinning.d.ts +8 -0
- package/dist/raw3d-skinning.d.ts.map +1 -0
- package/dist/raw3d-skinning.js +37 -0
- package/dist/raw3d-skinning.js.map +1 -0
- package/dist/raw3d.d.ts +77 -2
- package/dist/raw3d.d.ts.map +1 -1
- package/dist/raw3d.js +103 -7
- package/dist/raw3d.js.map +1 -1
- package/dist/rigid-interpolation.d.ts +16 -0
- package/dist/rigid-interpolation.d.ts.map +1 -0
- package/dist/rigid-interpolation.js +52 -0
- package/dist/rigid-interpolation.js.map +1 -0
- package/dist/three/backend.d.ts +13 -0
- package/dist/three/backend.d.ts.map +1 -0
- package/dist/three/backend.js +9 -0
- package/dist/three/backend.js.map +1 -0
- package/dist/three/effects.d.ts +7 -0
- package/dist/three/effects.d.ts.map +1 -0
- package/dist/three/effects.js +127 -0
- package/dist/three/effects.js.map +1 -0
- package/dist/three/index.d.ts +2 -1
- package/dist/three/index.d.ts.map +1 -1
- package/dist/three/index.js +72 -14
- package/dist/three/index.js.map +1 -1
- package/dist/three/native-lighting.d.ts +5 -0
- package/dist/three/native-lighting.d.ts.map +1 -0
- package/dist/three/native-lighting.js +86 -0
- package/dist/three/native-lighting.js.map +1 -0
- package/dist/three/parallax.d.ts +5 -0
- package/dist/three/parallax.d.ts.map +1 -0
- package/dist/three/parallax.js +63 -0
- package/dist/three/parallax.js.map +1 -0
- package/dist/three/raw3d.d.ts +25 -0
- package/dist/three/raw3d.d.ts.map +1 -1
- package/dist/three/raw3d.js +404 -16
- package/dist/three/raw3d.js.map +1 -1
- package/dist/three/renderer.d.ts.map +1 -1
- package/dist/three/renderer.js +3 -0
- package/dist/three/renderer.js.map +1 -1
- package/dist/three/skinning.d.ts +11 -0
- package/dist/three/skinning.d.ts.map +1 -0
- package/dist/three/skinning.js +92 -0
- package/dist/three/skinning.js.map +1 -0
- package/dist/three/tsl.d.ts +60 -0
- package/dist/three/tsl.d.ts.map +1 -0
- package/dist/three/tsl.js +3 -0
- package/dist/three/tsl.js.map +1 -0
- package/dist/three/webgpu-native.d.ts +3 -0
- package/dist/three/webgpu-native.d.ts.map +1 -0
- package/dist/three/webgpu-native.js +58 -0
- package/dist/three/webgpu-native.js.map +1 -0
- package/dist/three/webgpu-relief.d.ts +3 -0
- package/dist/three/webgpu-relief.d.ts.map +1 -0
- package/dist/three/webgpu-relief.js +61 -0
- package/dist/three/webgpu-relief.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,6 +58,217 @@ submeshes, and shadow flags.
|
|
|
58
58
|
|
|
59
59
|
Runtime code has no production dependencies and uses browser APIs only. ZIP method `8` entries are decompressed with `DecompressionStream("deflate-raw")`.
|
|
60
60
|
|
|
61
|
+
## RAW3D animation without a renderer
|
|
62
|
+
|
|
63
|
+
The root package has no Three.js dependency. It reads animation channels and
|
|
64
|
+
samples native node state independently of any renderer, UI, or playback clock:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { parseRaw3D } from "@jfk-solutions/demo3d-file-format";
|
|
68
|
+
|
|
69
|
+
const parsed = await parseRaw3D(await file.arrayBuffer());
|
|
70
|
+
const animation = parsed.model.animation; // Lazy, cached typed Updates parser.
|
|
71
|
+
console.log(animation.duration, animation.tracks, animation.warnings);
|
|
72
|
+
const states = animation.sample(1.25); // Absolute simulation seconds.
|
|
73
|
+
const node = animation.sampleNode(0, 1.25);
|
|
74
|
+
console.log(node.location, node.quaternion, node.layerIndex);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Supported tracks include position, rotation, scale, own-geometry visibility,
|
|
78
|
+
deletion, parent, mesh, layer, interaction mode, highlight, optimization metadata,
|
|
79
|
+
and material diffuse ARGB, texture offsets/scales, reflectivity, transparency,
|
|
80
|
+
luminosity, normal scale, and point size. Unknown tracks remain available through
|
|
81
|
+
their original XML and produce warnings; their timestamps still contribute to
|
|
82
|
+
the clip duration. Reading metadata does not execute its native behavior.
|
|
83
|
+
Invalid supported tracks fail explicitly. Duplicate key times select the last
|
|
84
|
+
value, and seeking before a first key restores the node's initial state.
|
|
85
|
+
|
|
86
|
+
`Raw3DInterpolationMode` matches the Emulate3D 2026 enum: `Default=0`, `None=1`,
|
|
87
|
+
`Linear=2`, `DualQuaternion=3`. `None` holds the previous key; `Linear` interpolates
|
|
88
|
+
numeric channels, with shortest-path angle interpolation. This library treats
|
|
89
|
+
`Default` as linear. Discrete properties and ARGB colors switch at key times.
|
|
90
|
+
|
|
91
|
+
`DualQuaternion` couples position and orientation using normalized dual-quaternion
|
|
92
|
+
linear blending (DLB). Scale stays separate. `quaternion` and `rotation` describe
|
|
93
|
+
the same sampled orientation in native coordinates. Transform keys are evaluated
|
|
94
|
+
on the union of the node's position/rotation key times. This original implementation
|
|
95
|
+
is derived from the mathematical representation and normalization in
|
|
96
|
+
[Kavan et al., Dual Quaternions for Rigid Transformation Blending (2006)](https://users.cs.utah.edu/~ladislav/kavan06dual/kavan06dual.pdf).
|
|
97
|
+
DLB follows a rigid screw path but is not constant-speed ScLERP. Exact parity
|
|
98
|
+
with Demo3D's interpolation variant/default policy has not yet been established.
|
|
99
|
+
No vendor or paper implementation code is copied.
|
|
100
|
+
|
|
101
|
+
Native node visibility, interpolation mode, highlight, user data, owner,
|
|
102
|
+
decal/billboard flags, material luminosity/offsets/point size, and scene floor,
|
|
103
|
+
lighting, ambient color and quality properties have typed accessors. Unknown XML
|
|
104
|
+
is still retained; these accessors do not imply full native shader, billboard,
|
|
105
|
+
decal, floor, interaction, or scripting behavior.
|
|
106
|
+
|
|
107
|
+
### Optional Three.js playback
|
|
108
|
+
|
|
109
|
+
Only the `/three` entry point binds the sampled state to Three.js objects:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { createRaw3DThreePlayback } from "@jfk-solutions/demo3d-file-format/three";
|
|
113
|
+
|
|
114
|
+
const playback = await createRaw3DThreePlayback(parsed, { three: THREE });
|
|
115
|
+
scene.add(playback.group);
|
|
116
|
+
playback.seek(1.25);
|
|
117
|
+
renderer.render(scene, camera);
|
|
118
|
+
// The application owns its animation clock, play/pause, speed and looping.
|
|
119
|
+
scene.remove(playback.group);
|
|
120
|
+
playback.dispose();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The binding applies transforms, visibility, deletion, parenting, mesh swaps,
|
|
124
|
+
layer-material fallback, and supported material changes. It preserves explicit
|
|
125
|
+
node materials when a layer changes and isolates animated materials between
|
|
126
|
+
nodes. Structural groups stay enabled when only their own geometry is hidden.
|
|
127
|
+
Retired mesh samples are released, and `dispose()` releases owned GPU resources.
|
|
128
|
+
Playback does not run simulation scripts, physics, or PLC connections. Both
|
|
129
|
+
native bone/weight buffers and baked deforming mesh updates are supported.
|
|
130
|
+
|
|
131
|
+
The demo and generated standalone viewer offer Play/Pause and an absolute-time
|
|
132
|
+
slider for animated RAW3D files. Embedding the original RAW3D retains animation;
|
|
133
|
+
the source-protected Three.js snapshot export remains a static snapshot.
|
|
134
|
+
|
|
135
|
+
### Native effects, surfaces and skinning
|
|
136
|
+
|
|
137
|
+
Use `animation.sampleFrame(time)` for a complete renderer-independent frame:
|
|
138
|
+
`nodes`, `lights`, `buttons`, and `scene`. The same current frame is available as
|
|
139
|
+
`playback.state` after `seek()`. Extended tracks and original XML are exposed by
|
|
140
|
+
`animation.effects.tracks`.
|
|
141
|
+
|
|
142
|
+
- Material `Texture`, `NormalMap`/`NormalTexture` references switch discretely,
|
|
143
|
+
including clearing a texture with a negative index. Referenced archive textures
|
|
144
|
+
are preloaded even when they are only used by later animation keys. Color and
|
|
145
|
+
normal textures are isolated per animated node and restored on backward seeks.
|
|
146
|
+
- Native light channels include `LightType`, `LightEnabled`, `LightMaterial`,
|
|
147
|
+
`LightAR`, `LightAC`, `LightAL`, `LightAQ`, `LightSF`, `LightSIA`, `LightSOA`, and
|
|
148
|
+
`LightCS`. Range, constant/linear/quadratic attenuation, total inner/outer cone
|
|
149
|
+
angles, falloff and shadow flags are applied. WebGL hooks and the TSL node backend implement
|
|
150
|
+
the distance/cone equations described in [Microsoft's Direct3D lighting
|
|
151
|
+
documentation](https://learn.microsoft.com/en-us/windows/win32/direct3d9/attenuation-and-spotlight-factor).
|
|
152
|
+
`evaluateRaw3DLightAttenuation()` exposes the same calculation without Three.js.
|
|
153
|
+
Shadow rendering still requires the host renderer's shadow map to be enabled.
|
|
154
|
+
- `SceneShowDefaultFloor`, `SceneAllowTeleportOnDefaultFloor`,
|
|
155
|
+
`SceneUseDefaultLighting`, and `ALR`/`ALG`/`ALB` update the sampled scene.
|
|
156
|
+
The Three binding provides ambient/default light and a finite floor preview on
|
|
157
|
+
the recorded plane. Teleport permission is metadata; browser navigation is a
|
|
158
|
+
host concern. Host-added lighting remains under host control.
|
|
159
|
+
- Native button visibility and checked-state channels are sampled and displayed
|
|
160
|
+
by the demo. Their original native serializer names `UpdateUIVisible` and
|
|
161
|
+
`UpdateUIChecked`, as well as `UIVisible`/`UIChecked`, are accepted. Displayed
|
|
162
|
+
buttons are read-only; the library does not execute their model actions.
|
|
163
|
+
- Unambiguous `UserData`/`ClientOwner` string keys are sampled as metadata. The
|
|
164
|
+
native serializer joins string arrays with spaces without escaping boundaries.
|
|
165
|
+
A single key may contain spaces; multi-key values with ambiguous boundaries
|
|
166
|
+
remain in XML with `RAW3D_STRING_KEYS_AMBIGUOUS` instead of being guessed.
|
|
167
|
+
- The native `Default`, `FlatText`, and `PointCloud` material shader modes map to
|
|
168
|
+
lit, unlit, and vertex-colored point rendering. Packed ARGB/byte/short vertex
|
|
169
|
+
attributes retain their native strides. RAW3D material `A` is opacity; the
|
|
170
|
+
public `transparency` property is its complement. This corrects older builds
|
|
171
|
+
which inverted partially transparent native materials.
|
|
172
|
+
- Billboards orient their own drawable toward the render camera while leaving
|
|
173
|
+
the node hierarchy intact. Decal flags apply depth bias and suppress depth
|
|
174
|
+
writes on the provided surface geometry; no projection onto an unrelated mesh
|
|
175
|
+
is invented.
|
|
176
|
+
- Mesh `Bones` expose driving scene-node references, bind offsets and native
|
|
177
|
+
skin index/weight buffer references. `decodeRaw3DSkinInfluences()` validates and
|
|
178
|
+
normalizes weights without a renderer. The Three adapter constructs GPU
|
|
179
|
+
`SkinnedMesh`/`Skeleton` bindings for up to four influences per vertex. Larger
|
|
180
|
+
influence sets use CPU skinning with positions, normals and tangents; no
|
|
181
|
+
weights are discarded. Unweighted vertices retain their mesh position.
|
|
182
|
+
|
|
183
|
+
Native channel names, bone fields and shader enums have a checked-in fixture
|
|
184
|
+
generated by the installed Emulate3D 2026 SDK serializer. To regenerate it on
|
|
185
|
+
Windows, run `./scripts/generate-native-feature-fixture.ps1`; other platforms can
|
|
186
|
+
run the tests using the existing fixture without that proprietary SDK.
|
|
187
|
+
Synthetic rigs exercise GPU/CPU deformation, bind offsets and reversible seeks.
|
|
188
|
+
Comparison against a captured native skinned person remains a separate parity
|
|
189
|
+
check; the current Bauhaus recording contains baked human geometry.
|
|
190
|
+
|
|
191
|
+
### Lossless strings and external resources
|
|
192
|
+
|
|
193
|
+
Native string arrays lose their boundaries when values containing spaces are
|
|
194
|
+
joined into a single attribute. Supply authoritative keys from a sidecar through
|
|
195
|
+
the renderer-independent parser option:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
const parsed = await parseRaw3D(bytes, {
|
|
199
|
+
resolveStringKeys: ({ nodeIndex, property, times, encoded, xml }) => {
|
|
200
|
+
return sidecar.lookup(nodeIndex, property, times); // string[] or undefined
|
|
201
|
+
},
|
|
202
|
+
resolveResource: async path => resources.get(path) // Uint8Array or undefined
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The resolver runs for string tracks and must return one string per timestamp,
|
|
207
|
+
including empty values. Incorrect lengths/types fail explicitly. Archive entries
|
|
208
|
+
take precedence over `resolveResource`; no filesystem/network request is made
|
|
209
|
+
automatically. A library-side extension also accepts `<Values><Value>...</Value>
|
|
210
|
+
...</Values>` children, or `ValueEncoding="json"` with a JSON array in `Value`.
|
|
211
|
+
These extensions are explicit conventions for this reader, not a claim that the
|
|
212
|
+
native serializer emits them. The original XML stays available. Missing
|
|
213
|
+
authoritative data still produces `RAW3D_STRING_KEYS_AMBIGUOUS`; impossible
|
|
214
|
+
boundaries are not guessed.
|
|
215
|
+
|
|
216
|
+
`parsed.model.streamableTextures` exposes native index, ID, name, dimensions,
|
|
217
|
+
path and any archived/resolved image bytes. Material `StreamableTexture` selects
|
|
218
|
+
the corresponding image. For video, a live camera or a recorded frame sequence,
|
|
219
|
+
provide Three.js textures and use asynchronous seeking:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const playback = await createRaw3DThreePlayback(parsed, {
|
|
223
|
+
three: THREE,
|
|
224
|
+
resolveStreamTexture: async ({ index, time, source, signal }) => {
|
|
225
|
+
return frames.textureAt(index, time, signal); // Texture or undefined
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
await playback.seekAsync(2.5); // false if superseded by a newer seek
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Resolvers receive clip time, stream metadata and an abort signal. A newer seek,
|
|
232
|
+
synchronous seek, or disposal cancels pending requests; stale responses never
|
|
233
|
+
replace newer imagery. Returned textures remain caller-owned. The player owns
|
|
234
|
+
only its clones. Returning `undefined` restores the archived fallback or clears
|
|
235
|
+
the unavailable frame and reports a warning. A synchronous `seek()` retains the
|
|
236
|
+
currently resolved stream image; use `seekAsync()` for frame-accurate seeking.
|
|
237
|
+
Missing video frames still need an external source; a file reader cannot
|
|
238
|
+
reconstruct imagery that was never recorded. No URL or camera is opened without
|
|
239
|
+
an explicit host resolver.
|
|
240
|
+
|
|
241
|
+
### Relief shading and the node renderer
|
|
242
|
+
|
|
243
|
+
`NormalDepth` drives layered parallax/relief UV ray marching with 32 layers and
|
|
244
|
+
five binary refinements in both the WebGL shader and TSL material paths. Heights
|
|
245
|
+
are read from the normal image's alpha channel by default; select a different
|
|
246
|
+
packed channel with `parallaxHeightChannel: "r" | "g" | "b" | "a"`. Opaque alpha
|
|
247
|
+
represents a flat top surface. Color and normal samples share the relief offset,
|
|
248
|
+
and animated depth updates are reversible. Depth controls texture-coordinate
|
|
249
|
+
displacement; this does not add geometry or alter silhouettes. A normal image
|
|
250
|
+
without height data cannot supply missing surface depth by itself. The height
|
|
251
|
+
packing and scale may need adjustment for a particular native export.
|
|
252
|
+
|
|
253
|
+
The renderer factory automatically registers native point/spot light nodes and
|
|
254
|
+
node materials with `WebGPURenderer`. Native attenuation, range and cone falloff
|
|
255
|
+
are calculated through TSL, which supports both the WebGPU and node-renderer
|
|
256
|
+
WebGL backends. Existing lights and materials outside the native binding keep
|
|
257
|
+
their standard behavior. For a manually constructed renderer, configure it
|
|
258
|
+
before creating RAW3D groups:
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import * as THREE from "three/webgpu";
|
|
262
|
+
import { configureRaw3DWebGPURenderer } from "@jfk-solutions/demo3d-file-format/three";
|
|
263
|
+
await configureRaw3DWebGPURenderer(renderer, THREE);
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Unbundled hosts must map `three/tsl` alongside `three/webgpu` to their matching
|
|
267
|
+
Three.js release. Node rendering code is loaded on demand; importing the parser
|
|
268
|
+
still loads no renderer. Browser tests compare visible relief and attenuation
|
|
269
|
+
changes plus backward restoration under WebGL and the TSL WebGL backend. The
|
|
270
|
+
hardware WebGPU case runs only when an adapter is available.
|
|
271
|
+
|
|
61
272
|
The default single-pass XML parser builds the Demo3D object tree directly, avoiding the time and memory cost of an intermediate browser DOM. For unusual XML inputs, callers can opt into the browser parser or inject another DOM implementation:
|
|
62
273
|
|
|
63
274
|
```ts
|
|
@@ -175,6 +386,20 @@ default, including inherited child-layer visibility. Set
|
|
|
175
386
|
`includeHiddenLayers: true` only when a tool needs to inspect hidden project
|
|
176
387
|
content.
|
|
177
388
|
|
|
389
|
+
Editable Demo3D triangle meshes support the native `Position`, `PositionColor`,
|
|
390
|
+
`PositionTexture`, `PositionNormal`, `PositionNormalColor`,
|
|
391
|
+
`PositionNormalTexture`, and `PositionNormalTextureTangent` vertex layouts.
|
|
392
|
+
Packed ARGB vertex colors retain alpha and enable vertex-color materials without
|
|
393
|
+
altering materials shared by uncolored geometry. Tangents retain their fourth
|
|
394
|
+
component and change handedness when converted to Three.js coordinates. Meshes
|
|
395
|
+
without stored normals receive computed normals. These layouts follow the
|
|
396
|
+
native `Demo3D.Raw.VertexBuffer` attribute definitions; runtime-generated C#
|
|
397
|
+
geometry still needs a native RAW3D recording rather than script execution.
|
|
398
|
+
|
|
399
|
+
Saved `NormalTexture`/`NormalTextureReference` material references bind normal
|
|
400
|
+
maps alongside color textures. Normal maps use a separate linear-data texture
|
|
401
|
+
cache so a shared image used as color does not acquire the wrong color space.
|
|
402
|
+
|
|
178
403
|
### WebGPU With WebGL Fallback
|
|
179
404
|
|
|
180
405
|
Tools can lazily select a canvas renderer before creating the Demo3D scene. The
|