@scenography/plugin-wall 0.2.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/dist/data-BMWvlhyh.cjs +84 -0
- package/dist/data-BMWvlhyh.cjs.map +1 -0
- package/dist/data-PI34E7UF.mjs +43 -0
- package/dist/data-PI34E7UF.mjs.map +1 -0
- package/dist/data.cjs +9 -0
- package/dist/data.d.cts +2 -0
- package/dist/data.d.mts +2 -0
- package/dist/data.mjs +2 -0
- package/dist/index-tssS_Ed-.d.cts +66 -0
- package/dist/index-tssS_Ed-.d.mts +66 -0
- package/dist/index.cjs +121 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +38 -0
- package/dist/index.d.mts +38 -0
- package/dist/index.mjs +112 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
let _scenography_scene = require("@scenography/scene");
|
|
2
|
+
//#region src/data/geometry.ts
|
|
3
|
+
const WALL_DEFAULT_HEIGHT = 300;
|
|
4
|
+
const WALL_DEFAULT_THICKNESS = 30;
|
|
5
|
+
/** Number of segments in a wall path (one fewer than vertices unless closed). */
|
|
6
|
+
const segmentCount = (wall) => wall.closed ? wall.path.length : wall.path.length - 1;
|
|
7
|
+
/** Endpoints `[a, b]` of segment `i` (wrapping to the first vertex when closed). */
|
|
8
|
+
const edgeEndpoints = (wall, segment) => {
|
|
9
|
+
const n = wall.path.length;
|
|
10
|
+
return [wall.path[segment % n], wall.path[(segment + 1) % n]];
|
|
11
|
+
};
|
|
12
|
+
/** Every edge name declared across all walls (the anchor namespace for artworks). */
|
|
13
|
+
const allEdgeNames = (walls) => walls.flatMap((w) => (w.edges ?? []).map((e) => e.name));
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/data/validate.ts
|
|
16
|
+
const isWallPath = (path) => Array.isArray(path) && path.length >= 2 && path.every((p) => (0, _scenography_scene.isVec2)(p));
|
|
17
|
+
const validateWall = (wall) => {
|
|
18
|
+
const segments = segmentCount(wall);
|
|
19
|
+
const edgeRules = (wall.edges ?? []).flatMap((_, i) => [(0, _scenography_scene.propIs)(`edges[${i}].segment`, (s) => typeof s === "number" && s >= 0 && s < segments, (s) => `segment ${String(s)} is out of range (0..${segments - 1}).`), (0, _scenography_scene.existsProp)(`edges[${i}].name`, "edge is missing a name.")]);
|
|
20
|
+
return (0, _scenography_scene.validate)([
|
|
21
|
+
(0, _scenography_scene.existsProp)("id", "Wall is missing an id."),
|
|
22
|
+
(0, _scenography_scene.nested)("texture", _scenography_scene.validateTexture),
|
|
23
|
+
(0, _scenography_scene.existsProp)("path"),
|
|
24
|
+
(0, _scenography_scene.propIs)("path", isWallPath, "path must have at least two [x, z] vertices."),
|
|
25
|
+
(0, _scenography_scene.when)((w) => isWallPath(w.path), ...edgeRules)
|
|
26
|
+
])(wall);
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/data/plugin.ts
|
|
30
|
+
/**
|
|
31
|
+
* The data half of the wall plugin: owns the `walls` scene key (a collection)
|
|
32
|
+
* and validates each wall. Pure — no three.js. Pass it to `defineScene` so
|
|
33
|
+
* scenes using walls validate without loading the runtime.
|
|
34
|
+
*/
|
|
35
|
+
const wallData = {
|
|
36
|
+
kind: "walls",
|
|
37
|
+
cardinality: "many",
|
|
38
|
+
validate: (wall) => validateWall(wall)
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
Object.defineProperty(exports, "WALL_DEFAULT_HEIGHT", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
get: function() {
|
|
44
|
+
return WALL_DEFAULT_HEIGHT;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
Object.defineProperty(exports, "WALL_DEFAULT_THICKNESS", {
|
|
48
|
+
enumerable: true,
|
|
49
|
+
get: function() {
|
|
50
|
+
return WALL_DEFAULT_THICKNESS;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
Object.defineProperty(exports, "allEdgeNames", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
get: function() {
|
|
56
|
+
return allEdgeNames;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
Object.defineProperty(exports, "edgeEndpoints", {
|
|
60
|
+
enumerable: true,
|
|
61
|
+
get: function() {
|
|
62
|
+
return edgeEndpoints;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
Object.defineProperty(exports, "segmentCount", {
|
|
66
|
+
enumerable: true,
|
|
67
|
+
get: function() {
|
|
68
|
+
return segmentCount;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
Object.defineProperty(exports, "validateWall", {
|
|
72
|
+
enumerable: true,
|
|
73
|
+
get: function() {
|
|
74
|
+
return validateWall;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
Object.defineProperty(exports, "wallData", {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
get: function() {
|
|
80
|
+
return wallData;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=data-BMWvlhyh.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-BMWvlhyh.cjs","names":["validateTexture"],"sources":["../src/data/geometry.ts","../src/data/validate.ts","../src/data/plugin.ts"],"sourcesContent":["import type { Vec2 } from \"@scenography/scene\";\n\nimport type { Wall } from \"./wall\";\n\nexport const WALL_DEFAULT_HEIGHT = 300;\nexport const WALL_DEFAULT_THICKNESS = 30;\n\n/** Number of segments in a wall path (one fewer than vertices unless closed). */\nexport const segmentCount = (wall: Wall): number =>\n wall.closed ? wall.path.length : wall.path.length - 1;\n\n/** Endpoints `[a, b]` of segment `i` (wrapping to the first vertex when closed). */\nexport const edgeEndpoints = (wall: Wall, segment: number): [Vec2, Vec2] => {\n const n = wall.path.length;\n return [wall.path[segment % n] as Vec2, wall.path[(segment + 1) % n] as Vec2];\n};\n\n/** Every edge name declared across all walls (the anchor namespace for artworks). */\nexport const allEdgeNames = (walls: Wall[]): string[] =>\n walls.flatMap((w) => (w.edges ?? []).map((e) => e.name));\n","import {\n existsProp,\n isVec2,\n nested,\n propIs,\n validate,\n validateTexture,\n when,\n type ValidationResult,\n} from \"@scenography/scene\";\n\nimport { segmentCount } from \"./geometry\";\nimport type { Wall } from \"./wall\";\n\nconst isWallPath = (path: unknown): boolean =>\n Array.isArray(path) && path.length >= 2 && path.every((p) => isVec2(p));\n\nexport const validateWall = (wall: Wall): ValidationResult => {\n const segments = segmentCount(wall);\n // Edge rules are built per declared edge (their paths carry the index); they\n // only run once the path itself is valid, since the range depends on it.\n const edgeRules = (wall.edges ?? []).flatMap((_, i) => [\n propIs(\n `edges[${i}].segment`,\n (s) => typeof s === \"number\" && s >= 0 && s < segments,\n (s) => `segment ${String(s)} is out of range (0..${segments - 1}).`,\n ),\n existsProp(`edges[${i}].name`, \"edge is missing a name.\"),\n ]);\n return validate<Wall>([\n existsProp(\"id\", \"Wall is missing an id.\"),\n nested(\"texture\", validateTexture),\n existsProp(\"path\"),\n propIs(\"path\", isWallPath, \"path must have at least two [x, z] vertices.\"),\n when((w: Wall) => isWallPath(w.path), ...edgeRules),\n ])(wall);\n};\n","import type { DataPlugin } from \"@scenography/scene\";\n\nimport { validateWall } from \"./validate\";\nimport type { Wall } from \"./wall\";\n\n/**\n * The data half of the wall plugin: owns the `walls` scene key (a collection)\n * and validates each wall. Pure — no three.js. Pass it to `defineScene` so\n * scenes using walls validate without loading the runtime.\n */\nexport const wallData: DataPlugin<Wall> = {\n kind: \"walls\",\n cardinality: \"many\",\n validate: (wall) => validateWall(wall),\n};\n"],"mappings":";;AAIA,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;;AAGtC,MAAa,gBAAgB,SAC3B,KAAK,SAAS,KAAK,KAAK,SAAS,KAAK,KAAK,SAAS;;AAGtD,MAAa,iBAAiB,MAAY,YAAkC;CAC1E,MAAM,IAAI,KAAK,KAAK;CACpB,OAAO,CAAC,KAAK,KAAK,UAAU,IAAY,KAAK,MAAM,UAAU,KAAK,EAAU;AAC9E;;AAGA,MAAa,gBAAgB,UAC3B,MAAM,SAAS,OAAO,EAAE,SAAS,CAAC,EAAA,CAAG,KAAK,MAAM,EAAE,IAAI,CAAC;;;ACLzD,MAAM,cAAc,SAClB,MAAM,QAAQ,IAAI,KAAK,KAAK,UAAU,KAAK,KAAK,OAAO,OAAA,GAAA,mBAAA,OAAA,CAAa,CAAC,CAAC;AAExE,MAAa,gBAAgB,SAAiC;CAC5D,MAAM,WAAW,aAAa,IAAI;CAGlC,MAAM,aAAa,KAAK,SAAS,CAAC,EAAA,CAAG,SAAS,GAAG,MAAM,EAAA,GAAA,mBAAA,OAAA,CAEnD,SAAS,EAAE,aACV,MAAM,OAAO,MAAM,YAAY,KAAK,KAAK,IAAI,WAC7C,MAAM,WAAW,OAAO,CAAC,EAAE,uBAAuB,WAAW,EAAE,GAClE,IAAA,GAAA,mBAAA,WAAA,CACW,SAAS,EAAE,SAAS,yBAAyB,CAC1D,CAAC;CACD,QAAA,GAAA,mBAAA,SAAA,CAAsB;qCACT,MAAM,wBAAwB;iCAClC,WAAWA,mBAAAA,eAAe;qCACtB,MAAM;iCACV,QAAQ,YAAY,8CAA8C;gCACnE,MAAY,WAAW,EAAE,IAAI,GAAG,GAAG,SAAS;CACpD,CAAC,CAAC,CAAC,IAAI;AACT;;;;;;;;AC1BA,MAAa,WAA6B;CACxC,MAAM;CACN,aAAa;CACb,WAAW,SAAS,aAAa,IAAI;AACvC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { existsProp, isVec2, nested, propIs, validate, validateTexture, when } from "@scenography/scene";
|
|
2
|
+
//#region src/data/geometry.ts
|
|
3
|
+
const WALL_DEFAULT_HEIGHT = 300;
|
|
4
|
+
const WALL_DEFAULT_THICKNESS = 30;
|
|
5
|
+
/** Number of segments in a wall path (one fewer than vertices unless closed). */
|
|
6
|
+
const segmentCount = (wall) => wall.closed ? wall.path.length : wall.path.length - 1;
|
|
7
|
+
/** Endpoints `[a, b]` of segment `i` (wrapping to the first vertex when closed). */
|
|
8
|
+
const edgeEndpoints = (wall, segment) => {
|
|
9
|
+
const n = wall.path.length;
|
|
10
|
+
return [wall.path[segment % n], wall.path[(segment + 1) % n]];
|
|
11
|
+
};
|
|
12
|
+
/** Every edge name declared across all walls (the anchor namespace for artworks). */
|
|
13
|
+
const allEdgeNames = (walls) => walls.flatMap((w) => (w.edges ?? []).map((e) => e.name));
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/data/validate.ts
|
|
16
|
+
const isWallPath = (path) => Array.isArray(path) && path.length >= 2 && path.every((p) => isVec2(p));
|
|
17
|
+
const validateWall = (wall) => {
|
|
18
|
+
const segments = segmentCount(wall);
|
|
19
|
+
const edgeRules = (wall.edges ?? []).flatMap((_, i) => [propIs(`edges[${i}].segment`, (s) => typeof s === "number" && s >= 0 && s < segments, (s) => `segment ${String(s)} is out of range (0..${segments - 1}).`), existsProp(`edges[${i}].name`, "edge is missing a name.")]);
|
|
20
|
+
return validate([
|
|
21
|
+
existsProp("id", "Wall is missing an id."),
|
|
22
|
+
nested("texture", validateTexture),
|
|
23
|
+
existsProp("path"),
|
|
24
|
+
propIs("path", isWallPath, "path must have at least two [x, z] vertices."),
|
|
25
|
+
when((w) => isWallPath(w.path), ...edgeRules)
|
|
26
|
+
])(wall);
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/data/plugin.ts
|
|
30
|
+
/**
|
|
31
|
+
* The data half of the wall plugin: owns the `walls` scene key (a collection)
|
|
32
|
+
* and validates each wall. Pure — no three.js. Pass it to `defineScene` so
|
|
33
|
+
* scenes using walls validate without loading the runtime.
|
|
34
|
+
*/
|
|
35
|
+
const wallData = {
|
|
36
|
+
kind: "walls",
|
|
37
|
+
cardinality: "many",
|
|
38
|
+
validate: (wall) => validateWall(wall)
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
export { allEdgeNames as a, WALL_DEFAULT_THICKNESS as i, validateWall as n, edgeEndpoints as o, WALL_DEFAULT_HEIGHT as r, segmentCount as s, wallData as t };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=data-PI34E7UF.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-PI34E7UF.mjs","names":[],"sources":["../src/data/geometry.ts","../src/data/validate.ts","../src/data/plugin.ts"],"sourcesContent":["import type { Vec2 } from \"@scenography/scene\";\n\nimport type { Wall } from \"./wall\";\n\nexport const WALL_DEFAULT_HEIGHT = 300;\nexport const WALL_DEFAULT_THICKNESS = 30;\n\n/** Number of segments in a wall path (one fewer than vertices unless closed). */\nexport const segmentCount = (wall: Wall): number =>\n wall.closed ? wall.path.length : wall.path.length - 1;\n\n/** Endpoints `[a, b]` of segment `i` (wrapping to the first vertex when closed). */\nexport const edgeEndpoints = (wall: Wall, segment: number): [Vec2, Vec2] => {\n const n = wall.path.length;\n return [wall.path[segment % n] as Vec2, wall.path[(segment + 1) % n] as Vec2];\n};\n\n/** Every edge name declared across all walls (the anchor namespace for artworks). */\nexport const allEdgeNames = (walls: Wall[]): string[] =>\n walls.flatMap((w) => (w.edges ?? []).map((e) => e.name));\n","import {\n existsProp,\n isVec2,\n nested,\n propIs,\n validate,\n validateTexture,\n when,\n type ValidationResult,\n} from \"@scenography/scene\";\n\nimport { segmentCount } from \"./geometry\";\nimport type { Wall } from \"./wall\";\n\nconst isWallPath = (path: unknown): boolean =>\n Array.isArray(path) && path.length >= 2 && path.every((p) => isVec2(p));\n\nexport const validateWall = (wall: Wall): ValidationResult => {\n const segments = segmentCount(wall);\n // Edge rules are built per declared edge (their paths carry the index); they\n // only run once the path itself is valid, since the range depends on it.\n const edgeRules = (wall.edges ?? []).flatMap((_, i) => [\n propIs(\n `edges[${i}].segment`,\n (s) => typeof s === \"number\" && s >= 0 && s < segments,\n (s) => `segment ${String(s)} is out of range (0..${segments - 1}).`,\n ),\n existsProp(`edges[${i}].name`, \"edge is missing a name.\"),\n ]);\n return validate<Wall>([\n existsProp(\"id\", \"Wall is missing an id.\"),\n nested(\"texture\", validateTexture),\n existsProp(\"path\"),\n propIs(\"path\", isWallPath, \"path must have at least two [x, z] vertices.\"),\n when((w: Wall) => isWallPath(w.path), ...edgeRules),\n ])(wall);\n};\n","import type { DataPlugin } from \"@scenography/scene\";\n\nimport { validateWall } from \"./validate\";\nimport type { Wall } from \"./wall\";\n\n/**\n * The data half of the wall plugin: owns the `walls` scene key (a collection)\n * and validates each wall. Pure — no three.js. Pass it to `defineScene` so\n * scenes using walls validate without loading the runtime.\n */\nexport const wallData: DataPlugin<Wall> = {\n kind: \"walls\",\n cardinality: \"many\",\n validate: (wall) => validateWall(wall),\n};\n"],"mappings":";;AAIA,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;;AAGtC,MAAa,gBAAgB,SAC3B,KAAK,SAAS,KAAK,KAAK,SAAS,KAAK,KAAK,SAAS;;AAGtD,MAAa,iBAAiB,MAAY,YAAkC;CAC1E,MAAM,IAAI,KAAK,KAAK;CACpB,OAAO,CAAC,KAAK,KAAK,UAAU,IAAY,KAAK,MAAM,UAAU,KAAK,EAAU;AAC9E;;AAGA,MAAa,gBAAgB,UAC3B,MAAM,SAAS,OAAO,EAAE,SAAS,CAAC,EAAA,CAAG,KAAK,MAAM,EAAE,IAAI,CAAC;;;ACLzD,MAAM,cAAc,SAClB,MAAM,QAAQ,IAAI,KAAK,KAAK,UAAU,KAAK,KAAK,OAAO,MAAM,OAAO,CAAC,CAAC;AAExE,MAAa,gBAAgB,SAAiC;CAC5D,MAAM,WAAW,aAAa,IAAI;CAGlC,MAAM,aAAa,KAAK,SAAS,CAAC,EAAA,CAAG,SAAS,GAAG,MAAM,CACrD,OACE,SAAS,EAAE,aACV,MAAM,OAAO,MAAM,YAAY,KAAK,KAAK,IAAI,WAC7C,MAAM,WAAW,OAAO,CAAC,EAAE,uBAAuB,WAAW,EAAE,GAClE,GACA,WAAW,SAAS,EAAE,SAAS,yBAAyB,CAC1D,CAAC;CACD,OAAO,SAAe;EACpB,WAAW,MAAM,wBAAwB;EACzC,OAAO,WAAW,eAAe;EACjC,WAAW,MAAM;EACjB,OAAO,QAAQ,YAAY,8CAA8C;EACzE,MAAM,MAAY,WAAW,EAAE,IAAI,GAAG,GAAG,SAAS;CACpD,CAAC,CAAC,CAAC,IAAI;AACT;;;;;;;;AC1BA,MAAa,WAA6B;CACxC,MAAM;CACN,aAAa;CACb,WAAW,SAAS,aAAa,IAAI;AACvC"}
|
package/dist/data.cjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_data = require("./data-BMWvlhyh.cjs");
|
|
3
|
+
exports.WALL_DEFAULT_HEIGHT = require_data.WALL_DEFAULT_HEIGHT;
|
|
4
|
+
exports.WALL_DEFAULT_THICKNESS = require_data.WALL_DEFAULT_THICKNESS;
|
|
5
|
+
exports.allEdgeNames = require_data.allEdgeNames;
|
|
6
|
+
exports.edgeEndpoints = require_data.edgeEndpoints;
|
|
7
|
+
exports.segmentCount = require_data.segmentCount;
|
|
8
|
+
exports.validateWall = require_data.validateWall;
|
|
9
|
+
exports.wallData = require_data.wallData;
|
package/dist/data.d.cts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as allEdgeNames, c as NamedEdge, i as WALL_DEFAULT_THICKNESS, l as Wall, n as validateWall, o as edgeEndpoints, r as WALL_DEFAULT_HEIGHT, s as segmentCount, t as wallData } from "./index-tssS_Ed-.cjs";
|
|
2
|
+
export { type NamedEdge, WALL_DEFAULT_HEIGHT, WALL_DEFAULT_THICKNESS, type Wall, allEdgeNames, edgeEndpoints, segmentCount, validateWall, wallData };
|
package/dist/data.d.mts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as allEdgeNames, c as NamedEdge, i as WALL_DEFAULT_THICKNESS, l as Wall, n as validateWall, o as edgeEndpoints, r as WALL_DEFAULT_HEIGHT, s as segmentCount, t as wallData } from "./index-tssS_Ed-.mjs";
|
|
2
|
+
export { type NamedEdge, WALL_DEFAULT_HEIGHT, WALL_DEFAULT_THICKNESS, type Wall, allEdgeNames, edgeEndpoints, segmentCount, validateWall, wallData };
|
package/dist/data.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as allEdgeNames, i as WALL_DEFAULT_THICKNESS, n as validateWall, o as edgeEndpoints, r as WALL_DEFAULT_HEIGHT, s as segmentCount, t as wallData } from "./data-PI34E7UF.mjs";
|
|
2
|
+
export { WALL_DEFAULT_HEIGHT, WALL_DEFAULT_THICKNESS, allEdgeNames, edgeEndpoints, segmentCount, validateWall, wallData };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { DataPlugin, SurfaceTexture, ValidationResult, Vec2 } from "@scenography/scene";
|
|
2
|
+
|
|
3
|
+
//#region src/data/wall.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Names a segment of a wall's path so artworks can hang on it. The segment runs
|
|
6
|
+
* from `path[segment]` to `path[segment + 1]` (wrapping to the first vertex when
|
|
7
|
+
* the wall is `closed`).
|
|
8
|
+
*/
|
|
9
|
+
interface NamedEdge {
|
|
10
|
+
segment: number;
|
|
11
|
+
/** Unique anchor name, referenced by an artwork's `location.edge`. */
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A wall as a top-down path with thickness and height. The engine extrudes the
|
|
16
|
+
* polyline into a continuous run of walls — no need to declare each side
|
|
17
|
+
* separately. Corners are simple butt joints for now (the path is followed at
|
|
18
|
+
* its center); chamfers/rounding and inside/outside offset are future work.
|
|
19
|
+
*/
|
|
20
|
+
interface Wall {
|
|
21
|
+
id: string;
|
|
22
|
+
/** Top-down footprint as `[x, z]` vertices; the wall follows this polyline. */
|
|
23
|
+
path: Vec2[];
|
|
24
|
+
/** Wall height in world units. Defaults to `300` (≈3 m). */
|
|
25
|
+
height?: number;
|
|
26
|
+
/** Wall thickness in world units. Defaults to `30`. */
|
|
27
|
+
thickness?: number;
|
|
28
|
+
/** Connect the last vertex back to the first. Defaults to `false`. */
|
|
29
|
+
closed?: boolean;
|
|
30
|
+
/** Named segments that artworks can hang on. */
|
|
31
|
+
edges?: NamedEdge[];
|
|
32
|
+
/** CSS-style color of the wall surface. Defaults to a neutral white. */
|
|
33
|
+
color?: string;
|
|
34
|
+
/** Image mapped onto the surface. Tints with `color` when both are set. */
|
|
35
|
+
texture?: SurfaceTexture;
|
|
36
|
+
}
|
|
37
|
+
declare module "@scenography/scene" {
|
|
38
|
+
interface Scene {
|
|
39
|
+
/** Walls in the space — provided by `@scenography/plugin-wall`. */
|
|
40
|
+
walls?: Wall[];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/data/geometry.d.ts
|
|
45
|
+
declare const WALL_DEFAULT_HEIGHT = 300;
|
|
46
|
+
declare const WALL_DEFAULT_THICKNESS = 30;
|
|
47
|
+
/** Number of segments in a wall path (one fewer than vertices unless closed). */
|
|
48
|
+
declare const segmentCount: (wall: Wall) => number;
|
|
49
|
+
/** Endpoints `[a, b]` of segment `i` (wrapping to the first vertex when closed). */
|
|
50
|
+
declare const edgeEndpoints: (wall: Wall, segment: number) => [Vec2, Vec2];
|
|
51
|
+
/** Every edge name declared across all walls (the anchor namespace for artworks). */
|
|
52
|
+
declare const allEdgeNames: (walls: Wall[]) => string[];
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/data/validate.d.ts
|
|
55
|
+
declare const validateWall: (wall: Wall) => ValidationResult;
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/data/plugin.d.ts
|
|
58
|
+
/**
|
|
59
|
+
* The data half of the wall plugin: owns the `walls` scene key (a collection)
|
|
60
|
+
* and validates each wall. Pure — no three.js. Pass it to `defineScene` so
|
|
61
|
+
* scenes using walls validate without loading the runtime.
|
|
62
|
+
*/
|
|
63
|
+
declare const wallData: DataPlugin<Wall>;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { allEdgeNames as a, NamedEdge as c, WALL_DEFAULT_THICKNESS as i, Wall as l, validateWall as n, edgeEndpoints as o, WALL_DEFAULT_HEIGHT as r, segmentCount as s, wallData as t };
|
|
66
|
+
//# sourceMappingURL=index-tssS_Ed-.d.cts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { DataPlugin, SurfaceTexture, ValidationResult, Vec2 } from "@scenography/scene";
|
|
2
|
+
|
|
3
|
+
//#region src/data/wall.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Names a segment of a wall's path so artworks can hang on it. The segment runs
|
|
6
|
+
* from `path[segment]` to `path[segment + 1]` (wrapping to the first vertex when
|
|
7
|
+
* the wall is `closed`).
|
|
8
|
+
*/
|
|
9
|
+
interface NamedEdge {
|
|
10
|
+
segment: number;
|
|
11
|
+
/** Unique anchor name, referenced by an artwork's `location.edge`. */
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A wall as a top-down path with thickness and height. The engine extrudes the
|
|
16
|
+
* polyline into a continuous run of walls — no need to declare each side
|
|
17
|
+
* separately. Corners are simple butt joints for now (the path is followed at
|
|
18
|
+
* its center); chamfers/rounding and inside/outside offset are future work.
|
|
19
|
+
*/
|
|
20
|
+
interface Wall {
|
|
21
|
+
id: string;
|
|
22
|
+
/** Top-down footprint as `[x, z]` vertices; the wall follows this polyline. */
|
|
23
|
+
path: Vec2[];
|
|
24
|
+
/** Wall height in world units. Defaults to `300` (≈3 m). */
|
|
25
|
+
height?: number;
|
|
26
|
+
/** Wall thickness in world units. Defaults to `30`. */
|
|
27
|
+
thickness?: number;
|
|
28
|
+
/** Connect the last vertex back to the first. Defaults to `false`. */
|
|
29
|
+
closed?: boolean;
|
|
30
|
+
/** Named segments that artworks can hang on. */
|
|
31
|
+
edges?: NamedEdge[];
|
|
32
|
+
/** CSS-style color of the wall surface. Defaults to a neutral white. */
|
|
33
|
+
color?: string;
|
|
34
|
+
/** Image mapped onto the surface. Tints with `color` when both are set. */
|
|
35
|
+
texture?: SurfaceTexture;
|
|
36
|
+
}
|
|
37
|
+
declare module "@scenography/scene" {
|
|
38
|
+
interface Scene {
|
|
39
|
+
/** Walls in the space — provided by `@scenography/plugin-wall`. */
|
|
40
|
+
walls?: Wall[];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/data/geometry.d.ts
|
|
45
|
+
declare const WALL_DEFAULT_HEIGHT = 300;
|
|
46
|
+
declare const WALL_DEFAULT_THICKNESS = 30;
|
|
47
|
+
/** Number of segments in a wall path (one fewer than vertices unless closed). */
|
|
48
|
+
declare const segmentCount: (wall: Wall) => number;
|
|
49
|
+
/** Endpoints `[a, b]` of segment `i` (wrapping to the first vertex when closed). */
|
|
50
|
+
declare const edgeEndpoints: (wall: Wall, segment: number) => [Vec2, Vec2];
|
|
51
|
+
/** Every edge name declared across all walls (the anchor namespace for artworks). */
|
|
52
|
+
declare const allEdgeNames: (walls: Wall[]) => string[];
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/data/validate.d.ts
|
|
55
|
+
declare const validateWall: (wall: Wall) => ValidationResult;
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/data/plugin.d.ts
|
|
58
|
+
/**
|
|
59
|
+
* The data half of the wall plugin: owns the `walls` scene key (a collection)
|
|
60
|
+
* and validates each wall. Pure — no three.js. Pass it to `defineScene` so
|
|
61
|
+
* scenes using walls validate without loading the runtime.
|
|
62
|
+
*/
|
|
63
|
+
declare const wallData: DataPlugin<Wall>;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { allEdgeNames as a, NamedEdge as c, WALL_DEFAULT_THICKNESS as i, Wall as l, validateWall as n, edgeEndpoints as o, WALL_DEFAULT_HEIGHT as r, segmentCount as s, wallData as t };
|
|
66
|
+
//# sourceMappingURL=index-tssS_Ed-.d.mts.map
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_data = require("./data-BMWvlhyh.cjs");
|
|
3
|
+
let _scenography_engine = require("@scenography/engine");
|
|
4
|
+
let three = require("three");
|
|
5
|
+
//#region src/buildWall.ts
|
|
6
|
+
/**
|
|
7
|
+
* Build the three.js object for a `Wall`: one thickened box per path segment,
|
|
8
|
+
* following the polyline at its center. Corners are simple butt joints (boxes
|
|
9
|
+
* overlap slightly), which reads cleanly at a uniform thickness.
|
|
10
|
+
*/
|
|
11
|
+
function buildWall(wall) {
|
|
12
|
+
const height = wall.height ?? 300;
|
|
13
|
+
const thickness = wall.thickness ?? 30;
|
|
14
|
+
const material = new three.MeshStandardMaterial({ color: wall.color ?? "#ffffff" });
|
|
15
|
+
const needsUv1 = wall.texture ? (0, _scenography_engine.applyTexture)(material, wall.texture) : false;
|
|
16
|
+
const group = new three.Group();
|
|
17
|
+
const segments = require_data.segmentCount(wall);
|
|
18
|
+
for (let i = 0; i < segments; i++) {
|
|
19
|
+
const [a, b] = require_data.edgeEndpoints(wall, i);
|
|
20
|
+
const dx = b[0] - a[0];
|
|
21
|
+
const dz = b[1] - a[1];
|
|
22
|
+
const length = Math.hypot(dx, dz);
|
|
23
|
+
if (length === 0) continue;
|
|
24
|
+
const geometry = new three.BoxGeometry(length, height, thickness);
|
|
25
|
+
if (needsUv1) {
|
|
26
|
+
const uv = geometry.getAttribute("uv");
|
|
27
|
+
if (uv) geometry.setAttribute("uv1", uv);
|
|
28
|
+
}
|
|
29
|
+
const box = new three.Mesh(geometry, material);
|
|
30
|
+
box.position.set((a[0] + b[0]) / 2, height / 2, (a[1] + b[1]) / 2);
|
|
31
|
+
box.rotation.y = Math.atan2(-dz, dx);
|
|
32
|
+
box.castShadow = true;
|
|
33
|
+
box.receiveShadow = true;
|
|
34
|
+
group.add(box);
|
|
35
|
+
}
|
|
36
|
+
group.name = `wall:${wall.id}`;
|
|
37
|
+
group.userData.scenographyId = wall.id;
|
|
38
|
+
return group;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/colliders.ts
|
|
42
|
+
/**
|
|
43
|
+
* Build a collision box for every wall segment (matching the built geometry) —
|
|
44
|
+
* the `colliders` capability the camera controls consume to keep the visitor
|
|
45
|
+
* out of walls.
|
|
46
|
+
*/
|
|
47
|
+
function buildColliders(walls) {
|
|
48
|
+
const colliders = [];
|
|
49
|
+
for (const wall of walls) {
|
|
50
|
+
const halfThickness = (wall.thickness ?? 30) / 2;
|
|
51
|
+
const segments = require_data.segmentCount(wall);
|
|
52
|
+
for (let i = 0; i < segments; i++) {
|
|
53
|
+
const [a, b] = require_data.edgeEndpoints(wall, i);
|
|
54
|
+
const ex = b[0] - a[0];
|
|
55
|
+
const ez = b[1] - a[1];
|
|
56
|
+
const length = Math.hypot(ex, ez);
|
|
57
|
+
if (length === 0) continue;
|
|
58
|
+
colliders.push({
|
|
59
|
+
cx: (a[0] + b[0]) / 2,
|
|
60
|
+
cz: (a[1] + b[1]) / 2,
|
|
61
|
+
dx: ex / length,
|
|
62
|
+
dz: ez / length,
|
|
63
|
+
halfLength: length / 2,
|
|
64
|
+
halfThickness
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return colliders;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/edgeIndex.ts
|
|
72
|
+
/**
|
|
73
|
+
* Build the `name -> EdgeAnchor` index across every wall — the `edges`
|
|
74
|
+
* capability the artwork plugin consumes to hang pieces on a named segment.
|
|
75
|
+
*/
|
|
76
|
+
function indexEdges(walls) {
|
|
77
|
+
const index = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const wall of walls) {
|
|
79
|
+
const height = wall.height ?? 300;
|
|
80
|
+
const thickness = wall.thickness ?? 30;
|
|
81
|
+
for (const edge of wall.edges ?? []) {
|
|
82
|
+
const [a, b] = require_data.edgeEndpoints(wall, edge.segment);
|
|
83
|
+
index.set(edge.name, {
|
|
84
|
+
a,
|
|
85
|
+
b,
|
|
86
|
+
height,
|
|
87
|
+
thickness
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return index;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/plugin.ts
|
|
95
|
+
/**
|
|
96
|
+
* The wall plugin: extrudes each `Wall` into geometry, and — across all walls —
|
|
97
|
+
* publishes the `edges` capability (named anchors artworks hang on) and the
|
|
98
|
+
* `colliders` capability (obstacles the camera can't pass). A single change
|
|
99
|
+
* token covers both, so consumers only rebuild when the walls actually change.
|
|
100
|
+
*/
|
|
101
|
+
const wall = () => ({
|
|
102
|
+
data: require_data.wallData,
|
|
103
|
+
build: (definition) => ({ object: buildWall(definition) }),
|
|
104
|
+
provide: (walls, ctx) => {
|
|
105
|
+
const token = JSON.stringify(walls);
|
|
106
|
+
ctx.capabilities.provide(_scenography_engine.EDGES, indexEdges(walls), token);
|
|
107
|
+
ctx.capabilities.provide(_scenography_engine.COLLIDERS, buildColliders(walls), token);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
//#endregion
|
|
111
|
+
exports.WALL_DEFAULT_HEIGHT = require_data.WALL_DEFAULT_HEIGHT;
|
|
112
|
+
exports.WALL_DEFAULT_THICKNESS = require_data.WALL_DEFAULT_THICKNESS;
|
|
113
|
+
exports.allEdgeNames = require_data.allEdgeNames;
|
|
114
|
+
exports.buildColliders = buildColliders;
|
|
115
|
+
exports.buildWall = buildWall;
|
|
116
|
+
exports.indexEdges = indexEdges;
|
|
117
|
+
exports.validateWall = require_data.validateWall;
|
|
118
|
+
exports.wall = wall;
|
|
119
|
+
exports.wallData = require_data.wallData;
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["MeshStandardMaterial","Group","segmentCount","edgeEndpoints","BoxGeometry","Mesh","segmentCount","edgeEndpoints","edgeEndpoints","wallData","EDGES","COLLIDERS"],"sources":["../src/buildWall.ts","../src/colliders.ts","../src/edgeIndex.ts","../src/plugin.ts"],"sourcesContent":["import { applyTexture } from \"@scenography/engine\";\nimport { BoxGeometry, Group, Mesh, MeshStandardMaterial, type Object3D } from \"three\";\n\nimport {\n WALL_DEFAULT_HEIGHT,\n WALL_DEFAULT_THICKNESS,\n edgeEndpoints,\n segmentCount,\n type Wall,\n} from \"./data\";\n\n/**\n * Build the three.js object for a `Wall`: one thickened box per path segment,\n * following the polyline at its center. Corners are simple butt joints (boxes\n * overlap slightly), which reads cleanly at a uniform thickness.\n */\nexport function buildWall(wall: Wall): Object3D {\n const height = wall.height ?? WALL_DEFAULT_HEIGHT;\n const thickness = wall.thickness ?? WALL_DEFAULT_THICKNESS;\n const material = new MeshStandardMaterial({ color: wall.color ?? \"#ffffff\" });\n const needsUv1 = wall.texture ? applyTexture(material, wall.texture) : false;\n\n const group = new Group();\n const segments = segmentCount(wall);\n for (let i = 0; i < segments; i++) {\n const [a, b] = edgeEndpoints(wall, i);\n const dx = b[0] - a[0];\n const dz = b[1] - a[1];\n const length = Math.hypot(dx, dz);\n if (length === 0) continue;\n\n const geometry = new BoxGeometry(length, height, thickness);\n // aoMap reads the second UV set; box geometry only ships `uv`, so mirror it.\n if (needsUv1) {\n const uv = geometry.getAttribute(\"uv\");\n if (uv) geometry.setAttribute(\"uv1\", uv);\n }\n\n const box = new Mesh(geometry, material);\n box.position.set((a[0] + b[0]) / 2, height / 2, (a[1] + b[1]) / 2);\n // Align the box's local X (its length) with the segment direction.\n box.rotation.y = Math.atan2(-dz, dx);\n box.castShadow = true;\n box.receiveShadow = true;\n group.add(box);\n }\n\n group.name = `wall:${wall.id}`;\n group.userData.scenographyId = wall.id;\n return group;\n}\n","import type { Collider } from \"@scenography/engine\";\n\nimport { WALL_DEFAULT_THICKNESS, edgeEndpoints, segmentCount, type Wall } from \"./data\";\n\n/**\n * Build a collision box for every wall segment (matching the built geometry) —\n * the `colliders` capability the camera controls consume to keep the visitor\n * out of walls.\n */\nexport function buildColliders(walls: Wall[]): Collider[] {\n const colliders: Collider[] = [];\n for (const wall of walls) {\n const halfThickness = (wall.thickness ?? WALL_DEFAULT_THICKNESS) / 2;\n const segments = segmentCount(wall);\n for (let i = 0; i < segments; i++) {\n const [a, b] = edgeEndpoints(wall, i);\n const ex = b[0] - a[0];\n const ez = b[1] - a[1];\n const length = Math.hypot(ex, ez);\n if (length === 0) continue;\n colliders.push({\n cx: (a[0] + b[0]) / 2,\n cz: (a[1] + b[1]) / 2,\n dx: ex / length,\n dz: ez / length,\n halfLength: length / 2,\n halfThickness,\n });\n }\n }\n return colliders;\n}\n","import type { EdgeAnchor, EdgeIndex } from \"@scenography/engine\";\n\nimport {\n WALL_DEFAULT_HEIGHT,\n WALL_DEFAULT_THICKNESS,\n edgeEndpoints,\n type Wall,\n} from \"./data\";\n\n/**\n * Build the `name -> EdgeAnchor` index across every wall — the `edges`\n * capability the artwork plugin consumes to hang pieces on a named segment.\n */\nexport function indexEdges(walls: Wall[]): EdgeIndex {\n const index = new Map<string, EdgeAnchor>();\n for (const wall of walls) {\n const height = wall.height ?? WALL_DEFAULT_HEIGHT;\n const thickness = wall.thickness ?? WALL_DEFAULT_THICKNESS;\n for (const edge of wall.edges ?? []) {\n const [a, b] = edgeEndpoints(wall, edge.segment);\n index.set(edge.name, { a, b, height, thickness });\n }\n }\n return index;\n}\n","import { COLLIDERS, EDGES, type EnginePlugin } from \"@scenography/engine\";\n\nimport { buildWall } from \"./buildWall\";\nimport { buildColliders } from \"./colliders\";\nimport { wallData, type Wall } from \"./data\";\nimport { indexEdges } from \"./edgeIndex\";\n\n/**\n * The wall plugin: extrudes each `Wall` into geometry, and — across all walls —\n * publishes the `edges` capability (named anchors artworks hang on) and the\n * `colliders` capability (obstacles the camera can't pass). A single change\n * token covers both, so consumers only rebuild when the walls actually change.\n */\nexport const wall = (): EnginePlugin<Wall> => ({\n data: wallData,\n build: (definition) => ({ object: buildWall(definition) }),\n provide: (walls, ctx) => {\n const token = JSON.stringify(walls);\n ctx.capabilities.provide(EDGES, indexEdges(walls), token);\n ctx.capabilities.provide(COLLIDERS, buildColliders(walls), token);\n },\n});\n"],"mappings":";;;;;;;;;;AAgBA,SAAgB,UAAU,MAAsB;CAC9C,MAAM,SAAS,KAAK,UAAA;CACpB,MAAM,YAAY,KAAK,aAAA;CACvB,MAAM,WAAW,IAAIA,MAAAA,qBAAqB,EAAE,OAAO,KAAK,SAAS,UAAU,CAAC;CAC5E,MAAM,WAAW,KAAK,WAAA,GAAA,oBAAA,aAAA,CAAuB,UAAU,KAAK,OAAO,IAAI;CAEvE,MAAM,QAAQ,IAAIC,MAAAA,MAAM;CACxB,MAAM,WAAWC,aAAAA,aAAa,IAAI;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;EACjC,MAAM,CAAC,GAAG,KAAKC,aAAAA,cAAc,MAAM,CAAC;EACpC,MAAM,KAAK,EAAE,KAAK,EAAE;EACpB,MAAM,KAAK,EAAE,KAAK,EAAE;EACpB,MAAM,SAAS,KAAK,MAAM,IAAI,EAAE;EAChC,IAAI,WAAW,GAAG;EAElB,MAAM,WAAW,IAAIC,MAAAA,YAAY,QAAQ,QAAQ,SAAS;EAE1D,IAAI,UAAU;GACZ,MAAM,KAAK,SAAS,aAAa,IAAI;GACrC,IAAI,IAAI,SAAS,aAAa,OAAO,EAAE;EACzC;EAEA,MAAM,MAAM,IAAIC,MAAAA,KAAK,UAAU,QAAQ;EACvC,IAAI,SAAS,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC;EAEjE,IAAI,SAAS,IAAI,KAAK,MAAM,CAAC,IAAI,EAAE;EACnC,IAAI,aAAa;EACjB,IAAI,gBAAgB;EACpB,MAAM,IAAI,GAAG;CACf;CAEA,MAAM,OAAO,QAAQ,KAAK;CAC1B,MAAM,SAAS,gBAAgB,KAAK;CACpC,OAAO;AACT;;;;;;;;ACzCA,SAAgB,eAAe,OAA2B;CACxD,MAAM,YAAwB,CAAC;CAC/B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,iBAAiB,KAAK,aAAA,MAAuC;EACnE,MAAM,WAAWC,aAAAA,aAAa,IAAI;EAClC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,CAAC,GAAG,KAAKC,aAAAA,cAAc,MAAM,CAAC;GACpC,MAAM,KAAK,EAAE,KAAK,EAAE;GACpB,MAAM,KAAK,EAAE,KAAK,EAAE;GACpB,MAAM,SAAS,KAAK,MAAM,IAAI,EAAE;GAChC,IAAI,WAAW,GAAG;GAClB,UAAU,KAAK;IACb,KAAK,EAAE,KAAK,EAAE,MAAM;IACpB,KAAK,EAAE,KAAK,EAAE,MAAM;IACpB,IAAI,KAAK;IACT,IAAI,KAAK;IACT,YAAY,SAAS;IACrB;GACF,CAAC;EACH;CACF;CACA,OAAO;AACT;;;;;;;AClBA,SAAgB,WAAW,OAA0B;CACnD,MAAM,wBAAQ,IAAI,IAAwB;CAC1C,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,KAAK,UAAA;EACpB,MAAM,YAAY,KAAK,aAAA;EACvB,KAAK,MAAM,QAAQ,KAAK,SAAS,CAAC,GAAG;GACnC,MAAM,CAAC,GAAG,KAAKC,aAAAA,cAAc,MAAM,KAAK,OAAO;GAC/C,MAAM,IAAI,KAAK,MAAM;IAAE;IAAG;IAAG;IAAQ;GAAU,CAAC;EAClD;CACF;CACA,OAAO;AACT;;;;;;;;;ACXA,MAAa,cAAkC;CAC7C,MAAMC,aAAAA;CACN,QAAQ,gBAAgB,EAAE,QAAQ,UAAU,UAAU,EAAE;CACxD,UAAU,OAAO,QAAQ;EACvB,MAAM,QAAQ,KAAK,UAAU,KAAK;EAClC,IAAI,aAAa,QAAQC,oBAAAA,OAAO,WAAW,KAAK,GAAG,KAAK;EACxD,IAAI,aAAa,QAAQC,oBAAAA,WAAW,eAAe,KAAK,GAAG,KAAK;CAClE;AACF"}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { a as allEdgeNames, c as NamedEdge, i as WALL_DEFAULT_THICKNESS, l as Wall, n as validateWall, r as WALL_DEFAULT_HEIGHT, t as wallData } from "./index-tssS_Ed-.cjs";
|
|
2
|
+
import { Collider, EdgeIndex, EnginePlugin } from "@scenography/engine";
|
|
3
|
+
import { Object3D } from "three";
|
|
4
|
+
|
|
5
|
+
//#region src/plugin.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The wall plugin: extrudes each `Wall` into geometry, and — across all walls —
|
|
8
|
+
* publishes the `edges` capability (named anchors artworks hang on) and the
|
|
9
|
+
* `colliders` capability (obstacles the camera can't pass). A single change
|
|
10
|
+
* token covers both, so consumers only rebuild when the walls actually change.
|
|
11
|
+
*/
|
|
12
|
+
declare const wall: () => EnginePlugin<Wall>;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/buildWall.d.ts
|
|
15
|
+
/**
|
|
16
|
+
* Build the three.js object for a `Wall`: one thickened box per path segment,
|
|
17
|
+
* following the polyline at its center. Corners are simple butt joints (boxes
|
|
18
|
+
* overlap slightly), which reads cleanly at a uniform thickness.
|
|
19
|
+
*/
|
|
20
|
+
declare function buildWall(wall: Wall): Object3D;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/colliders.d.ts
|
|
23
|
+
/**
|
|
24
|
+
* Build a collision box for every wall segment (matching the built geometry) —
|
|
25
|
+
* the `colliders` capability the camera controls consume to keep the visitor
|
|
26
|
+
* out of walls.
|
|
27
|
+
*/
|
|
28
|
+
declare function buildColliders(walls: Wall[]): Collider[];
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/edgeIndex.d.ts
|
|
31
|
+
/**
|
|
32
|
+
* Build the `name -> EdgeAnchor` index across every wall — the `edges`
|
|
33
|
+
* capability the artwork plugin consumes to hang pieces on a named segment.
|
|
34
|
+
*/
|
|
35
|
+
declare function indexEdges(walls: Wall[]): EdgeIndex;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type NamedEdge, WALL_DEFAULT_HEIGHT, WALL_DEFAULT_THICKNESS, type Wall, allEdgeNames, buildColliders, buildWall, indexEdges, validateWall, wall, wallData };
|
|
38
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { a as allEdgeNames, c as NamedEdge, i as WALL_DEFAULT_THICKNESS, l as Wall, n as validateWall, r as WALL_DEFAULT_HEIGHT, t as wallData } from "./index-tssS_Ed-.mjs";
|
|
2
|
+
import { Collider, EdgeIndex, EnginePlugin } from "@scenography/engine";
|
|
3
|
+
import { Object3D } from "three";
|
|
4
|
+
|
|
5
|
+
//#region src/plugin.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The wall plugin: extrudes each `Wall` into geometry, and — across all walls —
|
|
8
|
+
* publishes the `edges` capability (named anchors artworks hang on) and the
|
|
9
|
+
* `colliders` capability (obstacles the camera can't pass). A single change
|
|
10
|
+
* token covers both, so consumers only rebuild when the walls actually change.
|
|
11
|
+
*/
|
|
12
|
+
declare const wall: () => EnginePlugin<Wall>;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/buildWall.d.ts
|
|
15
|
+
/**
|
|
16
|
+
* Build the three.js object for a `Wall`: one thickened box per path segment,
|
|
17
|
+
* following the polyline at its center. Corners are simple butt joints (boxes
|
|
18
|
+
* overlap slightly), which reads cleanly at a uniform thickness.
|
|
19
|
+
*/
|
|
20
|
+
declare function buildWall(wall: Wall): Object3D;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/colliders.d.ts
|
|
23
|
+
/**
|
|
24
|
+
* Build a collision box for every wall segment (matching the built geometry) —
|
|
25
|
+
* the `colliders` capability the camera controls consume to keep the visitor
|
|
26
|
+
* out of walls.
|
|
27
|
+
*/
|
|
28
|
+
declare function buildColliders(walls: Wall[]): Collider[];
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/edgeIndex.d.ts
|
|
31
|
+
/**
|
|
32
|
+
* Build the `name -> EdgeAnchor` index across every wall — the `edges`
|
|
33
|
+
* capability the artwork plugin consumes to hang pieces on a named segment.
|
|
34
|
+
*/
|
|
35
|
+
declare function indexEdges(walls: Wall[]): EdgeIndex;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type NamedEdge, WALL_DEFAULT_HEIGHT, WALL_DEFAULT_THICKNESS, type Wall, allEdgeNames, buildColliders, buildWall, indexEdges, validateWall, wall, wallData };
|
|
38
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { a as allEdgeNames, i as WALL_DEFAULT_THICKNESS, n as validateWall, o as edgeEndpoints, r as WALL_DEFAULT_HEIGHT, s as segmentCount, t as wallData } from "./data-PI34E7UF.mjs";
|
|
2
|
+
import { COLLIDERS, EDGES, applyTexture } from "@scenography/engine";
|
|
3
|
+
import { BoxGeometry, Group, Mesh, MeshStandardMaterial } from "three";
|
|
4
|
+
//#region src/buildWall.ts
|
|
5
|
+
/**
|
|
6
|
+
* Build the three.js object for a `Wall`: one thickened box per path segment,
|
|
7
|
+
* following the polyline at its center. Corners are simple butt joints (boxes
|
|
8
|
+
* overlap slightly), which reads cleanly at a uniform thickness.
|
|
9
|
+
*/
|
|
10
|
+
function buildWall(wall) {
|
|
11
|
+
const height = wall.height ?? 300;
|
|
12
|
+
const thickness = wall.thickness ?? 30;
|
|
13
|
+
const material = new MeshStandardMaterial({ color: wall.color ?? "#ffffff" });
|
|
14
|
+
const needsUv1 = wall.texture ? applyTexture(material, wall.texture) : false;
|
|
15
|
+
const group = new Group();
|
|
16
|
+
const segments = segmentCount(wall);
|
|
17
|
+
for (let i = 0; i < segments; i++) {
|
|
18
|
+
const [a, b] = edgeEndpoints(wall, i);
|
|
19
|
+
const dx = b[0] - a[0];
|
|
20
|
+
const dz = b[1] - a[1];
|
|
21
|
+
const length = Math.hypot(dx, dz);
|
|
22
|
+
if (length === 0) continue;
|
|
23
|
+
const geometry = new BoxGeometry(length, height, thickness);
|
|
24
|
+
if (needsUv1) {
|
|
25
|
+
const uv = geometry.getAttribute("uv");
|
|
26
|
+
if (uv) geometry.setAttribute("uv1", uv);
|
|
27
|
+
}
|
|
28
|
+
const box = new Mesh(geometry, material);
|
|
29
|
+
box.position.set((a[0] + b[0]) / 2, height / 2, (a[1] + b[1]) / 2);
|
|
30
|
+
box.rotation.y = Math.atan2(-dz, dx);
|
|
31
|
+
box.castShadow = true;
|
|
32
|
+
box.receiveShadow = true;
|
|
33
|
+
group.add(box);
|
|
34
|
+
}
|
|
35
|
+
group.name = `wall:${wall.id}`;
|
|
36
|
+
group.userData.scenographyId = wall.id;
|
|
37
|
+
return group;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/colliders.ts
|
|
41
|
+
/**
|
|
42
|
+
* Build a collision box for every wall segment (matching the built geometry) —
|
|
43
|
+
* the `colliders` capability the camera controls consume to keep the visitor
|
|
44
|
+
* out of walls.
|
|
45
|
+
*/
|
|
46
|
+
function buildColliders(walls) {
|
|
47
|
+
const colliders = [];
|
|
48
|
+
for (const wall of walls) {
|
|
49
|
+
const halfThickness = (wall.thickness ?? 30) / 2;
|
|
50
|
+
const segments = segmentCount(wall);
|
|
51
|
+
for (let i = 0; i < segments; i++) {
|
|
52
|
+
const [a, b] = edgeEndpoints(wall, i);
|
|
53
|
+
const ex = b[0] - a[0];
|
|
54
|
+
const ez = b[1] - a[1];
|
|
55
|
+
const length = Math.hypot(ex, ez);
|
|
56
|
+
if (length === 0) continue;
|
|
57
|
+
colliders.push({
|
|
58
|
+
cx: (a[0] + b[0]) / 2,
|
|
59
|
+
cz: (a[1] + b[1]) / 2,
|
|
60
|
+
dx: ex / length,
|
|
61
|
+
dz: ez / length,
|
|
62
|
+
halfLength: length / 2,
|
|
63
|
+
halfThickness
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return colliders;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/edgeIndex.ts
|
|
71
|
+
/**
|
|
72
|
+
* Build the `name -> EdgeAnchor` index across every wall — the `edges`
|
|
73
|
+
* capability the artwork plugin consumes to hang pieces on a named segment.
|
|
74
|
+
*/
|
|
75
|
+
function indexEdges(walls) {
|
|
76
|
+
const index = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const wall of walls) {
|
|
78
|
+
const height = wall.height ?? 300;
|
|
79
|
+
const thickness = wall.thickness ?? 30;
|
|
80
|
+
for (const edge of wall.edges ?? []) {
|
|
81
|
+
const [a, b] = edgeEndpoints(wall, edge.segment);
|
|
82
|
+
index.set(edge.name, {
|
|
83
|
+
a,
|
|
84
|
+
b,
|
|
85
|
+
height,
|
|
86
|
+
thickness
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return index;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/plugin.ts
|
|
94
|
+
/**
|
|
95
|
+
* The wall plugin: extrudes each `Wall` into geometry, and — across all walls —
|
|
96
|
+
* publishes the `edges` capability (named anchors artworks hang on) and the
|
|
97
|
+
* `colliders` capability (obstacles the camera can't pass). A single change
|
|
98
|
+
* token covers both, so consumers only rebuild when the walls actually change.
|
|
99
|
+
*/
|
|
100
|
+
const wall = () => ({
|
|
101
|
+
data: wallData,
|
|
102
|
+
build: (definition) => ({ object: buildWall(definition) }),
|
|
103
|
+
provide: (walls, ctx) => {
|
|
104
|
+
const token = JSON.stringify(walls);
|
|
105
|
+
ctx.capabilities.provide(EDGES, indexEdges(walls), token);
|
|
106
|
+
ctx.capabilities.provide(COLLIDERS, buildColliders(walls), token);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
//#endregion
|
|
110
|
+
export { WALL_DEFAULT_HEIGHT, WALL_DEFAULT_THICKNESS, allEdgeNames, buildColliders, buildWall, indexEdges, validateWall, wall, wallData };
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/buildWall.ts","../src/colliders.ts","../src/edgeIndex.ts","../src/plugin.ts"],"sourcesContent":["import { applyTexture } from \"@scenography/engine\";\nimport { BoxGeometry, Group, Mesh, MeshStandardMaterial, type Object3D } from \"three\";\n\nimport {\n WALL_DEFAULT_HEIGHT,\n WALL_DEFAULT_THICKNESS,\n edgeEndpoints,\n segmentCount,\n type Wall,\n} from \"./data\";\n\n/**\n * Build the three.js object for a `Wall`: one thickened box per path segment,\n * following the polyline at its center. Corners are simple butt joints (boxes\n * overlap slightly), which reads cleanly at a uniform thickness.\n */\nexport function buildWall(wall: Wall): Object3D {\n const height = wall.height ?? WALL_DEFAULT_HEIGHT;\n const thickness = wall.thickness ?? WALL_DEFAULT_THICKNESS;\n const material = new MeshStandardMaterial({ color: wall.color ?? \"#ffffff\" });\n const needsUv1 = wall.texture ? applyTexture(material, wall.texture) : false;\n\n const group = new Group();\n const segments = segmentCount(wall);\n for (let i = 0; i < segments; i++) {\n const [a, b] = edgeEndpoints(wall, i);\n const dx = b[0] - a[0];\n const dz = b[1] - a[1];\n const length = Math.hypot(dx, dz);\n if (length === 0) continue;\n\n const geometry = new BoxGeometry(length, height, thickness);\n // aoMap reads the second UV set; box geometry only ships `uv`, so mirror it.\n if (needsUv1) {\n const uv = geometry.getAttribute(\"uv\");\n if (uv) geometry.setAttribute(\"uv1\", uv);\n }\n\n const box = new Mesh(geometry, material);\n box.position.set((a[0] + b[0]) / 2, height / 2, (a[1] + b[1]) / 2);\n // Align the box's local X (its length) with the segment direction.\n box.rotation.y = Math.atan2(-dz, dx);\n box.castShadow = true;\n box.receiveShadow = true;\n group.add(box);\n }\n\n group.name = `wall:${wall.id}`;\n group.userData.scenographyId = wall.id;\n return group;\n}\n","import type { Collider } from \"@scenography/engine\";\n\nimport { WALL_DEFAULT_THICKNESS, edgeEndpoints, segmentCount, type Wall } from \"./data\";\n\n/**\n * Build a collision box for every wall segment (matching the built geometry) —\n * the `colliders` capability the camera controls consume to keep the visitor\n * out of walls.\n */\nexport function buildColliders(walls: Wall[]): Collider[] {\n const colliders: Collider[] = [];\n for (const wall of walls) {\n const halfThickness = (wall.thickness ?? WALL_DEFAULT_THICKNESS) / 2;\n const segments = segmentCount(wall);\n for (let i = 0; i < segments; i++) {\n const [a, b] = edgeEndpoints(wall, i);\n const ex = b[0] - a[0];\n const ez = b[1] - a[1];\n const length = Math.hypot(ex, ez);\n if (length === 0) continue;\n colliders.push({\n cx: (a[0] + b[0]) / 2,\n cz: (a[1] + b[1]) / 2,\n dx: ex / length,\n dz: ez / length,\n halfLength: length / 2,\n halfThickness,\n });\n }\n }\n return colliders;\n}\n","import type { EdgeAnchor, EdgeIndex } from \"@scenography/engine\";\n\nimport {\n WALL_DEFAULT_HEIGHT,\n WALL_DEFAULT_THICKNESS,\n edgeEndpoints,\n type Wall,\n} from \"./data\";\n\n/**\n * Build the `name -> EdgeAnchor` index across every wall — the `edges`\n * capability the artwork plugin consumes to hang pieces on a named segment.\n */\nexport function indexEdges(walls: Wall[]): EdgeIndex {\n const index = new Map<string, EdgeAnchor>();\n for (const wall of walls) {\n const height = wall.height ?? WALL_DEFAULT_HEIGHT;\n const thickness = wall.thickness ?? WALL_DEFAULT_THICKNESS;\n for (const edge of wall.edges ?? []) {\n const [a, b] = edgeEndpoints(wall, edge.segment);\n index.set(edge.name, { a, b, height, thickness });\n }\n }\n return index;\n}\n","import { COLLIDERS, EDGES, type EnginePlugin } from \"@scenography/engine\";\n\nimport { buildWall } from \"./buildWall\";\nimport { buildColliders } from \"./colliders\";\nimport { wallData, type Wall } from \"./data\";\nimport { indexEdges } from \"./edgeIndex\";\n\n/**\n * The wall plugin: extrudes each `Wall` into geometry, and — across all walls —\n * publishes the `edges` capability (named anchors artworks hang on) and the\n * `colliders` capability (obstacles the camera can't pass). A single change\n * token covers both, so consumers only rebuild when the walls actually change.\n */\nexport const wall = (): EnginePlugin<Wall> => ({\n data: wallData,\n build: (definition) => ({ object: buildWall(definition) }),\n provide: (walls, ctx) => {\n const token = JSON.stringify(walls);\n ctx.capabilities.provide(EDGES, indexEdges(walls), token);\n ctx.capabilities.provide(COLLIDERS, buildColliders(walls), token);\n },\n});\n"],"mappings":";;;;;;;;;AAgBA,SAAgB,UAAU,MAAsB;CAC9C,MAAM,SAAS,KAAK,UAAA;CACpB,MAAM,YAAY,KAAK,aAAA;CACvB,MAAM,WAAW,IAAI,qBAAqB,EAAE,OAAO,KAAK,SAAS,UAAU,CAAC;CAC5E,MAAM,WAAW,KAAK,UAAU,aAAa,UAAU,KAAK,OAAO,IAAI;CAEvE,MAAM,QAAQ,IAAI,MAAM;CACxB,MAAM,WAAW,aAAa,IAAI;CAClC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;EACjC,MAAM,CAAC,GAAG,KAAK,cAAc,MAAM,CAAC;EACpC,MAAM,KAAK,EAAE,KAAK,EAAE;EACpB,MAAM,KAAK,EAAE,KAAK,EAAE;EACpB,MAAM,SAAS,KAAK,MAAM,IAAI,EAAE;EAChC,IAAI,WAAW,GAAG;EAElB,MAAM,WAAW,IAAI,YAAY,QAAQ,QAAQ,SAAS;EAE1D,IAAI,UAAU;GACZ,MAAM,KAAK,SAAS,aAAa,IAAI;GACrC,IAAI,IAAI,SAAS,aAAa,OAAO,EAAE;EACzC;EAEA,MAAM,MAAM,IAAI,KAAK,UAAU,QAAQ;EACvC,IAAI,SAAS,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC;EAEjE,IAAI,SAAS,IAAI,KAAK,MAAM,CAAC,IAAI,EAAE;EACnC,IAAI,aAAa;EACjB,IAAI,gBAAgB;EACpB,MAAM,IAAI,GAAG;CACf;CAEA,MAAM,OAAO,QAAQ,KAAK;CAC1B,MAAM,SAAS,gBAAgB,KAAK;CACpC,OAAO;AACT;;;;;;;;ACzCA,SAAgB,eAAe,OAA2B;CACxD,MAAM,YAAwB,CAAC;CAC/B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,iBAAiB,KAAK,aAAA,MAAuC;EACnE,MAAM,WAAW,aAAa,IAAI;EAClC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,KAAK;GACjC,MAAM,CAAC,GAAG,KAAK,cAAc,MAAM,CAAC;GACpC,MAAM,KAAK,EAAE,KAAK,EAAE;GACpB,MAAM,KAAK,EAAE,KAAK,EAAE;GACpB,MAAM,SAAS,KAAK,MAAM,IAAI,EAAE;GAChC,IAAI,WAAW,GAAG;GAClB,UAAU,KAAK;IACb,KAAK,EAAE,KAAK,EAAE,MAAM;IACpB,KAAK,EAAE,KAAK,EAAE,MAAM;IACpB,IAAI,KAAK;IACT,IAAI,KAAK;IACT,YAAY,SAAS;IACrB;GACF,CAAC;EACH;CACF;CACA,OAAO;AACT;;;;;;;AClBA,SAAgB,WAAW,OAA0B;CACnD,MAAM,wBAAQ,IAAI,IAAwB;CAC1C,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,KAAK,UAAA;EACpB,MAAM,YAAY,KAAK,aAAA;EACvB,KAAK,MAAM,QAAQ,KAAK,SAAS,CAAC,GAAG;GACnC,MAAM,CAAC,GAAG,KAAK,cAAc,MAAM,KAAK,OAAO;GAC/C,MAAM,IAAI,KAAK,MAAM;IAAE;IAAG;IAAG;IAAQ;GAAU,CAAC;EAClD;CACF;CACA,OAAO;AACT;;;;;;;;;ACXA,MAAa,cAAkC;CAC7C,MAAM;CACN,QAAQ,gBAAgB,EAAE,QAAQ,UAAU,UAAU,EAAE;CACxD,UAAU,OAAO,QAAQ;EACvB,MAAM,QAAQ,KAAK,UAAU,KAAK;EAClC,IAAI,aAAa,QAAQ,OAAO,WAAW,KAAK,GAAG,KAAK;EACxD,IAAI,aAAa,QAAQ,WAAW,eAAe,KAAK,GAAG,KAAK;CAClE;AACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scenography/plugin-wall",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Wall plugin for scenography: extrudes a top-down path into walls, publishes named edges (for hanging art) and colliders. Data half importable without three.js.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.cjs",
|
|
11
|
+
"module": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.cts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": {
|
|
16
|
+
"types": "./dist/index.d.mts",
|
|
17
|
+
"default": "./dist/index.mjs"
|
|
18
|
+
},
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/index.d.cts",
|
|
21
|
+
"default": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"./data": {
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./dist/data.d.mts",
|
|
27
|
+
"default": "./dist/data.mjs"
|
|
28
|
+
},
|
|
29
|
+
"require": {
|
|
30
|
+
"types": "./dist/data.d.cts",
|
|
31
|
+
"default": "./dist/data.cjs"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@scenography/scene": "0.2.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/three": "^0.160.0",
|
|
40
|
+
"three": "^0.160.0",
|
|
41
|
+
"@scenography/engine": "0.2.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"three": ">=0.160.0",
|
|
45
|
+
"@scenography/engine": "0.2.0"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsdown",
|
|
49
|
+
"dev": "tsdown --watch",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|