@code3d/core 0.0.1-alpha.0 → 0.0.1-alpha.2

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.
Files changed (128) hide show
  1. package/README.md +223 -786
  2. package/THIRD_PARTY.md +40 -0
  3. package/bld/THIRD_PARTY_NOTICES.txt +182 -0
  4. package/bld/chunks/chunk-5E6VXJU2.js +30 -0
  5. package/bld/chunks/chunk-5E6VXJU2.js.map +7 -0
  6. package/bld/chunks/chunk-63ZUQWQ2.js +19 -0
  7. package/bld/chunks/chunk-63ZUQWQ2.js.map +7 -0
  8. package/bld/chunks/chunk-AWYI64EE.js +31 -0
  9. package/bld/chunks/chunk-AWYI64EE.js.map +7 -0
  10. package/bld/chunks/chunk-F53RTQPT.js +24787 -0
  11. package/bld/chunks/chunk-F53RTQPT.js.map +7 -0
  12. package/bld/chunks/chunk-TJIN6S4R.js +1 -0
  13. package/bld/chunks/chunk-TJIN6S4R.js.map +7 -0
  14. package/bld/library/cached.d.ts +33 -0
  15. package/bld/library/cached.d.ts.map +1 -0
  16. package/bld/library/font.d.ts +39 -0
  17. package/bld/library/font.d.ts.map +1 -0
  18. package/bld/library/google-font.d.ts +14 -0
  19. package/bld/library/google-font.d.ts.map +1 -0
  20. package/bld/library/index.d.ts +8 -2
  21. package/bld/library/index.d.ts.map +1 -1
  22. package/bld/library/index.js +60 -3
  23. package/bld/library/index.js.map +7 -1
  24. package/bld/library/kernel-artifact-codec.d.ts.map +1 -1
  25. package/bld/library/kernel-cache.d.ts +17 -6
  26. package/bld/library/kernel-cache.d.ts.map +1 -1
  27. package/bld/library/material.d.ts +1 -1
  28. package/bld/library/material.d.ts.map +1 -1
  29. package/bld/library/open-cascade.d.ts +4 -0
  30. package/bld/library/open-cascade.d.ts.map +1 -0
  31. package/bld/library/replicad.d.ts +3 -2
  32. package/bld/library/replicad.d.ts.map +1 -1
  33. package/bld/library/replicad.js +10 -24
  34. package/bld/library/replicad.js.map +7 -1
  35. package/bld/library/retained-memory.d.ts.map +1 -1
  36. package/bld/library/runtime.d.ts +144 -80
  37. package/bld/library/runtime.d.ts.map +1 -1
  38. package/bld/library/sketch-solver.d.ts +1 -1
  39. package/bld/library/sketch-solver.d.ts.map +1 -1
  40. package/bld/library/sketch.d.ts +9 -1
  41. package/bld/library/sketch.d.ts.map +1 -1
  42. package/bld/library/text.d.ts +53 -0
  43. package/bld/library/text.d.ts.map +1 -0
  44. package/bld/library/three.js +3 -3
  45. package/bld/library/three.js.map +7 -1
  46. package/bld/node/index.d.ts.map +1 -1
  47. package/bld/node/index.js +62 -14
  48. package/bld/node/index.js.map +7 -1
  49. package/bld/node/replicad.js +13 -3
  50. package/bld/node/replicad.js.map +7 -1
  51. package/bld/tooling/index.d.ts +17 -15
  52. package/bld/tooling/index.d.ts.map +1 -1
  53. package/bld/tooling/index.js +147 -19
  54. package/bld/tooling/index.js.map +7 -1
  55. package/package.json +18 -6
  56. package/src/library/cached.ts +132 -0
  57. package/src/library/font.ts +186 -0
  58. package/src/library/google-font.ts +97 -0
  59. package/src/library/index.ts +8 -3
  60. package/src/library/kernel-artifact-codec.ts +129 -20
  61. package/src/library/kernel-cache.ts +111 -33
  62. package/src/library/material.ts +3 -4
  63. package/src/library/open-cascade.ts +13 -0
  64. package/src/library/replicad.ts +5 -5
  65. package/src/library/retained-memory.ts +6 -1
  66. package/src/library/runtime.ts +2049 -1728
  67. package/src/library/sketch-solver.ts +3 -1
  68. package/src/library/sketch.ts +81 -13
  69. package/src/library/text.ts +477 -0
  70. package/src/library/tsconfig.json +2 -1
  71. package/src/node/index.ts +14 -3
  72. package/src/node/tsconfig.json +2 -1
  73. package/src/tooling/index.ts +48 -46
  74. package/src/tooling/tsconfig.json +2 -1
  75. package/bld/library/alignment-geometry.js +0 -322
  76. package/bld/library/alignment-geometry.js.map +0 -1
  77. package/bld/library/bound-solver.js +0 -252
  78. package/bld/library/bound-solver.js.map +0 -1
  79. package/bld/library/extrude.js +0 -28
  80. package/bld/library/extrude.js.map +0 -1
  81. package/bld/library/kernel-artifact-codec.js +0 -148
  82. package/bld/library/kernel-artifact-codec.js.map +0 -1
  83. package/bld/library/kernel-cache.js +0 -245
  84. package/bld/library/kernel-cache.js.map +0 -1
  85. package/bld/library/kernel-shapes.js +0 -108
  86. package/bld/library/kernel-shapes.js.map +0 -1
  87. package/bld/library/loft.js +0 -161
  88. package/bld/library/loft.js.map +0 -1
  89. package/bld/library/material.js +0 -176
  90. package/bld/library/material.js.map +0 -1
  91. package/bld/library/model-color.js +0 -36
  92. package/bld/library/model-color.js.map +0 -1
  93. package/bld/library/open-cascade-error.js +0 -22
  94. package/bld/library/open-cascade-error.js.map +0 -1
  95. package/bld/library/relation-solver.js +0 -258
  96. package/bld/library/relation-solver.js.map +0 -1
  97. package/bld/library/retained-memory.js +0 -27
  98. package/bld/library/retained-memory.js.map +0 -1
  99. package/bld/library/runtime.js +0 -2954
  100. package/bld/library/runtime.js.map +0 -1
  101. package/bld/library/shell.js +0 -221
  102. package/bld/library/shell.js.map +0 -1
  103. package/bld/library/sketch-curve-intersections.js +0 -117
  104. package/bld/library/sketch-curve-intersections.js.map +0 -1
  105. package/bld/library/sketch-curves.js +0 -89
  106. package/bld/library/sketch-curves.js.map +0 -1
  107. package/bld/library/sketch-drag-rules.js +0 -522
  108. package/bld/library/sketch-drag-rules.js.map +0 -1
  109. package/bld/library/sketch-face.js +0 -72
  110. package/bld/library/sketch-face.js.map +0 -1
  111. package/bld/library/sketch-incidence.js +0 -114
  112. package/bld/library/sketch-incidence.js.map +0 -1
  113. package/bld/library/sketch-precision.js +0 -55
  114. package/bld/library/sketch-precision.js.map +0 -1
  115. package/bld/library/sketch-regions.js +0 -193
  116. package/bld/library/sketch-regions.js.map +0 -1
  117. package/bld/library/sketch-solver.js +0 -578
  118. package/bld/library/sketch-solver.js.map +0 -1
  119. package/bld/library/sketch.js +0 -650
  120. package/bld/library/sketch.js.map +0 -1
  121. package/bld/library/spatial.js +0 -195
  122. package/bld/library/spatial.js.map +0 -1
  123. package/bld/library/topology-id.js +0 -67
  124. package/bld/library/topology-id.js.map +0 -1
  125. package/bld/library/topology-inspection.js +0 -267
  126. package/bld/library/topology-inspection.js.map +0 -1
  127. package/bld/library/topology.js +0 -455
  128. package/bld/library/topology.js.map +0 -1
