@metamesh/modeling 0.10.0 → 0.11.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +56 -17
  3. package/dist/api/engine.d.ts +105 -8
  4. package/dist/api/index.d.ts +754 -771
  5. package/dist/engine/construction-operations.js +3 -1
  6. package/dist/engine/deferred-context.js +182 -0
  7. package/dist/engine/execution.js +38 -4
  8. package/dist/engine/finalization.js +65 -133
  9. package/dist/engine/geometry-recipes.js +12 -0
  10. package/dist/engine/immutable-generation-data.js +186 -0
  11. package/dist/engine/index.js +57 -35
  12. package/dist/engine/kernel/manifold.wasm +0 -0
  13. package/dist/engine/model-dependencies.js +46 -0
  14. package/dist/engine/model-summary.js +43 -0
  15. package/dist/engine/native/ownership.js +11 -5
  16. package/dist/engine/placement.js +24 -0
  17. package/dist/engine/recipe-realization.js +119 -0
  18. package/dist/engine/session-graph.js +442 -0
  19. package/dist/engine/session-native.js +90 -0
  20. package/dist/engine/session-snapshot.js +153 -0
  21. package/dist/engine/session.js +184 -0
  22. package/dist/engine/shape-anchors.js +5 -0
  23. package/dist/geometry/mesh-centroid.js +7 -6
  24. package/dist/geometry/mesh-planar.js +11 -10
  25. package/dist/geometry/mesh-quality.js +15 -14
  26. package/dist/geometry/mesh-signature.js +8 -7
  27. package/dist/geometry/mesh-solid.js +10 -4
  28. package/dist/geometry/mesh.js +36 -31
  29. package/dist/index.js +2 -0
  30. package/dist/model/execution-binding.js +5 -5
  31. package/dist/model/generation.js +27 -0
  32. package/dist/model/immutable-buffer.js +111 -0
  33. package/dist/model/modeling-context.js +1 -0
  34. package/dist/model/operations.js +521 -160
  35. package/dist/model/shape-handles.js +44 -0
  36. package/package.json +4 -4
@@ -0,0 +1,111 @@
1
+ const constructors = { Float32Array, Float64Array, Uint32Array, Uint8Array, Int32Array };
2
+ const protocol = Symbol.for("@metamesh/modeling/immutable-buffer/1");
3
+ const storage = new WeakMap();
4
+ const adopted = new WeakMap();
5
+ /**
6
+ * Copies numeric data once into private storage. This pure helper needs no active generation.
7
+ * @example
8
+ * ```ts
9
+ * import { immutableBuffer } from "@metamesh/modeling";
10
+ * const heights = immutableBuffer(new Float32Array([2, 4, 6]));
11
+ * const count = heights.length;
12
+ * const first = heights.at(0);
13
+ * const editable = heights.copy();
14
+ * editable[0] = 8; // heights still contains 2, 4, 6.
15
+ * ```
16
+ */
17
+ export function immutableBuffer(source) {
18
+ const entry = Object.entries(constructors).find(([, constructor]) => source instanceof constructor);
19
+ if (entry === undefined)
20
+ throw new TypeError("immutableBuffer requires a supported numeric typed array.");
21
+ const [kind, constructor] = entry;
22
+ const owned = new constructor(source);
23
+ const length = owned.length;
24
+ const result = Object.freeze({
25
+ [protocol]: kind,
26
+ length,
27
+ at: (index) => {
28
+ const offset = index < 0 ? length + index : index;
29
+ return Number.isInteger(offset) && offset >= 0 && offset < length ? owned[offset] : undefined;
30
+ },
31
+ copy: () => new constructor(owned),
32
+ });
33
+ storage.set(result, owned);
34
+ return result;
35
+ }
36
+ /**
37
+ * Copies mesh buffers into immutable data; geometric validation still occurs when modeling or finalizing.
38
+ * @example
39
+ * ```ts
40
+ * import { generate, immutableMesh } from "@metamesh/modeling";
41
+ * import { heightfieldMesh } from "@metamesh/modeling/geometry";
42
+ * const model = generate(({ computed, part }) => {
43
+ * const surface = computed("surface", () => immutableMesh(heightfieldMesh({
44
+ * size: [10, 10], segments: [8, 8], height: () => 2,
45
+ * })));
46
+ * return [part("surface", surface)];
47
+ * });
48
+ * ```
49
+ */
50
+ export function immutableMesh(mesh) {
51
+ const { positions, indices } = mesh;
52
+ if (!(positions instanceof Float32Array) || !(indices instanceof Uint32Array))
53
+ throw new TypeError("immutableMesh requires Float32 positions and Uint32 indices.");
54
+ return Object.freeze({
55
+ positions: immutableBuffer(positions),
56
+ indices: immutableBuffer(indices),
57
+ });
58
+ }
59
+ /** Recognizes the versioned cross-bundle protocol without invoking foreign callbacks. */
60
+ export function isImmutableBuffer(value) {
61
+ if (typeof value !== "object" || value === null)
62
+ return false;
63
+ if (storage.has(value))
64
+ return true;
65
+ if (!Object.isFrozen(value))
66
+ return false;
67
+ const field = (key) => {
68
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
69
+ return descriptor !== undefined && "value" in descriptor ? descriptor.value : undefined;
70
+ };
71
+ const kind = field(protocol), length = field("length");
72
+ return (typeof kind === "string" &&
73
+ Object.hasOwn(constructors, kind) &&
74
+ typeof length === "number" &&
75
+ Number.isSafeInteger(length) &&
76
+ length >= 0 &&
77
+ typeof field("at") === "function" &&
78
+ typeof field("copy") === "function");
79
+ }
80
+ /** Adopts separately bundled factories once, copying before trusting their storage or methods. */
81
+ export function adoptImmutableBuffer(buffer) {
82
+ if (storage.has(buffer))
83
+ return buffer;
84
+ const previous = adopted.get(buffer);
85
+ if (previous !== undefined)
86
+ return previous;
87
+ if (!isImmutableBuffer(buffer))
88
+ throw new TypeError("Expected an immutableBuffer() value.");
89
+ const source = buffer.copy();
90
+ const kind = Object.getOwnPropertyDescriptor(buffer, protocol)
91
+ .value;
92
+ if (!(source instanceof constructors[kind]))
93
+ throw new TypeError("An immutable buffer copy must retain its numeric type and length.");
94
+ const captured = immutableBuffer(source);
95
+ if (captured.length !== buffer.length)
96
+ throw new TypeError("An immutable buffer copy must retain its numeric type and length.");
97
+ adopted.set(buffer, captured);
98
+ return captured;
99
+ }
100
+ /** Trusted internal read only: never mutate or expose this view or its backing buffer. */
101
+ export function immutableBufferView(buffer) {
102
+ return storage.get(adoptImmutableBuffer(buffer));
103
+ }
104
+ /** Normalizes trusted modeling/finalization inputs without copying or exposing storage publicly. */
105
+ export function immutableMeshView(mesh) {
106
+ const { positions, indices } = mesh;
107
+ return {
108
+ positions: isImmutableBuffer(positions) ? immutableBufferView(positions) : positions,
109
+ indices: isImmutableBuffer(indices) ? immutableBufferView(indices) : indices,
110
+ };
111
+ }
@@ -0,0 +1 @@
1
+ export {};