@drawcall/charta 0.1.17 → 0.1.18

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.
@@ -1,10 +1,22 @@
1
1
  import { LoadingManager, Loader } from 'three';
2
2
  import { Interpreter } from '../interpreter.js';
3
+ export type AssetLoaderOptions = {
4
+ /**
5
+ * Mock mode: skips actual asset loading and creates placeholder objects.
6
+ * Useful for server-side validation. Default: false.
7
+ */
8
+ mock?: boolean;
9
+ /**
10
+ * Skip texture loading entirely. When true, loadTexture calls are ignored.
11
+ * Default: false.
12
+ */
13
+ skipTextureLoading?: boolean;
14
+ };
3
15
  export declare class AssetLoader extends Loader<void, Interpreter> {
4
- private readonly mock;
5
16
  private textureLoader;
6
17
  private gltfLoader;
7
- constructor(manager?: LoadingManager, mock?: boolean);
18
+ private readonly options;
19
+ constructor(manager?: LoadingManager, options?: AssetLoaderOptions);
8
20
  load(interpreter: Interpreter, onLoad: (data: void) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): void;
9
21
  private handleLoadTexture;
10
22
  private handleLoadModel;
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,cAAc,EAAqB,MAAM,EAAW,MAAM,OAAO,CAAA;AAEzG,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAM/C,qBAAa,WAAY,SAAQ,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC;IAIlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAH3D,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,UAAU,CAAY;gBAElB,OAAO,CAAC,EAAE,cAAc,EAAmB,IAAI,GAAE,OAAe;IAM5E,IAAI,CACF,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,EAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAC/B,IAAI;YAuBO,iBAAiB;YA8BjB,eAAe;CAuC9B"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/assets/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,cAAc,EAAqB,MAAM,EAAW,MAAM,OAAO,CAAA;AAEzG,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAM/C,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,qBAAa,WAAY,SAAQ,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC;IACxD,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;gBAEhC,OAAO,CAAC,EAAE,cAAc,EAAE,OAAO,GAAE,kBAAuB;IAOtE,IAAI,CACF,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,EAC5B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAC3C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAC/B,IAAI;YAyBO,iBAAiB;YA8BjB,eAAe;CAuC9B"}
@@ -5,14 +5,14 @@ import { InstancedMeshGroup } from '../utils/instanced-mesh-group.js';
5
5
  import { measureObject, PrefabBatchBuilder } from '../place/index.js';
6
6
  import { basePathSchema, loadTextureSchema, loadModelSchema } from '../schemas.js';
