partforge 0.122.0 → 0.124.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.
- package/README.md +3 -2
- package/docs/AUTHORING-PARTS.md +57 -31
- package/docs/KERNEL-CONTRACT.md +10 -0
- package/package.json +1 -1
- package/src/framework/annotate/annotate-mode.js +6 -1
- package/src/framework/app.css +69 -57
- package/src/framework/chrome.css +38 -25
- package/src/framework/cutaway-gizmo.js +2 -1
- package/src/framework/geometry/blend-surfaces.js +256 -0
- package/src/framework/geometry/creased-normals.js +121 -7
- package/src/framework/geometry/manifold-backend.js +56 -15
- package/src/framework/geometry/mesh-fillet.js +55 -5
- package/src/framework/materials/assets/SOURCES.md +1 -1
- package/src/framework/materials/assets/ground-pei.jpg +0 -0
- package/src/framework/materials/environment.js +16 -4
- package/src/framework/materials/patterns.js +106 -7
- package/src/framework/materials/physical.js +9 -2
- package/src/framework/materials/presets.js +6 -3
- package/src/framework/materials/print-bed.js +17 -0
- package/src/framework/materials/uv.js +27 -8
- package/src/framework/mount.js +83 -36
- package/src/framework/projection.js +48 -1
- package/src/framework/view-state.js +4 -10
- package/src/framework/view-style-controls.js +287 -0
- package/src/framework/view-style-state.js +27 -0
- package/src/framework/viewcube/viewcube-controls.js +23 -64
- package/src/framework/viewcube/viewcube-mode.js +5 -3
- package/src/framework/viewer.js +526 -47
- package/types/index.d.ts +14 -8
- package/src/framework/realistic-controls.js +0 -78
|
@@ -1,33 +1,26 @@
|
|
|
1
|
-
// The view cube's chrome: the bottom-right stack (the cube,
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
1
|
+
// The view cube's chrome: the bottom-right stack (the cube, and whatever sits
|
|
2
|
+
// over its bottom-right corner), and the visually-hidden per-view buttons that
|
|
3
|
+
// stand in for the DOM focus a canvas cannot give us. Generated, not declared —
|
|
4
|
+
// no part's HTML carries this, and partforge-cloud's scaffold does not either
|
|
5
|
+
// (the mobile-tabs.js and animation-controls.js precedent).
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
// rather than `canvas + gap + button`, so the size it publishes below — and
|
|
22
|
-
// therefore the crowding decision that reads it — went from 167px to 135
|
|
23
|
-
// (101 below the rail's narrow breakpoint).
|
|
24
|
-
import { attachButtonTooltips } from "../tooltip.js";
|
|
7
|
+
// Through 2026-09-23 this file also generated the projection toggle (#projection),
|
|
8
|
+
// a small bare circle laid OVER the cube's bottom-right corner — absolutely
|
|
9
|
+
// positioned, so the stack stayed exactly as wide as the canvas (135px, or 101
|
|
10
|
+
// below the rail's narrow breakpoint) and the size published below was the
|
|
11
|
+
// canvas's alone. There is no projection control any more: since 2026-09-24
|
|
12
|
+
// the projection is AUTOMATIC (Fusion 360's "Perspective with Ortho Faces") —
|
|
13
|
+
// a face click, on the canvas or through the keyboard buttons below, settles
|
|
14
|
+
// into orthographic, and rotating off the face returns to perspective (see
|
|
15
|
+
// viewer.js's tweenCameraTo). The view style button (view-style-controls.js)
|
|
16
|
+
// lives in the bottom toolbar (#viewbar); only a host with no #viewbar gets it
|
|
17
|
+
// in this stack, over the cube's bottom-right corner, absolutely positioned so
|
|
18
|
+
// the stack's published size is still the canvas's. History of the toggle's
|
|
19
|
+
// earlier homes (a `.pf-viewcube-pill` card below the cube, then a circle
|
|
20
|
+
// beside it) is in chrome.css/app.css's viewcube sections.
|
|
25
21
|
import { runCleanupSteps } from "../teardown.js";
|
|
26
22
|
import { createViewcubeMode } from "./viewcube-mode.js";
|
|
27
23
|
|
|
28
|
-
const PERSPECTIVE_ICON = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 4l18 3v10l-18 3z"/><path d="M3 4v16"/></svg>`;
|
|
29
|
-
const ORTHOGRAPHIC_ICON = `<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="6" width="14" height="12" rx="1"/><path d="M7 6V3h14v12h-4"/></svg>`;
|
|
30
|
-
|
|
31
24
|
// One hidden button per canonical FACE view. Edges and corners are reachable by
|
|
32
25
|
// pointer only — six targets is a usable keyboard surface; twenty-six is a
|
|
33
26
|
// tab-stop thicket.
|
|
@@ -40,19 +33,13 @@ const KEY_VIEWS = [
|
|
|
40
33
|
["bottom", "View from the bottom"],
|
|
41
34
|
];
|
|
42
35
|
|
|
43
|
-
export function attachViewcubeControls(viewer, { stage } = {}
|
|
36
|
+
export function attachViewcubeControls(viewer, { stage } = {}) {
|
|
44
37
|
const stack = document.createElement("div");
|
|
45
38
|
stack.className = "pf-viewcube-stack";
|
|
46
39
|
stage.appendChild(stack);
|
|
47
40
|
|
|
48
41
|
const mode = createViewcubeMode(viewer, { host: stack });
|
|
49
42
|
|
|
50
|
-
const button = document.createElement("button");
|
|
51
|
-
button.type = "button";
|
|
52
|
-
button.id = "projection";
|
|
53
|
-
button.className = "pf-viewcube-toggle";
|
|
54
|
-
stack.appendChild(button);
|
|
55
|
-
|
|
56
43
|
const keys = document.createElement("div");
|
|
57
44
|
keys.className = "pf-viewcube-key";
|
|
58
45
|
const keyButtons = KEY_VIEWS.map(([view, label]) => {
|
|
@@ -66,40 +53,15 @@ export function attachViewcubeControls(viewer, { stage } = {}, { tooltip } = {})
|
|
|
66
53
|
});
|
|
67
54
|
stack.appendChild(keys);
|
|
68
55
|
|
|
69
|
-
const tooltipBinding = tooltip
|
|
70
|
-
? attachButtonTooltips(tooltip, [{ element: button }])
|
|
71
|
-
: null;
|
|
72
|
-
|
|
73
|
-
function sync() {
|
|
74
|
-
const ortho = viewer.getProjection() === "orthographic";
|
|
75
|
-
button.innerHTML = ortho ? ORTHOGRAPHIC_ICON : PERSPECTIVE_ICON;
|
|
76
|
-
button.classList.toggle("on", ortho);
|
|
77
|
-
button.setAttribute("aria-pressed", String(ortho));
|
|
78
|
-
const label = ortho ? "Switch to perspective view" : "Switch to orthographic view";
|
|
79
|
-
button.setAttribute("aria-label", label);
|
|
80
|
-
if (!tooltip) button.title = label;
|
|
81
|
-
tooltipBinding?.sync();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const onToggle = () => {
|
|
85
|
-
viewer.setProjection(viewer.getProjection() === "orthographic" ? "perspective" : "orthographic");
|
|
86
|
-
sync();
|
|
87
|
-
};
|
|
88
|
-
button.addEventListener("click", onToggle);
|
|
89
|
-
|
|
90
56
|
const keyHandlers = keyButtons.map((b) => {
|
|
91
57
|
// Same user intent as clicking the face on the canvas, so the same
|
|
92
|
-
// `refit`
|
|
93
|
-
|
|
58
|
+
// `refit` and `autoProjection` (a face view settles into orthographic) —
|
|
59
|
+
// these buttons ARE the keyboard route to that click.
|
|
60
|
+
const handler = () => viewer.tweenCameraTo(b.dataset.view, { duration: 0.6, refit: true, autoProjection: true });
|
|
94
61
|
b.addEventListener("click", handler);
|
|
95
62
|
return handler;
|
|
96
63
|
});
|
|
97
64
|
|
|
98
|
-
// A host or another mode can flip projection without going through this
|
|
99
|
-
// button; the chrome follows rather than drifting out of sync.
|
|
100
|
-
const offProjection = viewer.onProjectionChange(sync);
|
|
101
|
-
sync();
|
|
102
|
-
|
|
103
65
|
// Publish the stack's size on the element itself, in the data-pf-* convention
|
|
104
66
|
// the shell already uses (data-pf-pane). animation-controls.js reads it to
|
|
105
67
|
// decide whether the transport bar is crowded, and that decision has to come
|
|
@@ -144,11 +106,8 @@ export function attachViewcubeControls(viewer, { stage } = {}, { tooltip } = {})
|
|
|
144
106
|
if (detached) return;
|
|
145
107
|
detached = true;
|
|
146
108
|
runCleanupSteps([
|
|
147
|
-
offProjection,
|
|
148
109
|
() => sizeObserver?.disconnect(),
|
|
149
|
-
() => button.removeEventListener("click", onToggle),
|
|
150
110
|
...keyButtons.map((b, i) => () => b.removeEventListener("click", keyHandlers[i])),
|
|
151
|
-
() => tooltipBinding?.detach(),
|
|
152
111
|
() => mode.detach(),
|
|
153
112
|
() => stack.remove(),
|
|
154
113
|
], "viewcube control cleanup failed");
|
|
@@ -128,9 +128,11 @@ export function createViewcubeMode(viewer, {
|
|
|
128
128
|
const id = hitRegion(...localPoint(event), projected);
|
|
129
129
|
// refit: clicking a region is now the only reframe control the framework's
|
|
130
130
|
// own pages ship, so it has to actually refit — under orthographic a tween
|
|
131
|
-
// alone changes the angle and leaves the user's dolly in place.
|
|
132
|
-
//
|
|
133
|
-
|
|
131
|
+
// alone changes the angle and leaves the user's dolly in place.
|
|
132
|
+
// autoProjection: a FACE click settles into orthographic, an edge or corner
|
|
133
|
+
// click is perspective (Fusion 360's "Perspective with Ortho Faces"). Only
|
|
134
|
+
// the cube passes it — animation cues never do. See viewer.js's tweenCameraTo.
|
|
135
|
+
if (id) viewer.tweenCameraTo(id, { duration: 0.6, refit: true, autoProjection: true });
|
|
134
136
|
};
|
|
135
137
|
|
|
136
138
|
const onPointerLeave = () => {
|