three-slicer 0.1.7 → 0.2.1
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/CHANGELOG.md +35 -0
- package/README.md +58 -3
- package/THIRD-PARTY-NOTICES.md +37 -0
- package/components/README.md +2 -0
- package/components/dist/SettingsPanel.js +92 -92
- package/data/config-schema.json +698 -0
- package/data/printers.json +1 -1
- package/data/ui-tree.json +342 -0
- package/engine/README.md +20 -0
- package/engine/examples/sla_headless.mjs +51 -0
- package/engine/index.d.ts +3 -0
- package/engine/index.js +6 -0
- package/engine/src/client.js +31 -2
- package/engine/src/settings.js +164 -0
- package/engine/src/sla_core.js +188 -0
- package/engine/src/sla_request.js +185 -0
- package/engine/src/slicer.worker.js +63 -1
- package/engine/src/slicer_core.js +0 -0
- package/engine/src/slicer_core.mt.js +0 -0
- package/package.json +8 -3
- package/types/client.d.ts +14 -0
- package/types/settings-keys.d.ts +107 -1
- package/types/settings.d.ts +34 -0
- package/types/sla.d.ts +167 -0
- package/types/viewer.d.ts +2 -0
- package/types/worker.d.ts +9 -1
- package/viewer/README.md +7 -1
- package/viewer/dist/Viewport.js +3454 -3138
- package/viewer/dist/model_loaders.js +1 -1
- package/viewer/dist/parse_3mf-C2X_W442.js +300 -0
- package/viewer/dist/parse_3mf.worker.js +1 -1
- package/viewer/dist/parse_3mf-8oCnCJNK.js +0 -216
package/data/ui-tree.json
CHANGED
|
@@ -1277,5 +1277,347 @@
|
|
|
1277
1277
|
}
|
|
1278
1278
|
]
|
|
1279
1279
|
}
|
|
1280
|
+
],
|
|
1281
|
+
"TabPrinter::build_sla": [
|
|
1282
|
+
{
|
|
1283
|
+
"page": "General",
|
|
1284
|
+
"icon": "printer",
|
|
1285
|
+
"line": 3016,
|
|
1286
|
+
"groups": [
|
|
1287
|
+
{
|
|
1288
|
+
"group": "Size and coordinates",
|
|
1289
|
+
"line": 3017,
|
|
1290
|
+
"options": [
|
|
1291
|
+
"max_print_height"
|
|
1292
|
+
]
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
"group": "Display",
|
|
1296
|
+
"line": 3024,
|
|
1297
|
+
"options": [
|
|
1298
|
+
"display_width",
|
|
1299
|
+
"display_height",
|
|
1300
|
+
"<custom-widget line:3032>",
|
|
1301
|
+
"display_orientation",
|
|
1302
|
+
"display_mirror_x",
|
|
1303
|
+
"display_mirror_y"
|
|
1304
|
+
]
|
|
1305
|
+
},
|
|
1306
|
+
{
|
|
1307
|
+
"group": "Tilt",
|
|
1308
|
+
"line": 3039,
|
|
1309
|
+
"options": [
|
|
1310
|
+
"<custom-widget line:3044>"
|
|
1311
|
+
]
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
"group": "Corrections",
|
|
1315
|
+
"line": 3046,
|
|
1316
|
+
"options": [
|
|
1317
|
+
"<custom-widget line:3053>",
|
|
1318
|
+
"absolute_correction",
|
|
1319
|
+
"elefant_foot_compensation",
|
|
1320
|
+
"elefant_foot_min_width",
|
|
1321
|
+
"gamma_correction"
|
|
1322
|
+
]
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
"group": "Exposure",
|
|
1326
|
+
"line": 3059,
|
|
1327
|
+
"options": [
|
|
1328
|
+
"min_exposure_time",
|
|
1329
|
+
"max_exposure_time",
|
|
1330
|
+
"min_initial_exposure_time",
|
|
1331
|
+
"max_initial_exposure_time"
|
|
1332
|
+
]
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
"group": "Output",
|
|
1336
|
+
"line": 3066,
|
|
1337
|
+
"options": [
|
|
1338
|
+
"sla_archive_format",
|
|
1339
|
+
"sla_output_precision"
|
|
1340
|
+
]
|
|
1341
|
+
}
|
|
1342
|
+
]
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
"page": "Notes",
|
|
1346
|
+
"icon": "note",
|
|
1347
|
+
"line": 3074,
|
|
1348
|
+
"groups": [
|
|
1349
|
+
{
|
|
1350
|
+
"group": "Notes",
|
|
1351
|
+
"line": 3075,
|
|
1352
|
+
"options": []
|
|
1353
|
+
}
|
|
1354
|
+
]
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
"page": "Dependencies",
|
|
1358
|
+
"icon": "wrench",
|
|
1359
|
+
"line": 3081,
|
|
1360
|
+
"groups": [
|
|
1361
|
+
{
|
|
1362
|
+
"group": "Profile dependencies",
|
|
1363
|
+
"line": 3082,
|
|
1364
|
+
"options": []
|
|
1365
|
+
}
|
|
1366
|
+
]
|
|
1367
|
+
}
|
|
1368
|
+
],
|
|
1369
|
+
"TabSLAMaterial::build": [
|
|
1370
|
+
{
|
|
1371
|
+
"page": "Material",
|
|
1372
|
+
"icon": "resin",
|
|
1373
|
+
"line": 5437,
|
|
1374
|
+
"groups": [
|
|
1375
|
+
{
|
|
1376
|
+
"group": "Material",
|
|
1377
|
+
"line": 5439,
|
|
1378
|
+
"options": [
|
|
1379
|
+
"material_colour",
|
|
1380
|
+
"bottle_cost",
|
|
1381
|
+
"bottle_volume",
|
|
1382
|
+
"bottle_weight",
|
|
1383
|
+
"material_density"
|
|
1384
|
+
]
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
"group": "Layers",
|
|
1388
|
+
"line": 5478,
|
|
1389
|
+
"options": [
|
|
1390
|
+
"initial_layer_height"
|
|
1391
|
+
]
|
|
1392
|
+
},
|
|
1393
|
+
{
|
|
1394
|
+
"group": "Exposure",
|
|
1395
|
+
"line": 5481,
|
|
1396
|
+
"options": [
|
|
1397
|
+
"exposure_time",
|
|
1398
|
+
"initial_exposure_time"
|
|
1399
|
+
]
|
|
1400
|
+
},
|
|
1401
|
+
{
|
|
1402
|
+
"group": "Corrections",
|
|
1403
|
+
"line": 5485,
|
|
1404
|
+
"options": [
|
|
1405
|
+
"<custom-widget line:5492>",
|
|
1406
|
+
"zcorrection_layers",
|
|
1407
|
+
"<custom-widget line:5502>"
|
|
1408
|
+
]
|
|
1409
|
+
}
|
|
1410
|
+
]
|
|
1411
|
+
},
|
|
1412
|
+
{
|
|
1413
|
+
"page": "Notes",
|
|
1414
|
+
"icon": "note",
|
|
1415
|
+
"line": 5506,
|
|
1416
|
+
"groups": [
|
|
1417
|
+
{
|
|
1418
|
+
"group": "Notes",
|
|
1419
|
+
"line": 5507,
|
|
1420
|
+
"options": []
|
|
1421
|
+
}
|
|
1422
|
+
]
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
"page": "Dependencies",
|
|
1426
|
+
"icon": "wrench",
|
|
1427
|
+
"line": 5514,
|
|
1428
|
+
"groups": [
|
|
1429
|
+
{
|
|
1430
|
+
"group": "Profile dependencies",
|
|
1431
|
+
"line": 5515,
|
|
1432
|
+
"options": []
|
|
1433
|
+
}
|
|
1434
|
+
]
|
|
1435
|
+
},
|
|
1436
|
+
{
|
|
1437
|
+
"page": "Material printing profile",
|
|
1438
|
+
"icon": "note",
|
|
1439
|
+
"line": 5535,
|
|
1440
|
+
"groups": [
|
|
1441
|
+
{
|
|
1442
|
+
"group": "Material printing profile",
|
|
1443
|
+
"line": 5537,
|
|
1444
|
+
"options": [
|
|
1445
|
+
"material_print_speed"
|
|
1446
|
+
]
|
|
1447
|
+
},
|
|
1448
|
+
{
|
|
1449
|
+
"group": "Tilt",
|
|
1450
|
+
"line": 5540,
|
|
1451
|
+
"options": [
|
|
1452
|
+
"area_fill"
|
|
1453
|
+
]
|
|
1454
|
+
},
|
|
1455
|
+
{
|
|
1456
|
+
"group": "Temperature",
|
|
1457
|
+
"line": 5543,
|
|
1458
|
+
"options": [
|
|
1459
|
+
"<custom-widget line:5560>",
|
|
1460
|
+
"<custom-widget line:5590>"
|
|
1461
|
+
]
|
|
1462
|
+
}
|
|
1463
|
+
]
|
|
1464
|
+
}
|
|
1465
|
+
],
|
|
1466
|
+
"TabSLAPrint::build": [
|
|
1467
|
+
{
|
|
1468
|
+
"page": "Layers and perimeters",
|
|
1469
|
+
"icon": "layers",
|
|
1470
|
+
"line": 6066,
|
|
1471
|
+
"groups": [
|
|
1472
|
+
{
|
|
1473
|
+
"group": "Layers",
|
|
1474
|
+
"line": 6068,
|
|
1475
|
+
"options": [
|
|
1476
|
+
"layer_height",
|
|
1477
|
+
"faded_layers"
|
|
1478
|
+
]
|
|
1479
|
+
}
|
|
1480
|
+
]
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
"page": "Supports",
|
|
1484
|
+
"icon": "support",
|
|
1485
|
+
"line": 6072,
|
|
1486
|
+
"groups": [
|
|
1487
|
+
{
|
|
1488
|
+
"group": "Supports",
|
|
1489
|
+
"line": 6074,
|
|
1490
|
+
"options": [
|
|
1491
|
+
"supports_enable",
|
|
1492
|
+
"support_tree_type",
|
|
1493
|
+
"support_enforcers_only"
|
|
1494
|
+
]
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
"group": "Automatic generation",
|
|
1498
|
+
"line": 6081,
|
|
1499
|
+
"options": [
|
|
1500
|
+
"support_points_density_relative"
|
|
1501
|
+
]
|
|
1502
|
+
},
|
|
1503
|
+
{
|
|
1504
|
+
"group": "Support head",
|
|
1505
|
+
"line": 5864,
|
|
1506
|
+
"options": [
|
|
1507
|
+
"support_head_front_diameter",
|
|
1508
|
+
"support_head_penetration",
|
|
1509
|
+
"support_head_width"
|
|
1510
|
+
]
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
"group": "Support pillar",
|
|
1514
|
+
"line": 5869,
|
|
1515
|
+
"options": [
|
|
1516
|
+
"support_pillar_diameter",
|
|
1517
|
+
"support_small_pillar_diameter_percent",
|
|
1518
|
+
"support_max_bridges_on_pillar",
|
|
1519
|
+
"support_pillar_connection_mode",
|
|
1520
|
+
"support_buildplate_only",
|
|
1521
|
+
"support_pillar_widening_factor",
|
|
1522
|
+
"support_max_weight_on_model",
|
|
1523
|
+
"support_base_diameter",
|
|
1524
|
+
"support_base_height",
|
|
1525
|
+
"support_base_safety_distance",
|
|
1526
|
+
"support_object_elevation",
|
|
1527
|
+
"<custom-widget line:5890>"
|
|
1528
|
+
]
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
"group": "Connection of the support sticks and junctions",
|
|
1532
|
+
"line": 5892,
|
|
1533
|
+
"options": [
|
|
1534
|
+
"support_critical_angle",
|
|
1535
|
+
"support_max_bridge_length",
|
|
1536
|
+
"support_max_pillar_link_distance"
|
|
1537
|
+
]
|
|
1538
|
+
}
|
|
1539
|
+
]
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
"page": "Pad",
|
|
1543
|
+
"icon": "pad",
|
|
1544
|
+
"line": 6084,
|
|
1545
|
+
"groups": [
|
|
1546
|
+
{
|
|
1547
|
+
"group": "Pad",
|
|
1548
|
+
"line": 6085,
|
|
1549
|
+
"options": [
|
|
1550
|
+
"pad_enable",
|
|
1551
|
+
"pad_wall_thickness",
|
|
1552
|
+
"pad_wall_height",
|
|
1553
|
+
"pad_brim_size",
|
|
1554
|
+
"pad_max_merge_distance",
|
|
1555
|
+
"pad_wall_slope",
|
|
1556
|
+
"pad_around_object",
|
|
1557
|
+
"pad_around_object_everywhere",
|
|
1558
|
+
"pad_object_gap",
|
|
1559
|
+
"pad_object_connector_stride",
|
|
1560
|
+
"pad_object_connector_width",
|
|
1561
|
+
"pad_object_connector_penetration"
|
|
1562
|
+
]
|
|
1563
|
+
}
|
|
1564
|
+
]
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
"page": "Hollowing",
|
|
1568
|
+
"icon": "hollowing",
|
|
1569
|
+
"line": 6102,
|
|
1570
|
+
"groups": [
|
|
1571
|
+
{
|
|
1572
|
+
"group": "Hollowing",
|
|
1573
|
+
"line": 6103,
|
|
1574
|
+
"options": [
|
|
1575
|
+
"hollowing_enable",
|
|
1576
|
+
"hollowing_min_thickness",
|
|
1577
|
+
"hollowing_quality",
|
|
1578
|
+
"hollowing_closing_distance"
|
|
1579
|
+
]
|
|
1580
|
+
}
|
|
1581
|
+
]
|
|
1582
|
+
},
|
|
1583
|
+
{
|
|
1584
|
+
"page": "Advanced",
|
|
1585
|
+
"icon": "wrench",
|
|
1586
|
+
"line": 6109,
|
|
1587
|
+
"groups": [
|
|
1588
|
+
{
|
|
1589
|
+
"group": "Slicing",
|
|
1590
|
+
"line": 6110,
|
|
1591
|
+
"options": [
|
|
1592
|
+
"slice_closing_radius",
|
|
1593
|
+
"slicing_mode"
|
|
1594
|
+
]
|
|
1595
|
+
}
|
|
1596
|
+
]
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
"page": "Output options",
|
|
1600
|
+
"icon": "output+page_white",
|
|
1601
|
+
"line": 6114,
|
|
1602
|
+
"groups": [
|
|
1603
|
+
{
|
|
1604
|
+
"group": "Output file",
|
|
1605
|
+
"line": 6115,
|
|
1606
|
+
"options": []
|
|
1607
|
+
}
|
|
1608
|
+
]
|
|
1609
|
+
},
|
|
1610
|
+
{
|
|
1611
|
+
"page": "Dependencies",
|
|
1612
|
+
"icon": "wrench",
|
|
1613
|
+
"line": 6120,
|
|
1614
|
+
"groups": [
|
|
1615
|
+
{
|
|
1616
|
+
"group": "Profile dependencies",
|
|
1617
|
+
"line": 6121,
|
|
1618
|
+
"options": []
|
|
1619
|
+
}
|
|
1620
|
+
]
|
|
1621
|
+
}
|
|
1280
1622
|
]
|
|
1281
1623
|
}
|
package/engine/README.md
CHANGED
|
@@ -355,6 +355,26 @@ Two consequences worth knowing before you build on this:
|
|
|
355
355
|
|
|
356
356
|
Results carry the split: `stats.filament_mm_by_tool` (indexed by tool number, one slot per extruder, sums to `filament_mm`) and `stats.filament_mm_purge` (the prime/wipe tower share, already included in the per-tool figures). In the streamed toolpath, `paths[k+3]` encodes `role + tool * 16` — mask with `& 15` for the role and `>>> 4` for the tool.
|
|
357
357
|
|
|
358
|
+
## SLA parameters
|
|
359
|
+
|
|
360
|
+
The table above is the FFF kernel's reader. The SLA entry (`slice_sla`) reads its own parameter set, produced
|
|
361
|
+
by `deriveSlaParams(settings)` — unlike `deriveKernelParams` it always emits every key (54 today), filling
|
|
362
|
+
schema/reference-machine defaults, because the SLA keys are not shared with another technology whose defaults
|
|
363
|
+
could disagree. The groups:
|
|
364
|
+
|
|
365
|
+
| Group | Keys |
|
|
366
|
+
| --- | --- |
|
|
367
|
+
| Layers and exposure | `layer_height`, `initial_layer_height`, `exposure_time`, `initial_exposure_time`, `faded_layers` |
|
|
368
|
+
| Display (doubles as the bed) | `display_width/height`, `display_pixels_x/y`, `display_orientation` (portrait default), `display_mirror_x/y`, `bed_width/depth` |
|
|
369
|
+
| Archive identity (config.ini) | `printer_model`, `printer_variant`, `printer_settings_id`, `sla_print_settings_id`, `sla_material_settings_id`, `material_print_speed` |
|
|
370
|
+
| Supports (upstream `SupportTreeConfig`) | `supports_enable`, `support_tree_type`, `support_pillar_diameter`, `support_head_*`, `support_points_density_relative`, `support_critical_angle`, `support_max_bridge_length`, `support_max_pillar_link_distance`, `support_base_*`, `support_small_pillar_diameter_percent`, `support_pillar_widening_factor`, `support_max_bridges_on_pillar`, `support_max_weight_on_model`, `support_object_elevation`, `support_pillar_connection_mode`, `support_buildplate_only`, `slice_closing_radius` |
|
|
371
|
+
| Pad (upstream `PadConfig`) | `pad_enable`, `pad_brim_size`, `pad_wall_thickness`, `pad_wall_height`, `pad_wall_slope`, `pad_max_merge_distance`, `pad_around_object` (embed — forces zero elevation), `pad_around_object_everywhere`, `pad_object_gap`, `pad_object_connector_width/stride/penetration` |
|
|
372
|
+
| Capability gate | `hollowing_enable` — `true` is refused with `SLA_UNSUPPORTED_HOLLOWING`, never sliced solid |
|
|
373
|
+
|
|
374
|
+
The result has no G-code: `stats.sla` is `true`, layers carry the same stride-8 segment stream, `support_mesh`
|
|
375
|
+
and `pad_mesh` are triangle soups for the preview, and `stats.lift_layers` (pad + elevation) is what a preview
|
|
376
|
+
must lift the model by.
|
|
377
|
+
|
|
358
378
|
## License
|
|
359
379
|
|
|
360
380
|
AGPL-3.0-or-later (derived from OrcaSlicer). A web app embedding this package must comply with AGPL — including offering its source to network users.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// three-slicer SLA (resin) headless example: slice a cube with supports + pad through the public API,
|
|
2
|
+
// then show the typed capability refusal — an unsupported request errors, it never approximates.
|
|
3
|
+
// run: node packages/engine/examples/sla_headless.mjs
|
|
4
|
+
import { createSlicer } from 'three-slicer'
|
|
5
|
+
import { deriveSlaParams, printerTechnology } from 'three-slicer/settings'
|
|
6
|
+
|
|
7
|
+
// minimal binary-STL writer for a 10mm cube. Winding matters here, unlike the FFF example: the SLA
|
|
8
|
+
// support generator reads facet normals to find downward faces, so every face is CCW seen from outside.
|
|
9
|
+
function boxSTL() {
|
|
10
|
+
const vertices = [[-5,-5,0],[5,-5,0],[5,5,0],[-5,5,0],[-5,-5,10],[5,-5,10],[5,5,10],[-5,5,10]]
|
|
11
|
+
const faces = [[0,2,1],[0,3,2],[4,5,6],[4,6,7],[0,1,5],[0,5,4],[1,2,6],[1,6,5],[2,3,7],[2,7,6],[3,0,4],[3,4,7]]
|
|
12
|
+
const buf = Buffer.alloc(84 + faces.length * 50)
|
|
13
|
+
buf.writeUInt32LE(faces.length, 80)
|
|
14
|
+
faces.forEach((face, i) => {
|
|
15
|
+
let off = 84 + i * 50 + 12
|
|
16
|
+
for (const vi of face) for (const v of vertices[vi]) { buf.writeFloatLE(v, off); off += 4 }
|
|
17
|
+
})
|
|
18
|
+
return buf
|
|
19
|
+
}
|
|
20
|
+
const cube = boxSTL()
|
|
21
|
+
|
|
22
|
+
// A sparse settings map, the same shape the UI holds. printer_technology is what routes to slice_sla.
|
|
23
|
+
const settings = {
|
|
24
|
+
printer_technology: 'SLA',
|
|
25
|
+
layer_height: 0.05,
|
|
26
|
+
exposure_time: 7,
|
|
27
|
+
supports_enable: true,
|
|
28
|
+
support_object_elevation: 5,
|
|
29
|
+
pad_enable: true,
|
|
30
|
+
}
|
|
31
|
+
console.log(`technology: ${printerTechnology(settings)}`)
|
|
32
|
+
|
|
33
|
+
const slicer = await createSlicer()
|
|
34
|
+
const params = deriveSlaParams(settings) // fills display/support/pad defaults (SL1 reference machine)
|
|
35
|
+
|
|
36
|
+
// (a) SLA slice — no G-code; masks, meshes and resin stats instead.
|
|
37
|
+
const r = slicer.sliceSla(cube, params)
|
|
38
|
+
if (r.error) { console.error('FAIL', r.error); process.exit(1) }
|
|
39
|
+
console.log(`sla : layers=${r.stats.layers} (lift=${r.stats.lift_layers}) points=${r.stats.support_points}`
|
|
40
|
+
+ ` pad_layers=${r.stats.pad_layers} resin=${r.stats.resin_ml.toFixed(2)}ml`)
|
|
41
|
+
console.log(`meshes: support=${r.support_mesh.length / 9} tris, pad=${r.pad_mesh.length / 9} tris`)
|
|
42
|
+
|
|
43
|
+
// (b) the capability gate: hollowing is not ported, so the request is REFUSED with a stable code —
|
|
44
|
+
// a solid slice answered to a hollow request would be a mislabeled print.
|
|
45
|
+
const refused = slicer.sliceSla(cube, deriveSlaParams({ ...settings, hollowing_enable: true }))
|
|
46
|
+
console.log(`gate : ${refused.error}`)
|
|
47
|
+
|
|
48
|
+
if (r.stats.support_points > 0 && r.stats.pad_layers > 0 && /^SLA_UNSUPPORTED_HOLLOWING/.test(refused.error ?? ''))
|
|
49
|
+
console.log('OK — SLA slices headlessly via the public API')
|
|
50
|
+
else { console.error('FAIL'); process.exit(1) }
|
|
51
|
+
slicer.dispose()
|
package/engine/index.d.ts
CHANGED
|
@@ -86,6 +86,9 @@ export interface PaintArgs {
|
|
|
86
86
|
}
|
|
87
87
|
export interface Slicer {
|
|
88
88
|
slice(stl: ArrayBuffer | Uint8Array, params: object | string, cb?: SliceCallbacks): SliceResult
|
|
89
|
+
/** SLA (resin) slice — no G-code: mask segment streams per layer, support/pad meshes, resin stats.
|
|
90
|
+
* Params from deriveSlaParams(); a refused capability (e.g. hollowing) sets `error` to its typed code. */
|
|
91
|
+
sliceSla(stl: ArrayBuffer | Uint8Array, params: object | string, onProgress?: (done: number, total: number) => void): SliceResult
|
|
89
92
|
paintPrepare(stl: ArrayBuffer | Uint8Array): number
|
|
90
93
|
paint(args: PaintArgs): { enf: number; blk: number }
|
|
91
94
|
paintClear(): void
|
package/engine/index.js
CHANGED
|
@@ -31,6 +31,12 @@ export async function createSlicer() {
|
|
|
31
31
|
try { return M.slice(u8(stl), p, onProgress || (() => {})) }
|
|
32
32
|
finally { if (onLayer) M.clear_layer_sink() }
|
|
33
33
|
},
|
|
34
|
+
// SLA (resin) slice: no G-code — layers carry the mask segment stream, support_mesh/pad_mesh the preview
|
|
35
|
+
// soups, stats the resin figures and lift_layers. Same params-object-or-string contract as slice().
|
|
36
|
+
sliceSla(stl, params, onProgress) {
|
|
37
|
+
const p = typeof params === 'string' ? params : JSON.stringify(params || {})
|
|
38
|
+
return M.slice_sla(u8(stl), p, onProgress || (() => {}))
|
|
39
|
+
},
|
|
34
40
|
paintPrepare(stl) { M.selector_prepare(u8(stl)); return M.selector_facet_count() },
|
|
35
41
|
paint(a) {
|
|
36
42
|
M.selector_paint(a.facet, a.hx, a.hy, a.hz, a.cx, a.cy, a.cz, a.radius, a.enforcer)
|
package/engine/src/client.js
CHANGED
|
@@ -14,14 +14,19 @@
|
|
|
14
14
|
// replies exactly once, so a FIFO of pending requests is enough to match a reply to its caller — the protocol
|
|
15
15
|
// carries no request ids and does not need them.
|
|
16
16
|
import { engineWorkerURL } from '../index.js'
|
|
17
|
+
import { parseSlaJob, SlaRequestError } from './sla_request.js'
|
|
18
|
+
|
|
19
|
+
export { SLA_CAPABILITIES, SLA_JOB_VERSION, SlaRequestError } from './sla_request.js'
|
|
17
20
|
|
|
18
21
|
// Which reply type ends which command. A slice has no cmd (that is what selects slicing) and ends on 'done'.
|
|
19
22
|
const REPLY_OF = {
|
|
20
23
|
warmup: 'warm', prepare: 'prepared', paint: 'painted', erase: 'painted', clear: 'painted',
|
|
21
|
-
importPaint: 'painted', exportPaint: 'paintExport', overlay: 'overlay', slice: 'done',
|
|
24
|
+
importPaint: 'painted', exportPaint: 'paintExport', overlay: 'overlay', slice: 'done', sla: 'done',
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
const asBuffer = (data) => (data instanceof ArrayBuffer ? data : data?.buffer ?? data)
|
|
28
|
+
const slaTransferables = (job) => job.objects.flatMap(object => [object, ...(object.modifierVolumes ?? [])])
|
|
29
|
+
.map(record => asBuffer(record.stl)).filter(buffer => buffer instanceof ArrayBuffer)
|
|
25
30
|
|
|
26
31
|
/**
|
|
27
32
|
* @param {Worker} [worker] an existing worker to drive. Omit to create one — which only works in a browser,
|
|
@@ -49,7 +54,9 @@ export function createSlicerClient(worker = new Worker(engineWorkerURL(), { type
|
|
|
49
54
|
return
|
|
50
55
|
}
|
|
51
56
|
pending.shift()
|
|
52
|
-
if (data.type === 'error') {
|
|
57
|
+
if (data.type === 'error') {
|
|
58
|
+
head.reject(data.code ? new SlaRequestError(data.code, data.error) : new Error(data.error)); return
|
|
59
|
+
}
|
|
53
60
|
if (data.type !== head.expect) { head.reject(new Error(`expected '${head.expect}', got '${data.type}'`)); return }
|
|
54
61
|
// What the layer messages accumulated, if this caller did not take them itself.
|
|
55
62
|
if (data.type === 'done' && head.layers.length) data.assembled = { gcode: head.chunks.join(''), layers: head.layers }
|
|
@@ -92,6 +99,28 @@ export function createSlicerClient(worker = new Worker(engineWorkerURL(), { type
|
|
|
92
99
|
return { ...result, gcode: reply.assembled.gcode, layers: reply.assembled.layers }
|
|
93
100
|
},
|
|
94
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Legacy single-object SLA slice: per-layer closed contours instead of toolpaths. It uses WASM when available;
|
|
104
|
+
* its contour-only JS fallback rejects requested supports and pads. Same streaming shape as slice(): `onLayer` hands you the layers and the result
|
|
105
|
+
* carries stats only; without it they are assembled onto the result.
|
|
106
|
+
*/
|
|
107
|
+
async sliceSla(stl, params, { onProgress, onLayer } = {}) {
|
|
108
|
+
const buffer = asBuffer(stl)
|
|
109
|
+
const entry = { cmd: 'sla', stl: buffer, params: typeof params === 'string' ? params : JSON.stringify(params ?? {}) }
|
|
110
|
+
const reply = await send(entry, { transfer: [buffer], onProgress, onLayer })
|
|
111
|
+
const result = reply.result ?? {}
|
|
112
|
+
if (!reply.assembled) return result
|
|
113
|
+
return { ...result, layers: reply.assembled.layers }
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
async sliceSlaJob(job, { onProgress, onLayer } = {}) {
|
|
117
|
+
const parsed = parseSlaJob(job)
|
|
118
|
+
const reply = await send({ cmd: 'slaJob', job: parsed }, { transfer: slaTransferables(parsed), onProgress, onLayer })
|
|
119
|
+
const result = reply.result ?? {}
|
|
120
|
+
if (!reply.assembled) return result
|
|
121
|
+
return { ...result, layers: reply.assembled.layers }
|
|
122
|
+
},
|
|
123
|
+
|
|
95
124
|
/** Register a mesh for painting. `keepPaint` carries existing marks across a move. */
|
|
96
125
|
prepare: (stl, { keepPaint = false } = {}) => {
|
|
97
126
|
const buffer = asBuffer(stl)
|