@anvpx/motion-scenes 0.1.0 → 0.1.1
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/dist/custom.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isAbsolute, posix, relative, resolve } from "node:path";
|
|
2
2
|
import { SceneEntryBaseSchema, } from "@anvpx/motion-schema";
|
|
3
3
|
import { rootElement, safePadding } from "./define-scene.js";
|
|
4
|
+
import { isSharedModulePath } from "./runtime-files.js";
|
|
4
5
|
/** The storyboard `type` that means "the author wrote this scene". */
|
|
5
6
|
export const CUSTOM_SCENE_TYPE = "custom";
|
|
6
7
|
/** The bare specifiers a scene script may import; everything else must be a relative path. */
|
|
@@ -77,6 +78,11 @@ export const readRelativeClosure = async (entryJs, read) => {
|
|
|
77
78
|
for (const specifier of scan.escaping)
|
|
78
79
|
escaping.add(specifier);
|
|
79
80
|
for (const specifier of scan.paths) {
|
|
81
|
+
// Shared modules are virtual build outputs, never reads from the source
|
|
82
|
+
// filesystem. Resolve from the same scenes/<id>/ location used by emit.
|
|
83
|
+
const emitted = posix.normalize(posix.join("scenes/custom", item.base, specifier));
|
|
84
|
+
if (isSharedModulePath(emitted))
|
|
85
|
+
continue;
|
|
80
86
|
const path = resolveRelative(item.base, specifier);
|
|
81
87
|
if (path === undefined) {
|
|
82
88
|
escaping.add(specifier);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { clamp01, ease } from "./easing.js";
|
|
2
|
+
/**
|
|
3
|
+
* Normalized interval in seconds. A zero duration is an instantaneous cut;
|
|
4
|
+
* negative durations are invalid. No prior samples or DOM state are read.
|
|
5
|
+
* @param {number} time
|
|
6
|
+
* @param {number} start
|
|
7
|
+
* @param {number} duration
|
|
8
|
+
*/
|
|
9
|
+
export declare const progress: (time: number, start: number, duration: number) => number;
|
|
10
|
+
/** Numeric interpolation; amount may overshoot for spring or anticipation.
|
|
11
|
+
* @param {number} from
|
|
12
|
+
* @param {number} to
|
|
13
|
+
* @param {number} amount
|
|
14
|
+
*/
|
|
15
|
+
export declare const interpolate: (from: number, to: number, amount: number) => number;
|
|
16
|
+
/** Start time for an item. A negative step expresses a reversed order.
|
|
17
|
+
* @param {number} index non-negative integer
|
|
18
|
+
* @param {number} step seconds between items
|
|
19
|
+
* @param {number} [start=0] first item's time
|
|
20
|
+
*/
|
|
21
|
+
export declare const stagger: (index: number, step: number, start?: number) => number;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
// Style-neutral authoring helpers. Every sample depends only on its inputs.
|
|
3
|
+
export { clamp01, ease } from "./easing.js";
|
|
4
|
+
/** @param {number[]} values */
|
|
5
|
+
const finite = (...values) => {
|
|
6
|
+
if (!values.every(Number.isFinite))
|
|
7
|
+
throw new RangeError("composition inputs must be finite");
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Normalized interval in seconds. A zero duration is an instantaneous cut;
|
|
11
|
+
* negative durations are invalid. No prior samples or DOM state are read.
|
|
12
|
+
* @param {number} time
|
|
13
|
+
* @param {number} start
|
|
14
|
+
* @param {number} duration
|
|
15
|
+
*/
|
|
16
|
+
export const progress = (time, start, duration) => {
|
|
17
|
+
finite(time, start, duration);
|
|
18
|
+
if (duration < 0)
|
|
19
|
+
throw new RangeError("duration must be non-negative");
|
|
20
|
+
if (duration === 0)
|
|
21
|
+
return time < start ? 0 : 1;
|
|
22
|
+
return Math.max(0, Math.min(1, (time - start) / duration));
|
|
23
|
+
};
|
|
24
|
+
/** Numeric interpolation; amount may overshoot for spring or anticipation.
|
|
25
|
+
* @param {number} from
|
|
26
|
+
* @param {number} to
|
|
27
|
+
* @param {number} amount
|
|
28
|
+
*/
|
|
29
|
+
export const interpolate = (from, to, amount) => {
|
|
30
|
+
finite(from, to, amount);
|
|
31
|
+
return from + (to - from) * amount;
|
|
32
|
+
};
|
|
33
|
+
/** Start time for an item. A negative step expresses a reversed order.
|
|
34
|
+
* @param {number} index non-negative integer
|
|
35
|
+
* @param {number} step seconds between items
|
|
36
|
+
* @param {number} [start=0] first item's time
|
|
37
|
+
*/
|
|
38
|
+
export const stagger = (index, step, start = 0) => {
|
|
39
|
+
if (!Number.isInteger(index) || index < 0)
|
|
40
|
+
throw new RangeError("index must be a non-negative integer");
|
|
41
|
+
finite(step, start);
|
|
42
|
+
return start + index * step;
|
|
43
|
+
};
|
package/dist/runtime-files.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
/** True only for a browser module that this package emits; does not read disk. */
|
|
2
|
+
export declare const isSharedModulePath: (path: string) => boolean;
|
|
1
3
|
/** Shared browser modules; the build emits them once under `runtime/` and `shared/`. */
|
|
2
4
|
export declare const runtimeFiles: () => Map<string, string>;
|
package/dist/runtime-files.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { readText } from "./text-file.js";
|
|
2
|
-
const RUNTIME_MODULES = ["easing.js", "timeline.js", "mount.js"];
|
|
2
|
+
const RUNTIME_MODULES = ["easing.js", "timeline.js", "mount.js", "compose.js"];
|
|
3
3
|
/** Pure helpers shared with emit time; they import `../runtime/easing.js`, so they sit beside it. */
|
|
4
4
|
const SHARED_MODULES = ["motion.js", "format.js"];
|
|
5
|
+
/** True only for a browser module that this package emits; does not read disk. */
|
|
6
|
+
export const isSharedModulePath = (path) => RUNTIME_MODULES.some((name) => path === `runtime/${name}`) ||
|
|
7
|
+
SHARED_MODULES.some((name) => path === `shared/${name}`);
|
|
5
8
|
/** Shared browser modules; the build emits them once under `runtime/` and `shared/`. */
|
|
6
9
|
export const runtimeFiles = () => new Map([
|
|
7
10
|
...RUNTIME_MODULES.map((name) => [
|
|
@@ -32,6 +32,7 @@ const copy = (props) => {
|
|
|
32
32
|
};
|
|
33
33
|
const render = (props) => {
|
|
34
34
|
const data = [
|
|
35
|
+
`data-model="${esc(props.model ?? "knot")}"`,
|
|
35
36
|
`data-post="${esc(props.post)}"`,
|
|
36
37
|
`data-light="${esc(props.light)}"`,
|
|
37
38
|
`data-material="${esc(props.material)}"`,
|
|
@@ -45,7 +46,7 @@ export const scene3dScene = defineScene({
|
|
|
45
46
|
type: "scene3d",
|
|
46
47
|
configSchema,
|
|
47
48
|
meta: {
|
|
48
|
-
purpose: "WebGL diorama (vendored three.js): post, light, material, environment presets; flat 2D canvas fallback without WebGL. 3D output is machine+GPU stable, not portable.",
|
|
49
|
+
purpose: "WebGL diorama (vendored three.js): post, light, material, environment presets; model presets knot|gem|sphere|torus; flat 2D canvas fallback without WebGL. 3D output is machine+GPU stable, not portable.",
|
|
49
50
|
example: { title: "Orbit" },
|
|
50
51
|
},
|
|
51
52
|
style: readText("./style.css", import.meta.url),
|
|
@@ -43,6 +43,25 @@ const MATERIAL = {
|
|
|
43
43
|
metal: { roughness: 0.3, metalness: 1, emissiveIntensity: 0 },
|
|
44
44
|
emissive: { roughness: 0.45, metalness: 0, emissiveIntensity: 1.6 },
|
|
45
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* Hero geometry per `model` preset. These are procedural shapes, not loaded
|
|
48
|
+
* GLB files: the scene stays offline and deterministic. `gem` is a faceted
|
|
49
|
+
* low-poly stone; unknown names fall back to the knot.
|
|
50
|
+
* @param {string} name
|
|
51
|
+
* @returns {any}
|
|
52
|
+
*/
|
|
53
|
+
const modelGeometry = (name) => {
|
|
54
|
+
switch (name) {
|
|
55
|
+
case "gem":
|
|
56
|
+
return new THREE.OctahedronGeometry(1.28, 0);
|
|
57
|
+
case "sphere":
|
|
58
|
+
return new THREE.SphereGeometry(0.95, 48, 32);
|
|
59
|
+
case "torus":
|
|
60
|
+
return new THREE.TorusGeometry(0.95, 0.28, 32, 96);
|
|
61
|
+
default:
|
|
62
|
+
return new THREE.TorusKnotGeometry(0.82, 0.27, 160, 32);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
46
65
|
/**
|
|
47
66
|
* @param {Record<string, any>} table
|
|
48
67
|
* @param {string | undefined} name
|
|
@@ -241,7 +260,7 @@ const flatStage = (canvas, presets, duration) => {
|
|
|
241
260
|
* library) returns null so the caller falls back to the 2D diorama instead of a black frame.
|
|
242
261
|
* @param {HTMLCanvasElement} canvas
|
|
243
262
|
* @param {HTMLElement} root
|
|
244
|
-
* @param {{ post: any, light: any, material: any, env: any }} presets
|
|
263
|
+
* @param {{ post: any, light: any, material: any, model?: string, env: any }} presets
|
|
245
264
|
* @param {number} duration
|
|
246
265
|
*/
|
|
247
266
|
const glStage = (canvas, root, presets, duration) => {
|
|
@@ -293,14 +312,17 @@ const glStage = (canvas, root, presets, duration) => {
|
|
|
293
312
|
floor.receiveShadow = true;
|
|
294
313
|
scene.add(floor);
|
|
295
314
|
const surface = presets.material;
|
|
315
|
+
const modelName = presets.model ?? "knot";
|
|
316
|
+
const geometry = modelGeometry(modelName);
|
|
296
317
|
const heroMaterial = new THREE.MeshStandardMaterial({
|
|
297
318
|
color: new THREE.Color(accent),
|
|
298
319
|
roughness: surface.roughness,
|
|
299
320
|
metalness: surface.metalness,
|
|
300
321
|
emissive: new THREE.Color(accent2),
|
|
301
322
|
emissiveIntensity: surface.emissiveIntensity * 0.35,
|
|
323
|
+
flatShading: modelName === "gem",
|
|
302
324
|
});
|
|
303
|
-
const hero = new THREE.Mesh(
|
|
325
|
+
const hero = new THREE.Mesh(geometry, heroMaterial);
|
|
304
326
|
hero.position.y = 0.12;
|
|
305
327
|
hero.castShadow = true;
|
|
306
328
|
scene.add(hero);
|
|
@@ -386,6 +408,7 @@ export function createScene(root, config, ctx) {
|
|
|
386
408
|
post: pick(POST, box?.dataset.post) ?? POST.cinematic,
|
|
387
409
|
light: pick(LIGHT, box?.dataset.light) ?? LIGHT.studio,
|
|
388
410
|
material: pick(MATERIAL, box?.dataset.material) ?? MATERIAL.clay,
|
|
411
|
+
model: box?.dataset.model ?? "knot",
|
|
389
412
|
env,
|
|
390
413
|
bg: env.bg,
|
|
391
414
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anvpx/motion-scenes",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Scene registry and browser renderer for @anvpx/motion storyboards.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "anvpx",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"dist/**/*.css"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@anvpx/motion-assets": "0.1.
|
|
32
|
-
"@anvpx/motion-schema": "0.1.
|
|
33
|
-
"@anvpx/motion-themes": "0.1.
|
|
31
|
+
"@anvpx/motion-assets": "0.1.1",
|
|
32
|
+
"@anvpx/motion-schema": "0.1.1",
|
|
33
|
+
"@anvpx/motion-themes": "0.1.1",
|
|
34
34
|
"postprocessing": "6.39.5",
|
|
35
35
|
"three": "0.186.0",
|
|
36
36
|
"zod": "4.6.7"
|