7
7
  export class AssetLoader extends Loader {
8
- mock;
9
8
  textureLoader;
10
9
  gltfLoader;
11
- constructor(manager, mock = false) {
10
+ options;
11
+ constructor(manager, options = {}) {
12
12
  super(manager);
13
- this.mock = mock;
14
13
  this.textureLoader = new TextureLoader(manager);
15
14
  this.gltfLoader = new GLTFLoader(manager);
15
+ this.options = options;
16
16
  }
17
17
  load(interpreter, onLoad, onProgress, onError) {
18
18
  const calls = interpreter.getCalls(undefined, {
@@ -27,7 +27,9 @@ export class AssetLoader extends Loader {
27
27
  basePath = args.path.length === 0 ? undefined : args.path;
28
28
  }
29
29
  else if (key === 'loadTexture') {
30
- promises.push(this.handleLoadTexture(interpreter, args.name, basePath, args.path, location));
30
+ if (!this.options.skipTextureLoading) {
31
+ promises.push(this.handleLoadTexture(interpreter, args.name, basePath, args.path, location));
32
+ }
31
33
  }
32
34
  else if (key === 'loadModel') {
33
35
  promises.push(this.handleLoadModel(interpreter, args.name, basePath, args.path, location));
@@ -38,7 +40,7 @@ export class AssetLoader extends Loader {
38
40
  .catch((reason) => onError?.(reason));
39
41
  }
40
42
  async handleLoadTexture(interpreter, name, basePath, path, location) {
41
- if (this.mock) {
43
+ if (this.options.mock) {
42
44
  const texture = new Texture();
43
45
  texture.name = name;
44
46
  interpreter.setAsset(`${name}BaseColorTexture`, texture);
@@ -55,7 +57,7 @@ export class AssetLoader extends Loader {
55
57
  }
56
58
  }
57
59
  async handleLoadModel(interpreter, name, basePath, path, location) {
58
- if (this.mock) {
60
+ if (this.options.mock) {
59
61
  const batchBuilder = new PrefabBatchBuilder(new Vector3(), () => new Object3D());
60
62
  interpreter.setAsset(`${name}Prefab`, batchBuilder);
61
63
  return;
@@ -28,11 +28,7 @@ export type PlaceGroupOptions = {
28
28
  * computation and instance generation. Useful for server-side validation. Default: false.
29
29
  */
30
30
  mock?: boolean;
31
- /**
32
- * Skip the final build() call on batch builders. Computes all placements but doesn't
33
- * create the final Object3D instances. Useful for testing placement logic. Default: false.
34
- */
35
- skipBuild?: boolean;
31
+ skipModelInstantiation?: boolean;
36
32
  };
37
33
  export declare class PlaceGroup extends Group {
38
34
  readonly batchBuilders: Map<string, PrefabBatchBuilder>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/place/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAQ,MAAM,OAAO,CAAA;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAO/C,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;AAEvD,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE;IACvC,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,WAAW,CAAA;IACxB,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;IAC5D,IAAI,EAAE,MAAM,CAAA;CACb,KAAK,IAAI,CAAA;AAKV,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAOvD;AAED,qBAAa,kBAAkB;aAIX,UAAU,EAAE,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAJpC,SAAgB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAK;gBAG3B,UAAU,EAAE,OAAO,EAClB,iBAAiB,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ;IAG5E,GAAG,CAAC,MAAM,EAAE,OAAO;IAKZ,KAAK,IAAI,QAAQ;CAGzB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,aAAa,kCAAwC;gBAEzD,WAAW,EAAE,WAAW,EAAE,iBAAiB,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAE,iBAAsB;IAuPhG,OAAO;CAOR"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/place/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAQ,MAAM,OAAO,CAAA;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAO/C,MAAM,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;AAEvD,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE;IACvC,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,WAAW,CAAA;IACxB,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;IAC5D,IAAI,EAAE,MAAM,CAAA;CACb,KAAK,IAAI,CAAA;AAKV,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAOvD;AAED,qBAAa,kBAAkB;aAIX,UAAU,EAAE,OAAO;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAJpC,SAAgB,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAK;gBAG3B,UAAU,EAAE,OAAO,EAClB,iBAAiB,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,QAAQ;IAG5E,GAAG,CAAC,MAAM,EAAE,OAAO;IAKZ,KAAK,IAAI,QAAQ;CAGzB;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,sBAAsB,CAAC,EAAE,OAAO,CAAA;CACjC,CAAA;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,aAAa,kCAAwC;gBAEzD,WAAW,EAAE,WAAW,EAAE,iBAAiB,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAE,iBAAsB;IAuPhG,OAAO;CAOR"}
@@ -34,7 +34,7 @@ export class PlaceGroup extends Group {
34
34
  batchBuilders = new Map();
35
35
  constructor(interpreter, _materialFallback, opts = {}) {
36
36
  super();
37
- const { mock = false, skipBuild = false } = opts;
37
+ const { mock = false, skipModelInstantiation: skipBuild = false } = opts;
38
38
  const rows = interpreter.getRows();
39
39
  const cols = interpreter.getCols();
40
40
  const cellSize = interpreter.getCellSize();
@@ -9,6 +9,7 @@ export type TilesMeshOptions = {
9
9
  * Useful for server-side validation. Default: false.
10
10
  */
11
11
  mock?: boolean;
12
+ skipTextureLoading?: boolean;
12
13
  };
13
14
  export declare class TilesMesh extends Mesh<TilesGeometry> {
14
15
  constructor(interpreter: Interpreter, material?: Material, options?: TilesMeshOptions);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tiles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,IAAI,EAOL,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAA;AAIlE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAc,MAAM,eAAe,CAAA;AAEvE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAA;AAEtC,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAyCD,qBAAa,SAAU,SAAQ,IAAI,CAAC,aAAa,CAAC;gBACpC,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAkC,EAAE,OAAO,GAAE,gBAAqB;CA0JnH"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tiles/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,IAAI,EAOL,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAA;AAIlE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAc,MAAM,eAAe,CAAA;AAEvE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAA;AAEtC,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAyCD,qBAAa,SAAU,SAAQ,IAAI,CAAC,aAAa,CAAC;gBACpC,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAkC,EAAE,OAAO,GAAE,gBAAqB;CAiInH"}
@@ -34,39 +34,10 @@ export class TilesMesh extends Mesh {
34
34
  constructor(interpreter, material = new MeshBasicMaterial(), options = {}) {
35
35
  const rows = interpreter.getRows();
36
36
  const cols = interpreter.getCols();
37
- // Mock mode: validate calls exist but skip geometry creation
38
- if (options.mock) {
39
- super(undefined);
40
- for (let row = 0; row < rows; row++) {
41
- for (let col = 0; col < cols; col++) {
42
- // Validate all ground/ceiling/wall calls and their parameters
43
- const calls = interpreter.getCalls([row, col], {
44
- ground: groundSchema,
45
- ceiling: ceilingSchema,
46
- wall: wallSchema,
47
- });
48
- // Also validate wall heights using the helper
49
- resolveHeights([row, col], calls.map(([_1, parsed, _2, loc]) => ({
50
- loc,
51
- layerY: 'y' in parsed ? parsed.y : undefined,
52
- explicitWallY: 'bottomY' in parsed ? parsed.bottomY : undefined,
53
- })), interpreter, false);
54
- resolveHeights([row, col], calls.map(([_1, parsed, _2, loc]) => ({
55
- loc,
56
- layerY: 'y' in parsed ? parsed.y : undefined,
57
- explicitWallY: 'topY' in parsed ? parsed.topY : undefined,
58
- })), interpreter, true);
59
- // Validate texture references
60
- for (const [name, parsed, , loc] of calls) {
61
- if (name === 'ground' || name === 'ceiling') {
62
- interpreter.getAsset(Texture, `${parsed.texture}BaseColorTexture`, loc);
63
- }
64
- }
65
- }
66
- }
67
- return;
68
- }
69
- // Helper to manage texture indices on the fly
37
+ const { mock = false, skipTextureLoading = false } = options;
38
+ const createGeometry = !mock;
39
+ const createMaterial = !mock && !skipTextureLoading;
40
+ // Texture index tracking (only used when creating materials)
70
41
  const textureIndex = new Map();
71
42
  const getTextureIndex = (name, loc) => {
72
43
  const texture = interpreter.getAsset(Texture, `${name}BaseColorTexture`, loc);
@@ -79,23 +50,27 @@ export class TilesMesh extends Mesh {
79
50
  }
80
51
  return idx;
81
52
  };
82
- // Initialize grid structures
83
- const tiles = Array.from({ length: rows }, () => Array.from({ length: cols }, () => []));
84
- const walls = Array.from({ length: rows }, () => Array.from({ length: cols }, () => ({
85
- top: [],
86
- bottom: [],
87
- left: [],
88
- right: [],
89
- })));
53
+ // Initialize grid structures (only needed for geometry)
54
+ const tiles = createGeometry
55
+ ? Array.from({ length: rows }, () => Array.from({ length: cols }, () => []))
56
+ : null;
57
+ const walls = createGeometry
58
+ ? Array.from({ length: rows }, () => Array.from({ length: cols }, () => ({
59
+ top: [],
60
+ bottom: [],
61
+ left: [],
62
+ right: [],
63
+ })))
64
+ : null;
90
65
  for (let row = 0; row < rows; row++) {
91
66
  for (let col = 0; col < cols; col++) {
92
- // 1. Collect all entries for this cell
67
+ // Collect and validate all entries for this cell
93
68
  const calls = Array.from(interpreter.getCalls([row, col], {
94
69
  ground: groundSchema,
95
70
  ceiling: ceilingSchema,
96
71
  wall: wallSchema,
97
72
  }));
98
- // 2. Compute wall heights using the helper
73
+ // Compute/validate wall heights
99
74
  const bottomYs = resolveHeights([row, col], calls.map(([_1, parsed, _2, loc]) => ({
100
75
  loc,
101
76
  layerY: 'y' in parsed ? parsed.y : undefined,
@@ -106,7 +81,7 @@ export class TilesMesh extends Mesh {
106
81
  layerY: 'y' in parsed ? parsed.y : undefined,
107
82
  explicitWallY: 'topY' in parsed ? parsed.topY : undefined,
108
83
  })), interpreter, true);
109
- // 3. Populate data structures
84
+ // Populate data structures and/or validate
110
85
  for (let i = 0; i < calls.length; i++) {
111
86
  const [name, parsed, _, loc] = calls[i];
112
87
  if (name === 'wall') {
@@ -119,32 +94,44 @@ export class TilesMesh extends Mesh {
119
94
  ;
120
95
  [bottomY, topY] = [topY, bottomY];
121
96
  }
122
- const dir = parsed.dir;
123
- if (walls[row][col][dir]) {
97
+ if (createGeometry) {
98
+ const dir = parsed.dir;
124
99
  walls[row][col][dir].push({ bottomY, topY });
125
100
  }
126
101
  }
127
102
  else {
128
103
  // Ground or Ceiling
129
- tiles[row][col].push({
130
- type: name,
131
- y: parsed.y,
132
- textureId: getTextureIndex(parsed.texture, loc),
133
- row,
134
- col,
135
- });
104
+ if (createGeometry) {
105
+ tiles[row][col].push({
106
+ type: name,
107
+ y: parsed.y,
108
+ textureId: createMaterial ? getTextureIndex(parsed.texture, loc) : 0,
109
+ row,
110
+ col,
111
+ });
112
+ }
113
+ else if (!skipTextureLoading) {
114
+ // Validate texture exists in mock mode (unless mockTexture is set)
115
+ interpreter.getAsset(Texture, `${parsed.texture}BaseColorTexture`, loc);
116
+ }
136
117
  }
137
118
  }
138
119
  }
139
120
  }
121
+ if (!createGeometry) {
122
+ super(undefined);
123
+ return;
124
+ }
140
125
  const cellSize = interpreter.getCellSize();
141
126
  const geometry = new TilesGeometry(tiles, walls, cols * cellSize, rows * cellSize);
142
127
  super(geometry);
143
128
  interpreter.setAsset('tilesGeometry', geometry);
144
- // Build texture array from interpreter assets using encountered material names in insertion order
145
- const texturesInOrder = Array.from(textureIndex.keys()).sort((a, b) => textureIndex.get(a) - textureIndex.get(b));
146
- if (texturesInOrder.length > 0) {
147
- this.material = buildTilesMaterial(material, buildTextureArrayFromAssets(texturesInOrder));
129
+ // Build material from textures
130
+ if (createMaterial) {
131
+ const texturesInOrder = Array.from(textureIndex.keys()).sort((a, b) => textureIndex.get(a) - textureIndex.get(b));
132
+ if (texturesInOrder.length > 0) {
133
+ this.material = buildTilesMaterial(material, buildTextureArrayFromAssets(texturesInOrder));
134
+ }
148
135
  }
149
136
  }
150
137
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawcall/charta",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "author": "Bela Bohlender",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://drawcall.ai",