parapoly-runtime 1.0.1 → 1.0.3

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.
@@ -0,0 +1,220 @@
1
+ ---
2
+ applyTo: "**/*.part3d,**/*.part3d.js,**/Part3dCodeExporter*,**/part3d/**"
3
+ description: "Part3D 编辑器与 .part3d/.part3d.js 导出规范。涵盖 Part3dCodeExporter 架构、特征导出模式、sketch 可见度、颜色格式等。"
4
+ ---
5
+ # Part3D & .part3d.js 导出指南
6
+
7
+ ## 文件概览
8
+
9
+ | 文件类型 | 说明 |
10
+ |---|---|
11
+ | `.part3d` | Part3D 编辑器的项目文件(JSON 格式,Sprite 序列化树) |
12
+ | `.part3d.js` | 从 `.part3d` 导出的可执行 JS 代码,可在 code3d 运行时独立运行 |
13
+
14
+ ## 源码位置
15
+
16
+ ```
17
+ packages/parapoly-runtime/src/io/Part3dCodeExporter.ts ← 核心导出类(类库)
18
+ packages/parapoly-editor/src/io/Part3dCodeExporter.ts ← 向后兼容 re-export
19
+ packages/parapoly-editor/src/editors/part3d/ ← Part3D 编辑器
20
+ packages/parapoly-runtime/src/part/feature_node/ ← 特征节点定义
21
+ packages/parapoly-runtime/src/part/feature_node/op/ ← 操作型特征的 run() 逻辑
22
+ ```
23
+
24
+ ## Part3dCodeExporter API
25
+
26
+ ```typescript
27
+ import { Part3dCodeExporter } from "parapoly-runtime";
28
+
29
+ // 导出 FeatureContainerNode 为 .part3d.js 代码
30
+ let code = Part3dCodeExporter.export(feature_container, default_color?);
31
+ // feature_container: FeatureContainerNode 实例
32
+ // default_color: 默认颜色(默认 "#ffffff"),当节点无颜色时使用
33
+ ```
34
+
35
+ ## 导出代码结构
36
+
37
+ ```javascript
38
+ let main = function() {
39
+ let block3d_doc = new PartBlock3dDocument();
40
+
41
+ // Helpers
42
+ let __id_to_name = {}; // feature_id → 运行时节点名映射
43
+ let __saved_shapes = {}; // Boolean 操作前保存的 shape 引用
44
+ let __record_name = function(feature_id) { ... };
45
+ let __select_feature = function(feature_id) { ... };
46
+
47
+ // Feature summary(注释段,人类可读预览)
48
+ // Feature count: N
49
+ // [0] FeatureNodeSetBox op=union ...
50
+
51
+ // Executable export(可执行段)
52
+ block3d_doc.box("union", 10, 5, 3, "#ff0000");
53
+ __record_name("abc12345-...");
54
+ // ...
55
+
56
+ return block3d_doc;
57
+ };
58
+ ```
59
+
60
+ ## 导出模式分类
61
+
62
+ ### 模式 A:基础体(直接 PartBlock3dDocument API)
63
+
64
+ 适用于:Box, Cylinder, Sphere, Cone, Torus, Prism, Ellipsoid, Wedge, Trapezoid, Step
65
+
66
+ ```javascript
67
+ block3d_doc.box(op, x, y, z, color);
68
+ block3d_doc.translate(px, py, pz); // TransformComponent
69
+ block3d_doc.rotate_by_quaternion(rx, ry, rz, rw);
70
+ __record_name(feature_id);
71
+ ```
72
+
73
+ ### 模式 B:IIFE + ParaPolyShapeMaker(操作型特征)
74
+
75
+ 适用于:Extrude, Revolve, Sweep, Helix, Fillet, Chamfer, Shell, Draft, Mirror, Boolean, Transform
76
+
77
+ ```javascript
78
+ (function() {
79
+ let target_name = __id_to_name[target_id];
80
+ if (!target_name) { console.warn("..."); return; }
81
+ let root = block3d_doc.get_root_node();
82
+ let node = root.getChildByName(target_name, true);
83
+ // ... 获取 shape / 调用 ParaPolyShapeMaker.xxx() ...
84
+ let result_node = block3d_doc.push_node(op, name, color, false);
85
+ result_node.set_topo_shape(result_shape);
86
+ block3d_doc.pop_node();
87
+ node.set_archived(true);
88
+ node.set_op_feature_node_id(feature_id);
89
+ __record_name(feature_id);
90
+ })();
91
+ ```
92
+
93
+ ## 关键经验与注意事项
94
+
95
+ ### 1. 颜色格式必须带 `#` 前缀
96
+
97
+ `get_color()` 返回的值可能不带 `#`(如 `"ffffff"`),导出时必须补全:
98
+
99
+ ```typescript
100
+ let color = node.get_color ? node.get_color() : default_color;
101
+ if (color && !color.startsWith("#")) color = "#" + color;
102
+ ```
103
+
104
+ ### 2. Sketch 可见度保持
105
+
106
+ Part3D 中 Sketch 有两种独立的隐藏机制,导出时必须都保留:
107
+
108
+ | 属性 | 含义 | 设置方式 |
109
+ |---|---|---|
110
+ | `get_archived()` | 被操作消费后系统隐藏 | `update_feature_node_archived()` 计算 |
111
+ | `get_op_feature_node_id()` | 关联的消费操作 ID | 操作 run() 时持久化设置 |
112
+ | `get_visible()` | 用户通过眼睛图标隐藏 | 用户手动切换 |
113
+
114
+ **导出逻辑**:
115
+ ```typescript
116
+ // 创建 sketch 后立即检查并保持可见度
117
+ let is_archived = node.get_archived ? node.get_archived() : false;
118
+ let op_id = node.get_op_feature_node_id ? node.get_op_feature_node_id() : null;
119
+ let is_visible = node.get_visible ? node.get_visible() : true;
120
+ if (is_archived || op_id) {
121
+ lines.push(`block3d_doc.selected_node.set_archived(true);`);
122
+ }
123
+ if (!is_visible) {
124
+ lines.push(`block3d_doc.selected_node.set_visible(false);`);
125
+ }
126
+ ```
127
+
128
+ **为什么要检查 `op_id`**:`get_archived()` 依赖编辑器的 `update_feature_node_archived()` 调用,可能不是最新状态。`get_op_feature_node_id()` 是持久化属性,更可靠。
129
+
130
+ **`end_sketch()` 后 `selected_node` 指向**:`PartBlock3dDocument.end_sketch()` 执行 `this.selected_node = node`(sketch 节点),所以 `block3d_doc.selected_node.set_archived(true)` 能正确定位。
131
+
132
+ **渲染过滤**:`SpriteToNativeNode` 和 `Text2CADFacade.build()` 遍历节点时均跳过 `topo_shape_component.get_archived() === true` 的节点。
133
+
134
+ ### 3. Sketch 复用与重发射
135
+
136
+ 同一 sketch 被多次引用时(如被两个 Extrude 使用),需要在第二次引用前重新发射:
137
+
138
+ ```typescript
139
+ let consumed_sketches: Set<string> = new Set();
140
+ // 在 Extrude/Revolve 处理时:
141
+ if (target_id && consumed_sketches.has(target_id) && sketch_nodes.has(target_id)) {
142
+ lines.push(...Part3dCodeExporter.export_sketch_lines(sketch_nodes.get(target_id)));
143
+ lines.push(`__record_name(${JSON.stringify(target_id)});`);
144
+ }
145
+ consumed_sketches.add(target_id);
146
+ ```
147
+
148
+ ### 4. 操作型特征的归档配对
149
+
150
+ Extrude/Revolve/Fillet 等操作在 IIFE 中必须:
151
+ 1. 先取消归档:`node.set_archived(false); node.set_op_feature_node_id(null);`
152
+ 2. 执行操作
153
+ 3. 重新归档:`node.set_archived(true); node.set_op_feature_node_id(feature_id);`
154
+
155
+ 如果 `keep_original === true`,跳过步骤 3。
156
+
157
+ ### 5. `__saved_shapes` 用于 Boolean 后的引用
158
+
159
+ Boolean 操作会删除原始节点,但后续 Mirror/Fillet 等可能需要引用被删除节点的 shape。Boolean 在删除前保存:
160
+
161
+ ```javascript
162
+ __saved_shapes[target_name] = { shape: topo_shape.clone(), color: color };
163
+ ```
164
+
165
+ 后续操作查找目标时先查节点,再查 `__saved_shapes`:
166
+ ```javascript
167
+ let topo_shape;
168
+ if (node && node.get_topo_shape) {
169
+ topo_shape = node.get_topo_shape();
170
+ } else if (__saved_shapes[target_name]) {
171
+ topo_shape = __saved_shapes[target_name].shape;
172
+ }
173
+ ```
174
+
175
+ ### 6. 变换顺序差异
176
+
177
+ 不同特征对 `transform_native_shape` 的调用顺序不同:
178
+
179
+ | 特征 | 顺序 |
180
+ |---|---|
181
+ | Extrude | 先 extrude_shape → 再 transform_native_shape |
182
+ | Helix | 先 helix_shape → 再 transform_native_shape |
183
+ | Revolve | 先 transform_native_shape(wires) → 再 revolve_shape |
184
+ | Sweep | 先 transform(profile+path) → 再 sweep_shape |
185
+
186
+ ### 7. STEP 导入体的 base64 编码
187
+
188
+ `FeatureNodeSetStep` 的 content 可能是字符串或 Uint8Array,导出时统一转为 base64:
189
+
190
+ ```typescript
191
+ private static step_payload_base64(content: any): string {
192
+ if (!content) return "";
193
+ if (content instanceof Uint8Array) {
194
+ return btoa(String.fromCharCode(...content));
195
+ }
196
+ if (typeof content === "string") {
197
+ return btoa(content);
198
+ }
199
+ return "";
200
+ }
201
+ ```
202
+
203
+ 运行时通过 `block3d_doc.import_step_shape_by_string(op, base64, true, color)` 还原。
204
+
205
+ ### 8. 错误日志格式
206
+
207
+ 所有 IIFE 中的 warn 日志统一格式:
208
+ ```
209
+ [part3d.js #序号 操作类型 特征ID前8位] 消息
210
+ ```
211
+ 例如:`[part3d.js #3 Extrude abc12345] target_name not found for sketch def67890`
212
+
213
+ ## 修改 Exporter 的流程
214
+
215
+ 1. 定位源码:`packages/parapoly-runtime/src/part/feature_node/op/FeatureNode*.ts` 的 `run()` 方法
216
+ 2. 找到 `ParaPolyShapeMaker.xxx()` 调用及参数来源
217
+ 3. 注意变换顺序(transform 在操作前/后)
218
+ 4. 更新 `Part3dCodeExporter.ts` 中对应 `class_name.indexOf(...)` 分支
219
+ 5. 保持 IIFE 模式和归档配对
220
+ 6. 运行 `get_errors` 验证无 TypeScript 错误
@@ -0,0 +1,248 @@
1
+ ---
2
+ applyTo: "**/*.sketch3d,**/*.sketch3d.js,**/SketchCodeExporter*,**/sketch3d/**,**/sketch_node/**"
3
+ description: "Sketch3D 草图编辑器与 .sketch3d/.sketch3d.js 导出规范。涵盖 SketchCodeExporter 架构、几何导出、约束导出、可见度处理等。"
4
+ ---
5
+ # Sketch3D & .sketch3d.js 导出指南
6
+
7
+ ## 文件概览
8
+
9
+ | 文件类型 | 说明 |
10
+ |---|---|
11
+ | `.sketch3d` | Sketch3D 编辑器的项目文件(JSON 格式,SkContainerNode 序列化) |
12
+ | `.sketch3d.js` / `.code3d.js` | 从 sketch 导出的可执行 JS 代码 |
13
+
14
+ ## 源码位置
15
+
16
+ ```
17
+ packages/parapoly-runtime/src/io/SketchCodeExporter.ts ← 核心导出类(类库)
18
+ packages/parapoly-editor/src/io/SketchCodeExporter.ts ← 向后兼容 re-export
19
+ packages/parapoly-editor/src/editors/sketch3d/ ← Sketch3D 编辑器
20
+ packages/parapoly-runtime/src/part/sketch_node/ ← 草图节点定义
21
+ ```
22
+
23
+ ## SketchCodeExporter API
24
+
25
+ ```typescript
26
+ import { SketchCodeExporter } from "parapoly-runtime";
27
+
28
+ // 导出 SkContainerNode 为 .code3d.js 代码
29
+ let code = SketchCodeExporter.export(sk_container_node);
30
+ ```
31
+
32
+ ## 导出代码结构
33
+
34
+ **重要**:每个 `.sketch3d.js` 文件只包含一个有效的 sketch(一对 `start_sketch`/`end_sketch`)。所有几何体和约束都属于这同一个 sketch 上下文。AI 阅读时应将文件内容视为单一草图的完整定义。
35
+
36
+ ```javascript
37
+ // This .sketch3d.js file contains exactly ONE sketch (start_sketch/end_sketch pair).
38
+ // All geometry and constraints belong to this single sketch context.
39
+ let main = function() {
40
+ let block3d_doc = new PartBlock3dDocument();
41
+ block3d_doc.start_sketch("sketch", [0, 0, 0, 0, 0, 1]);
42
+
43
+ // 几何绘制(返回 geom_id)
44
+ let g0 = block3d_doc.line_segment(0, 0, 0, 10, 0, 0);
45
+ let g1 = block3d_doc.line_segment(10, 0, 0, 10, 5, 0);
46
+ // ...
47
+
48
+ // 约束
49
+ block3d_doc.constraint_horizontal(g0);
50
+ block3d_doc.constraint_coincident(g0, PointPos.end, g1, PointPos.start);
51
+ // ...
52
+
53
+ block3d_doc.end_sketch();
54
+ return block3d_doc;
55
+ };
56
+ ```
57
+
58
+ ### start_sketch 平面方向
59
+
60
+ `start_sketch` 的第二个参数是平面定义,导出时从 `SkContainerNode.get_ax2()` 的 `Ax2Component` 读取 center 和 direction,输出为 6 元素数组 `[cx, cy, cz, dx, dy, dz]`:
61
+
62
+ | 平面 | 数组值 |
63
+ |---|---|
64
+ | XY 平面(Z 方向) | `[0, 0, 0, 0, 0, 1]` |
65
+ | XZ 平面(Y 方向) | `[0, 0, 0, 0, 1, 0]` |
66
+ | YZ 平面(X 方向) | `[0, 0, 0, 1, 0, 0]` |
67
+ | 偏移平面 | `[0, 0, 10, 0, 0, 1]`(Z=10 处的 XY 平面) |
68
+ | 任意方向 | `[cx, cy, cz, dx, dy, dz]` |
69
+
70
+ 也支持字符串简写形式(仅限手写代码):`"x"`, `"y"`, `"z"`。
71
+
72
+ ## 几何类型映射
73
+
74
+ | 节点类 | 导出方法 | 返回值 |
75
+ |---|---|---|
76
+ | `SkGeomPointNode` | `block3d_doc.point(x, y, z)` | geom_id |
77
+ | `SkGeomLineNode` | `block3d_doc.line_segment(x1, y1, z1, x2, y2, z2)` | geom_id |
78
+ | `SkGeomCircleNode` | `block3d_doc.circle(cx, cy, cz, r)` | geom_id |
79
+ | `SkGeomEllipseNode` | `block3d_doc.ellipse(cx, cy, cz, major_r, minor_r)` | geom_id |
80
+ | `SkGeomArcNode` | `block3d_doc.arc(cx, cy, cz, r, start_deg, end_deg)` | geom_id |
81
+ | `SkGeomBSplineNode` | `start_bspline(closed)` + `add_pole()` × N + `end_bspline()` | 无返回值 |
82
+
83
+ ## 约束类型映射
84
+
85
+ | ConstraintType | 导出方法 | 条件 |
86
+ |---|---|---|
87
+ | `Coincident` | `constraint_coincident(s, sp, f, fp)` | — |
88
+ | `Horizontal` | `constraint_horizontal(f)` | 单线段 |
89
+ | `Horizontal` | `constraint_horizontal_points(f, fp, s, sp)` | 两点(`second >= 0` 且 `firstPos != none`) |
90
+ | `Vertical` | `constraint_vertical(f)` | 单线段 |
91
+ | `Vertical` | `constraint_vertical_points(f, fp, s, sp)` | 两点 |
92
+ | `Distance` | `constraint_distance(f, value)` | 无 second |
93
+ | `Distance` | `constraint_distance_points(f, fp, s, sp, value)` | 两点 |
94
+ | `Distance` | `constraint_distance_point_to_line(f, fp, s, value)` | 点到线 |
95
+ | `DistanceX` | `constraint_distance_h(f, value)` / `_points(...)` | — |
96
+ | `DistanceY` | `constraint_distance_v(f, value)` / `_points(...)` | — |
97
+ | `Radius` | `constraint_radius(f, value)` | — |
98
+ | `Diameter` | `constraint_diameter(f, value)` | — |
99
+ | `Parallel` | `constraint_parallel(f, s)` | — |
100
+ | `Perpendicular` | `constraint_perpendicular(f, s)` | — |
101
+ | `Equal` | `constraint_equal(f, s)` | — |
102
+ | `Tangent` | `constraint_tangent(f, s)` | — |
103
+ | `Angle` | `constraint_angle(f, value)` | 单线段(与 X 轴夹角) |
104
+ | `Angle` | `constraint_angle_lines(f, s, value)` | 两线夹角 |
105
+ | `PointOnObject` | `constraint_point_on_object(f, fp, s)` | — |
106
+ | `Symmetric` | `constraint_symmetric(f, fp, line, s, sp)` | — |
107
+
108
+ ## 关键经验与注意事项
109
+
110
+ ### 1. 跳过内部几何体
111
+
112
+ Sketch 中存在内部辅助几何(如坐标轴),必须跳过:
113
+
114
+ ```typescript
115
+ if (node.get_is_internal && node.get_is_internal()) {
116
+ continue;
117
+ }
118
+ ```
119
+
120
+ ### 2. 跳过 InternalAlignment 约束
121
+
122
+ ```typescript
123
+ if (type === ConstraintType.InternalAlignment) {
124
+ continue;
125
+ }
126
+ ```
127
+
128
+ ### 3. Arc 角度转换
129
+
130
+ `SkGeomArcNode` 存储弧度制,导出时需转为角度制:
131
+
132
+ ```typescript
133
+ let sa = node.component.get_start_angle(); // 弧度
134
+ let ea = node.component.get_end_angle(); // 弧度
135
+ // 导出时转为度
136
+ block3d_doc.arc(cx, cy, cz, r, sa * 180 / Math.PI, ea * 180 / Math.PI);
137
+ ```
138
+
139
+ ### 4. BSpline 无 geom_id 返回
140
+
141
+ `start_bspline` / `end_bspline` 不返回 geom_id,因此 BSpline 不参与约束引用:
142
+
143
+ ```typescript
144
+ if (className === ClassNames.SkGeomBSplineNode) {
145
+ // ... export poles ...
146
+ geom_id_to_var.delete(geom_id); // 不记录变量映射
147
+ }
148
+ ```
149
+
150
+ ### 5. geom_id 变量命名
151
+
152
+ 每个几何体的 geom_id 映射为 `g{id}` 变量名,约束中引用这些变量:
153
+
154
+ ```javascript
155
+ let g0 = block3d_doc.line_segment(...);
156
+ let g1 = block3d_doc.line_segment(...);
157
+ block3d_doc.constraint_coincident(g0, PointPos.end, g1, PointPos.start);
158
+ ```
159
+
160
+ ### 6. PointPos 枚举值
161
+
162
+ ```
163
+ PointPos.none = 0 // 整条边/线(用于 constraint_horizontal 等)
164
+ PointPos.start = 1 // 起点
165
+ PointPos.end = 2 // 终点
166
+ PointPos.mid = 3 // 中点(圆心等)
167
+ ```
168
+
169
+ ### 7. Coincident 约束参数顺序
170
+
171
+ 注意 Coincident 的参数顺序是 `(second, secondPos, first, firstPos)`,与其他约束不同:
172
+
173
+ ```typescript
174
+ case ConstraintType.Coincident:
175
+ return `block3d_doc.constraint_coincident(${s}, ${sp}, ${f}, ${fp});`;
176
+ ```
177
+
178
+ ## 在 Part3dCodeExporter 中的 Sketch 导出
179
+
180
+ Part3dCodeExporter 中嵌入 sketch 时使用简化版(不含约束,不含 geom_id 变量):
181
+
182
+ ```javascript
183
+ block3d_doc.start_sketch("sketch_name", [cx, cy, cz, dx, dy, dz]);
184
+ block3d_doc.line_segment(x1, y1, z1, x2, y2, z2);
185
+ block3d_doc.circle(cx, cy, cz, r);
186
+ // ...
187
+ block3d_doc.end_sketch();
188
+ ```
189
+
190
+ **差异**:
191
+ - `start_sketch` 参数为 `[center_x, center_y, center_z, dir_x, dir_y, dir_z]` 数组(Part3d 模式),而非 `"z"` 字符串(独立 sketch 模式)
192
+ - 不导出约束(拉伸/旋转只需要 wires 形状)
193
+ - 不保留 geom_id 变量
194
+
195
+ ## Sketch 可见度(在 Part3D 上下文中)
196
+
197
+ 当 Sketch 存在于 Part3D 特征树中时,有两种隐藏机制:
198
+
199
+ 1. **`archived = true`**:被 Extrude/Revolve 等操作消费后,系统设置
200
+ 2. **`visible = false`**:用户通过眼睛图标手动隐藏
201
+
202
+ Part3dCodeExporter 在导出 sketch 后需检查并保持可见度状态:
203
+
204
+ ```typescript
205
+ if (is_archived || op_id) {
206
+ lines.push(`block3d_doc.selected_node.set_archived(true);`);
207
+ }
208
+ if (!is_visible) {
209
+ lines.push(`block3d_doc.selected_node.set_visible(false);`);
210
+ }
211
+ ```
212
+
213
+ `get_op_feature_node_id()` 是最可靠的"已被消费"指标(持久化属性),优先于 `get_archived()`(计算属性)。
214
+
215
+ ## SkContainerNode 关键 API
216
+
217
+ ```typescript
218
+ // 坐标系
219
+ sk_node.get_ax2() → { center, direction }
220
+ sk_node.set_ax2(center: Vector3, direction: Vector3)
221
+
222
+ // 几何体容器
223
+ sk_node.get_geoms() → Node (children = SkGeom*Node[])
224
+
225
+ // 约束容器
226
+ sk_node.get_constraints() → Node (children = ConstraintNode[])
227
+
228
+ // 生成 wire shape(供 Extrude/Revolve 使用)
229
+ sk_node.to_wires_shape() → TopoDS_Shape
230
+
231
+ // 可见度
232
+ sk_node.get_archived() → boolean
233
+ sk_node.set_archived(v)
234
+ sk_node.get_visible() → boolean
235
+ sk_node.set_visible(v)
236
+
237
+ // 操作关联
238
+ sk_node.get_op_feature_node_id() → string | null
239
+ sk_node.set_op_feature_node_id(id)
240
+ ```
241
+
242
+ ## 修改 SketchCodeExporter 的流程
243
+
244
+ 1. 确认几何类型:`packages/parapoly-runtime/src/part/sketch_node/SkGeom*.ts`
245
+ 2. 确认约束类型:`packages/parapoly-runtime/src/types/Constraint.ts` (`ConstraintType` 枚举)
246
+ 3. 确认 API:`packages/parapoly-runtime/src/part/PartBlock3dDocument.ts` 中的 sketch 方法
247
+ 4. 更新 `SketchCodeExporter.ts` 中对应分支
248
+ 5. 注意约束参数的 `second >= 0` 条件判断(区分单目/双目约束)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parapoly-runtime",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "ParaPoly 3D CAD Runtime — CSG modeling, sketch, and project builder",
5
5
  "main": "./parapoly_runtime.js",