@@ -1,16 +1,17 @@
1
- import type {OpenCascadeInstance} from '@code3d/opencascade';
2
- import {getOC} from 'replicad';
3
- import {estimateRetainedBytes} from './retained-memory.js';
4
1
  import {
5
2
  decodeKernelArtifact,
6
3
  encodeKernelArtifact,
7
4
  } from './kernel-artifact-codec.js';
5
+ import {estimateRetainedBytes} from './retained-memory.js';
8
6
 
9
7
  /** The host opens storage before synchronous evaluation and owns its lifetime. */
10
8
  export interface KernelArtifactStore {
11
9
  get(id: string): Uint8Array | undefined;
10
+ getMany(ids: readonly string[]): readonly (Uint8Array | undefined)[];
12
11
  set(id: string, bytes: Uint8Array): void;
13
12
  touch(id: string): boolean;
13
+ /** Update access order together, returning existence in the same order. */
14
+ touchMany(ids: readonly string[]): readonly boolean[];
14
15
  delete(id: string): void;
15
16
  flush(): void;
16
17
  }
@@ -23,6 +24,11 @@ export type KernelArtifact<Value> = Readonly<{
23
24
  value: Value;
24
25
  }>;
25
26
 
27
+ export type CacheCodec<Value> = Readonly<{
28
+ encoder(value: Value): Uint8Array;
29
+ decoder(bytes: Uint8Array): Value;
30
+ }>;
31
+
26
32
  export type KernelValueLifecycle<Value> = Readonly<{
27
33
  estimateBytes(value: Value): number;
28
34
  retain(value: Value): Value;
@@ -38,7 +44,7 @@ type CacheEntry<Value> = Readonly<{
38
44
  release(value: Value): void;
39
45
  }>;
40
46
 
41
- export function createKernelOperationCache({
47
+ export function createComputationCache({
42
48
  maximumBytes = 2 * 1024 ** 3,
43
49
  nativeAllocatedBytes,
44
50
  }: {
@@ -58,6 +64,7 @@ export function createKernelOperationCache({
58
64
  let persistentWrites = 0;
59
65
  let persistenceErrors = 0;
60
66
  const persisted = new Set<string>();
67
+ const pendingPersistence = new Map<string, () => Uint8Array>();
61
68
  let externalBytes = 0;
62
69
 
63
70
  /** The host accounts for in-flight inputs and all auxiliary native heaps. */
@@ -69,6 +76,7 @@ export function createKernelOperationCache({
69
76
  function setKernelArtifactStore(next: KernelArtifactStore | undefined): void {
70
77
  store = next;
71
78
  persisted.clear();
79
+ pendingPersistence.clear();
72
80
  }
73
81
 
74
82
  function accessStore<Result>(
@@ -97,6 +105,7 @@ export function createKernelOperationCache({
97
105
  const used = new Set<string>();
98
106
  currentEvaluation = {used, checkCancelled};
99
107
  return () => {
108
+ flushPendingPersistence();
100
109
  for (const id of retainedEvaluation) {
101
110
  if (!used.has(id)) historicalEntries.set(id, entries.get(id)!);
102
111
  }
@@ -107,39 +116,65 @@ export function createKernelOperationCache({
107
116
  };
108
117
  }
109
118
 
110
- /**
111
- * Reuses one complete, deterministic kernel operation. Arguments describe
112
- * scalar semantics; inputs carry the content identities of prior operations.
113
- * The lifecycle keeps the retained value independent from each disposable use.
114
- */
115
- function evaluateKernelOperation<Value>(
116
- operation: string,
117
- arguments_: readonly KernelKeyPart[],
118
- inputs: readonly KernelArtifact<unknown>[],
119
+ function evaluateCachedArtifact<Value>(
120
+ key: KernelOperationKey,
119
121
  lifecycle: KernelValueLifecycle<Value>,
120
122
  compute: () => Value,
123
+ codec?: CacheCodec<Value> | false,
121
124
  ): KernelArtifact<Value> {
122
- const key = kernelOperationKey(operation, arguments_, inputs);
123
- const cached = findKernelOperation(key, lifecycle);
124
- if (cached) return cached;
125
+ const hit = findKernelOperation(key, lifecycle, codec);
126
+ if (hit) return hit;
125
127
  const value = compute();
126
- acceptKernelOperation(key, lifecycle, value);
128
+ acceptKernelOperation(key, lifecycle, value, codec);
127
129
  return {id: key.id, value};
128
130
  }
129
131
 
130
132
  function findKernelOperation<Value>(
131
133
  key: KernelOperationKey,
132
134
  lifecycle: KernelValueLifecycle<Value>,
135
+ codec?: CacheCodec<Value> | false,
136
+ ): KernelArtifact<Value> | undefined {
137
+ return lookup(key, lifecycle, codec, () =>
138
+ accessStore(store => store.get(key.id)),
139
+ );
140
+ }
141
+
142
+ function findKernelOperations<Value>(
143
+ keys: readonly KernelOperationKey[],
144
+ lifecycle: KernelValueLifecycle<Value>,
145
+ codec?: CacheCodec<Value> | false,
146
+ ): readonly (KernelArtifact<Value> | undefined)[] {
147
+ currentEvaluation?.checkCancelled?.();
148
+ const missing =
149
+ codec === false ? [] : keys.filter(key => !entries.has(key.id));
150
+ const bytes = missing.length
151
+ ? accessStore(store => store.getMany(missing.map(key => key.id)))
152
+ : undefined;
153
+ const restored = new Map(
154
+ missing.map((key, index) => [key.id, bytes?.[index]]),
155
+ );
156
+ return keys.map(key =>
157
+ lookup(key, lifecycle, codec, () => restored.get(key.id)),
158
+ );
159
+ }
160
+
161
+ function lookup<Value>(
162
+ key: KernelOperationKey,
163
+ lifecycle: KernelValueLifecycle<Value>,
164
+ codec: CacheCodec<Value> | false | undefined,
165
+ read: () => Uint8Array | undefined,
133
166
  ): KernelArtifact<Value> | undefined {
134
167
  currentEvaluation?.checkCancelled?.();
135
168
  const {id, signature} = key;
136
169
  let cached = entries.get(id) as CacheEntry<Value> | undefined;
137
- if (!cached) {
138
- const bytes = accessStore(store => store.get(id));
170
+ if (!cached && codec !== false) {
171
+ const bytes = read();
139
172
  if (bytes) {
140
173
  let restored: Value;
141
174
  try {
142
- restored = decodeKernelArtifact<Value>(bytes, signature);
175
+ restored = codec
176
+ ? codec.decoder(decodeKernelArtifact<Uint8Array>(bytes, signature))
177
+ : decodeKernelArtifact<Value>(bytes, signature);
143
178
  } catch {
144
179
  persistenceErrors += 1;
145
180
  accessStore(store => store.delete(id));
@@ -159,7 +194,7 @@ export function createKernelOperationCache({
159
194
  throw new Error(`Kernel operation cache identity collision: ${id}`);
160
195
  hits += 1;
161
196
  const value = cached.instantiate(cached.value);
162
- persist(key, cached.value);
197
+ if (codec !== false) persist(key, cached.value, codec, true);
163
198
  touchEntry(id, cached as CacheEntry<unknown>);
164
199
  return {id, value};
165
200
  }
@@ -169,6 +204,7 @@ export function createKernelOperationCache({
169
204
  key: KernelOperationKey,
170
205
  lifecycle: KernelValueLifecycle<Value>,
171
206
  value: Value,
207
+ codec?: CacheCodec<Value> | false,
172
208
  ): void {
173
209
  const existing = entries.get(key.id);
174
210
  if (existing) {
@@ -185,21 +221,53 @@ export function createKernelOperationCache({
185
221
  throw error;
186
222
  }
187
223
  const entry = retainEntry(key, lifecycle, retained);
188
- persist(key, retained);
224
+ if (codec !== false) persist(key, retained, codec);
189
225
  touchEntry(key.id, entry as CacheEntry<unknown>);
190
226
  }
191
227
 
192
- function persist(key: KernelOperationKey, value: unknown): void {
228
+ function persist<Value>(
229
+ key: KernelOperationKey,
230
+ value: Value,
231
+ codec?: CacheCodec<Value>,
232
+ defer = false,
233
+ ): void {
193
234
  if (!store || persisted.has(key.id)) return;
235
+ const encode = () =>
236
+ encodeKernelArtifact(
237
+ key.signature,
238
+ codec ? Uint8Array.from(codec.encoder(value)) : value,
239
+ );
240
+ if (defer && currentEvaluation) {
241
+ pendingPersistence.set(key.id, encode);
242
+ return;
243
+ }
194
244
  accessStore(store => {
195
- if (!store.touch(key.id)) {
196
- store.set(key.id, encodeKernelArtifact(key.signature, value));
245
+ // A completed computation follows a miss; write it without another lookup.
246
+ if (!defer || !store.touch(key.id)) {
247
+ store.set(key.id, encode());
197
248
  persistentWrites += 1;
198
249
  }
199
250
  persisted.add(key.id);
200
251
  });
201
252
  }
202
253
 
254
+ /** Memory hits need one transaction, while newly computed work is saved immediately. */
255
+ function flushPendingPersistence(): void {
256
+ if (!pendingPersistence.size) return;
257
+ accessStore(store => {
258
+ const ids = [...pendingPersistence.keys()];
259
+ const present = store.touchMany(ids);
260
+ ids.forEach((id, index) => {
261
+ if (!present[index]) {
262
+ store.set(id, pendingPersistence.get(id)!());
263
+ persistentWrites += 1;
264
+ }
265
+ persisted.add(id);
266
+ });
267
+ });
268
+ pendingPersistence.clear();
269
+ }
270
+
203
271
  function retainEntry<Value>(
204
272
  key: KernelOperationKey,
205
273
  lifecycle: KernelValueLifecycle<Value>,
@@ -246,6 +314,7 @@ export function createKernelOperationCache({
246
314
  persistentWrites = 0;
247
315
  persistenceErrors = 0;
248
316
  persisted.clear();
317
+ pendingPersistence.clear();
249
318
  }
250
319
 
251
320
  function kernelOperationCacheStats() {
@@ -279,29 +348,37 @@ export function createKernelOperationCache({
279
348
  }
280
349
 
281
350
  return {
351
+ evaluateCachedArtifact,
282
352
  beginKernelOperationEvaluation,
283
- evaluateKernelOperation,
284
353
  clearKernelOperationCache,
285
354
  kernelOperationCacheStats,
286
355
  setKernelArtifactStore,
287
356
  findKernelOperation,
357
+ findKernelOperations,
288
358
  acceptKernelOperation,
289
359
  setKernelExternalBytes,
290
360
  };
291
361
  }
292
362
 
363
+ let nativeMemoryCounter = () => 0;
364
+
365
+ /** The installed backend supplies native accounting; pure caches need no kernel. */
366
+ export function setKernelNativeMemoryCounter(read: () => number): void {
367
+ nativeMemoryCounter = read;
368
+ }
369
+
293
370
  export const {
371
+ evaluateCachedArtifact,
294
372
  beginKernelOperationEvaluation,
295
- evaluateKernelOperation,
296
373
  clearKernelOperationCache,
297
374
  kernelOperationCacheStats,
298
375
  setKernelArtifactStore,
299
376
  findKernelOperation,
377
+ findKernelOperations,
300
378
  acceptKernelOperation,
301
379
  setKernelExternalBytes,
302
- } = createKernelOperationCache({
303
- nativeAllocatedBytes: () =>
304
- (getOC() as OpenCascadeInstance).Code3dMemory.AllocatedBytes(),
380
+ } = createComputationCache({
381
+ nativeAllocatedBytes: () => nativeMemoryCounter(),
305
382
  });
306
383
 
307
384
  export type KernelOperationKey = Readonly<{id: string; signature: string}>;
@@ -316,16 +393,17 @@ export function kernelOperationKey(
316
393
  arguments_,
317
394
  inputs.map(input => input.id),
318
395
  ]);
319
- return {id: contentId(signature), signature};
396
+ return {id: kernelContentId(signature), signature};
320
397
  }
321
398
 
322
- function contentId(value: string): string {
399
+ export function kernelContentId(value: string | Uint8Array): string {
323
400
  let first = 0x811c9dc5;
324
401
  let second = 0x9e3779b9;
325
402
  let third = 0x85ebca6b;
326
403
  let fourth = 0xc2b2ae35;
327
404
  for (let index = 0; index < value.length; index += 1) {
328
- const code = value.charCodeAt(index);
405
+ const code =
406
+ typeof value === 'string' ? value.charCodeAt(index) : value[index];
329
407
  first = Math.imul(first ^ code, 0x01000193);
330
408
  second = Math.imul(second ^ code, 0x27d4eb2d);
331
409
  third = Math.imul(third ^ code, 0x165667b1);
@@ -6,7 +6,7 @@ import {
6
6
  type SerializedImage,
7
7
  type Texture,
8
8
  type TypedArray,
9
- } from './three.js';
9
+ } from 'three';
10
10
  import {parseModelColor} from './model-color.js';
11
11
 
12
12
  /** A color selects the default material for each geometry kind. */
@@ -52,14 +52,13 @@ export function captureModelMaterial(
52
52
  }
53
53
  }
54
54
  if ('isShaderMaterial' in input) {
55
- const shader = input as import('./three.js').ShaderMaterial;
55
+ const shader = input as import('three').ShaderMaterial;
56
56
  if (
57
57
  shader.uniformsGroups.length ||
58
58
  shader.index0AttributeName !== undefined ||
59
59
  JSON.stringify(shader.defaultAttributeValues) !==
60
60
  JSON.stringify(
61
- (restored as import('./three.js').ShaderMaterial)
62
- .defaultAttributeValues,
61
+ (restored as import('three').ShaderMaterial).defaultAttributeValues,
63
62
  )
64
63
  ) {
65
64
  throw new Error(
@@ -0,0 +1,13 @@
1
+ import type {OpenCascadeInstance} from '@code3d/opencascade';
2
+ import {setOC} from 'replicad';
3
+ import {
4
+ clearKernelOperationCache,
5
+ setKernelNativeMemoryCounter,
6
+ } from './kernel-cache.js';
7
+
8
+ /** Install the backend and its memory accounting for Node and hosted runtimes. */
9
+ export function installOpenCascade(openCascade: OpenCascadeInstance): void {
10
+ clearKernelOperationCache();
11
+ setOC(openCascade);
12
+ setKernelNativeMemoryCounter(() => openCascade.Code3dMemory.AllocatedBytes());
13
+ }
@@ -1,5 +1,5 @@
1
1
  import * as replicadModule from 'replicad';
2
- import {modelFromReplicadSolid} from './runtime.js';
2
+ import {primitiveConstructor} from './runtime.js';
3
3
  import {castOwnedShape} from './kernel-shapes.js';
4
4
  import type {SolidModel} from './index.js';
5
5
  import type {Shape3D} from 'replicad';
@@ -29,12 +29,12 @@ export const replicad: Replicad = Object.freeze({
29
29
 
30
30
  /**
31
31
  * Defines a synchronous model constructor with the builder's parameters.
32
- * The builder runs on every call and transfers ownership of its returned solid
33
- * to code3d. Intermediate shapes remain the builder's responsibility.
32
+ * Reuses deterministic geometry by arguments; pass changing captured state as
33
+ * explicit parameters. Each invocation creates a fresh model. The builder
34
+ * transfers its returned solid to code3d and owns its intermediate shapes.
34
35
  */
35
36
  export function definePrimitive<
36
37
  Builder extends (...arguments_: never[]) => Shape3D,
37
38
  >(build: Builder): (...arguments_: Parameters<Builder>) => SolidModel {
38
- return (...arguments_: Parameters<Builder>) =>
39
- modelFromReplicadSolid(build(...arguments_));
39
+ return primitiveConstructor(build);
40
40
  }
@@ -12,7 +12,12 @@ export function estimateRetainedBytes(value: unknown): number {
12
12
  seen.add(value);
13
13
  if (ArrayBuffer.isView(value)) return 64 + visit(value.buffer);
14
14
  if (value instanceof ArrayBuffer) return 32 + value.byteLength;
15
- const values = Object.values(value);
15
+ const values =
16
+ value instanceof Map
17
+ ? [...value].flat()
18
+ : value instanceof Set
19
+ ? [...value]
20
+ : Object.values(value);
16
21
  return (
17
22
  32 +
18
23
  values.length * 8 +