6
6
  "types": "./parapoly_runtime.d.ts",
@@ -1777,6 +1777,12 @@ declare module "parapoly-runtime" {
1777
1777
  * @param color Optional override color
1778
1778
  */
1779
1779
  public static create_doc_from_part3d(json_str: string, recompile?: boolean, color?: string): PartBlock3dDocument;
1780
+ /**
1781
+ * Create a PartBlock3dDocument from a .block3d file's raw JSON string.
1782
+ * Extracts the stored JavaScript code from BlockCodeComponent and executes it.
1783
+ * @param json_str The raw JSON content of the .block3d file
1784
+ */
1785
+ public static create_doc_from_block3d(json_str: string): PartBlock3dDocument;
1780
1786
  public set_root_node(node: Node): void;
1781
1787
  public get_root_node(): Node;
1782
1788
  public to_json(): any;
@@ -1822,14 +1828,37 @@ declare module "parapoly-runtime" {
1822
1828
  public start_sketch(name: string, plane_dir: any): SkContainerNode;
1823
1829
  public end_sketch(): void;
1824
1830
  public get_sketch_ax2_component(): Ax2Component;
1825
- public point(x: number, y: number, z: number): void;
1826
- public line_segment(start_x: number, start_y: number, start_z: number, end_x: number, end_y: number, end_z: number): void;
1827
- public circle(x: number, y: number, z: number, r: number): void;
1828
- public ellipse(x: number, y: number, z: number, major_r: number, minor_r: number): void;
1829
- public arc(x: number, y: number, z: number, r: number, startAngle: number, endAngle: number, isDegree?: boolean): void;
1831
+ public point(x: number, y: number, z: number): number;
1832
+ public line_segment(start_x: number, start_y: number, start_z: number, end_x: number, end_y: number, end_z: number): number;
1833
+ public circle(x: number, y: number, z: number, r: number): number;
1834
+ public ellipse(x: number, y: number, z: number, major_r: number, minor_r: number): number;
1835
+ public arc(x: number, y: number, z: number, r: number, startAngle: number, endAngle: number, isDegree?: boolean): number;
1830
1836
  public start_bspline(closed: boolean): void;
1831
1837
  public end_bspline(): void;
1832
1838
  public add_pole(x: number, y: number, z: number): void;
1839
+ private get_sk_container(): SkContainerNode | null;
1840
+ public constraint_coincident(from_geom_id: number, from_pos: PointPos, to_geom_id: number, to_pos: PointPos): void;
1841
+ public constraint_horizontal(geom_id: number): void;
1842
+ public constraint_vertical(geom_id: number): void;
1843
+ public constraint_horizontal_points(from_geom_id: number, from_pos: PointPos, to_geom_id: number, to_pos: PointPos): void;
1844
+ public constraint_vertical_points(from_geom_id: number, from_pos: PointPos, to_geom_id: number, to_pos: PointPos): void;
1845
+ public constraint_distance(geom_id: number, value: number): void;
1846
+ public constraint_distance_points(from_geom_id: number, from_pos: PointPos, to_geom_id: number, to_pos: PointPos, value: number): void;
1847
+ public constraint_distance_h(geom_id: number, value: number): void;
1848
+ public constraint_distance_h_points(from_geom_id: number, from_pos: PointPos, to_geom_id: number, to_pos: PointPos, value: number): void;
1849
+ public constraint_distance_v(geom_id: number, value: number): void;
1850
+ public constraint_distance_v_points(from_geom_id: number, from_pos: PointPos, to_geom_id: number, to_pos: PointPos, value: number): void;
1851
+ public constraint_distance_point_to_line(point_geom_id: number, point_pos: PointPos, line_geom_id: number, value: number): void;
1852
+ public constraint_radius(geom_id: number, value: number): void;
1853
+ public constraint_diameter(geom_id: number, value: number): void;
1854
+ public constraint_parallel(geom_id_1: number, geom_id_2: number): void;
1855
+ public constraint_perpendicular(geom_id_1: number, geom_id_2: number): void;
1856
+ public constraint_equal(geom_id_1: number, geom_id_2: number): void;
1857
+ public constraint_tangent(geom_id_1: number, geom_id_2: number): void;
1858
+ public constraint_angle(geom_id: number, value: number): void;
1859
+ public constraint_angle_lines(geom_id_1: number, geom_id_2: number, value: number): void;
1860
+ public constraint_point_on_object(point_geom_id: number, point_pos: PointPos, obj_geom_id: number): void;
1861
+ public constraint_symmetric(geom_id_1: number, pos_1: PointPos, line_geom_id: number, geom_id_2: number, pos_2: PointPos): void;
1833
1862
  public extrude(op: BooleanTypes, length: number, color: string, bSolid: boolean, transform_matrix_arr: Array<number>): void;
1834
1863
  public extrude_by_face(op: BooleanTypes, length: number, face_index: number, direction: DirectionTypes, color: string, bSolid: boolean, bAutoCheckDir: boolean): void;
1835
1864
  public revolve(op: BooleanTypes, angle: number, axis: DirectionTypes | Array<number>, color: string, bSolid: boolean, transform_matrix_arr: Array<number>): void;
@@ -2878,6 +2907,7 @@ declare module "parapoly-runtime" {
2878
2907
  FeatureSetEllipsoid = "FeatureSetEllipsoid",
2879
2908
  FeatureSetWedge = "FeatureSetWedge",
2880
2909
  FeatureSetTrapezoid = "FeatureSetTrapezoid",
2910
+ FeatureSetStep = "FeatureSetStep",
2881
2911
  FeatureBoolean = "FeatureBoolean",
2882
2912
  FeatureExtrude = "FeatureExtrude",
2883
2913
  FeatureChamfer = "FeatureChamfer",
@@ -2954,6 +2984,8 @@ declare module "parapoly-runtime" {
2954
2984
  viewSketchExtrudeScript = "viewSketchExtrudeScript",
2955
2985
  copySketchRevolveScript = "copySketchRevolveScript",
2956
2986
  viewSketchRevolveScript = "viewSketchRevolveScript",
2987
+ exportSketch3dJs = "exportSketch3dJs",
2988
+ exportPart3dJs = "exportPart3dJs",
2957
2989
  }
2958
2990
 
2959
2991
  export enum GeomTypes {
@@ -3258,7 +3290,7 @@ declare module "parapoly-runtime" {
3258
3290
  * @param onProgress - Progress callback
3259
3291
  * @returns Bundle output string and metadata
3260
3292
  */
3261
- export function buildCode3dProject(files: Record<string, string>, config: Code3dProjectConfig, onProgress?: BuildProgress): Promise<{
3293
+ export function buildCode3dProject(files: Record<string, string>, config: Code3dProjectConfig, onProgress?: BuildProgress, fileLoader?: FileLoader): Promise<{
3262
3294
  output: string;
3263
3295
  binOutput: Uint8Array | null;
3264
3296
  result: BuildResult;
@@ -3347,6 +3379,36 @@ declare module "parapoly-runtime" {
3347
3379
  errors?: Array<string>;
3348
3380
  }
3349
3381
 
3382
+ export class Part3dCodeExporter {
3383
+ public static export(feature_container: FeatureContainerNode, default_color?: string): string;
3384
+ private static export_feature_summary(feature_container: FeatureContainerNode): Array<string>;
3385
+ private static export_executable_calls(feature_container: FeatureContainerNode, default_color?: string): Array<string>;
3386
+ private static export_sketch_lines(node: any): Array<string>;
3387
+ private static append_transform_lines(lines: Array<string>, node: any): void;
3388
+ private static extract_edges_and_target(items: Array<any>): {
3389
+ target_id: string;
3390
+ edges: Array<number>;
3391
+ };
3392
+ private static extract_faces_and_target(items: Array<any>): {
3393
+ target_id: string;
3394
+ faces: Array<number>;
3395
+ };
3396
+ private static step_payload_base64(content: Uint8Array): string;
3397
+ private static n(v: any): string;
3398
+ private static summarize_feature_node(index: number, node: any): string;
3399
+ private static summarize_feature_component(component: any): string;
3400
+ private static push_if_defined(target: Array<string>, key: string, value: any): void;
3401
+ private static to_simple_value(value: any): string;
3402
+ }
3403
+
3404
+ export class SketchCodeExporter {
3405
+ public static export(sk_container_node: SkContainerNode): string;
3406
+ private static n(v: number): string;
3407
+ private static pp(pos: PointPos): string;
3408
+ private static gv(geom_id: number, map: Map<number, string>): string;
3409
+ private static exportConstraint(type: ConstraintType, first: number, firstPos: PointPos, second: number, secondPos: PointPos, value: number, map: Map<number, string>): string | null;
3410
+ }
3411
+
3350
3412
  export class EventDispatcher {
3351
3413
  private _listeners: Record<string, Array<Func>>;
3352
3414
  private _unique_maps: {};
@@ -4229,6 +4291,13 @@ declare module "parapoly-runtime" {
4229
4291
  getId(): string;
4230
4292
  }
4231
4293
 
4294
+ /**
4295
+ * Optional file loader callback for on-demand loading.
4296
+ * Called when a file is needed but not yet in the files map.
4297
+ * Should return the file content string, or null if not found.
4298
+ */
4299
+ export type FileLoader = (filePath: string) => Promise<string | null>;
4300
+
4232
4301
  export interface Vector3Like {
4233
4302
  readonly x: number;
4234
4303
  readonly y: number;