partforge 0.13.0 → 0.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "partforge",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Turn a declarative part definition into a parametric-CAD web app (three.js + Manifold/Replicad). Requires a Vite-based consumer.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,9 @@
1
1
  /* Shared chrome styles for any part app (panel, tabs, viewbar, download row,
2
2
  busy overlay) + the light/dark palettes. Imported by framework/mount.js, so
3
3
  every part-app gets it; each part's HTML only carries structural markup.
4
+ Skinned to the shared design language (partforge-cloud spec
5
+ 2026-07-17-shared-design-language-design.md): zinc-tuned neutrals, blue
6
+ accent, shadcn-shaped radii/shadows/focus rings — plain CSS on --pf-*.
4
7
  See docs/AUTHORING-PARTS.md. */
5
8
  @import "./tokens.css"; /* palette + light overrides; also exported standalone as partforge/tokens.css */
6
9
 
@@ -13,8 +16,9 @@ canvas { display: block; }
13
16
  #panel {
14
17
  position: fixed; top: 12px; left: 12px; width: 256px;
15
18
  max-height: calc(100vh - 24px); overflow-y: auto; z-index: 10;
16
- background: var(--pf-surface); border: 1px solid var(--pf-border); border-radius: 10px;
17
- padding: 14px; color: var(--pf-text); box-shadow: 0 6px 24px rgba(0,0,0,.35);
19
+ background: var(--pf-surface); border: 1px solid var(--pf-border); border-radius: 14px;
20
+ padding: 14px; color: var(--pf-text);
21
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);
18
22
  }
19
23
  #panel h1 { font-size: 14px; margin: 0 0 2px; color: var(--pf-text-strong); letter-spacing: -0.01em; }
20
24
  #panel .sub {
@@ -23,16 +27,18 @@ canvas { display: block; }
23
27
  margin: 0 0 12px; padding-bottom: 12px; border-bottom: 1px solid var(--pf-border);
24
28
  }
25
29
 
26
- .seg { display: flex; gap: 4px; margin-bottom: 12px; }
30
+ .seg { display: flex; gap: 2px; margin-bottom: 12px;
31
+ background: var(--pf-surface-2); border-radius: 10px; padding: 3px; }
27
32
  .seg button {
28
- flex: 1; padding: 7px 0; border: 1px solid var(--pf-border); border-radius: 7px;
29
- background: var(--pf-surface-2); color: var(--pf-muted-2); cursor: pointer;
33
+ flex: 1; padding: 6px 0; border: 0; border-radius: 8px;
34
+ background: transparent; color: var(--pf-muted); cursor: pointer;
30
35
  font-family: var(--pf-mono); font-size: 11px; letter-spacing: 0.02em;
31
36
  }
32
- .seg button.on { background: var(--pf-accent); color: var(--pf-on-accent); border-color: var(--pf-accent); }
37
+ .seg button:hover { color: var(--pf-text-2); }
38
+ .seg button.on { background: var(--pf-accent); color: var(--pf-on-accent); }
33
39
 
34
40
  .section {
35
- border: 1px solid var(--pf-border); border-radius: 8px; padding: 10px;
41
+ border: 1px solid var(--pf-border); border-radius: 10px; padding: 10px;
36
42
  margin-bottom: 8px; background: var(--pf-surface-2);
37
43
  }
38
44
  .sec-title {
@@ -41,7 +47,7 @@ canvas { display: block; }
41
47
  }
42
48
  select.preset {
43
49
  width: 100%; background: var(--pf-input-bg); color: var(--pf-text-2);
44
- border: 1px solid var(--pf-border); border-radius: 6px; padding: 6px 8px;
50
+ border: 1px solid var(--pf-border); border-radius: 8px; padding: 7px 9px;
45
51
  font-family: var(--pf-mono); font-size: 11px;
46
52
  }
47
53
  .feat { display: flex; align-items: center; gap: 8px; margin: 6px 0;
@@ -50,7 +56,7 @@ select.preset {
50
56
  .feat-group { margin: 2px 0 8px; padding-left: 10px; border-left: 2px solid var(--pf-border); }
51
57
  .feat-group.hidden { display: none; }
52
58
  .adv-toggle {
53
- margin-top: 8px; padding: 4px 0; width: 100%; border: 0; border-radius: 5px;
59
+ margin-top: 8px; padding: 4px 0; width: 100%; border: 0; border-radius: 6px;
54
60
  background: transparent; color: var(--pf-muted); cursor: pointer;
55
61
  font-family: var(--pf-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; text-align: left;
56
62
  }
@@ -66,9 +72,10 @@ select.preset {
66
72
  .row .num {
67
73
  width: 54px; text-align: right; font-family: var(--pf-mono); font-size: 12px; font-variant-numeric: tabular-nums;
68
74
  background: var(--pf-input-bg); color: var(--pf-text-strong);
69
- border: 1px solid var(--pf-border); border-radius: 5px; padding: 3px 6px;
75
+ border: 1px solid var(--pf-border); border-radius: 6px; padding: 3px 6px;
70
76
  }
71
- .row .num:focus { outline: none; border-color: var(--pf-accent); box-shadow: 0 0 0 3px var(--pf-accent-soft); }
77
+ .row .num:focus { outline: none; border-color: var(--pf-accent);
78
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pf-accent) 35%, transparent); }
72
79
  .row .num::-webkit-outer-spin-button, .row .num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
73
80
  .row .num { -moz-appearance: textfield; }
74
81
  .row .unit { font-family: var(--pf-mono); color: var(--pf-muted); font-size: 10px; }
@@ -87,16 +94,18 @@ input[type="range"]::-moz-range-thumb {
87
94
  width: 14px; height: 14px; border-radius: 50%; background: var(--pf-accent);
88
95
  border: 2px solid var(--pf-surface-2); box-shadow: 0 0 0 1px var(--pf-accent);
89
96
  }
90
- input[type="range"]:hover::-webkit-slider-thumb { box-shadow: 0 0 0 5px var(--pf-accent-soft); }
97
+ input[type="range"]:hover::-webkit-slider-thumb { box-shadow: 0 0 0 5px color-mix(in oklab, var(--pf-accent) 35%, transparent); }
91
98
  input[type="range"]:focus-visible { outline: none; }
92
- input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 5px var(--pf-accent-soft); }
93
- input[type="range"]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 5px var(--pf-accent-soft); }
99
+ input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 5px color-mix(in oklab, var(--pf-accent) 35%, transparent); }
100
+ input[type="range"]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 5px color-mix(in oklab, var(--pf-accent) 35%, transparent); }
94
101
 
95
102
  button.action {
96
- width: 100%; margin-top: 8px; padding: 9px; border: 0; border-radius: 7px;
97
- background: var(--pf-accent); color: var(--pf-on-accent); font-weight: 600; cursor: pointer;
103
+ width: 100%; margin-top: 8px; padding: 9px; border: 0; border-radius: 8px;
104
+ background: var(--pf-accent); color: var(--pf-on-accent); font-weight: 500; cursor: pointer;
98
105
  }
99
- button.ghost { background: var(--pf-border); color: var(--pf-text-2); font-weight: 500; }
106
+ button.action:hover:not(:disabled) { background: color-mix(in oklab, var(--pf-accent) 90%, black); }
107
+ button.ghost { background: transparent; border: 1px solid var(--pf-border); color: var(--pf-text-2); font-weight: 500; }
108
+ button.ghost:hover:not(:disabled) { background: var(--pf-surface-2); }
100
109
  button.action:disabled { opacity: .5; cursor: default; }
101
110
 
102
111
  .dl { margin-top: 14px; }
@@ -106,8 +115,8 @@ button.action:disabled { opacity: .5; cursor: default; }
106
115
  }
107
116
  .dl-row { display: flex; gap: 6px; }
108
117
  .dl-row button {
109
- flex: 1; padding: 8px 0; border: 1px solid var(--pf-border); border-radius: 7px;
110
- background: var(--pf-surface-2); color: var(--pf-text-2);
118
+ flex: 1; padding: 8px 0; border: 1px solid var(--pf-border); border-radius: 8px;
119
+ background: transparent; color: var(--pf-text-2);
111
120
  font-family: var(--pf-mono); font-weight: 600; font-size: 11px; letter-spacing: 0.06em; cursor: pointer;
112
121
  }
113
122
  .dl-row button:hover:not(:disabled) { border-color: var(--pf-accent); color: var(--pf-text-strong); }
@@ -120,7 +129,8 @@ button.action:disabled { opacity: .5; cursor: default; }
120
129
  /* keyboard focus ring shared across the panel's interactive controls */
121
130
  .seg button:focus-visible, select.preset:focus-visible, .dl-row button:focus-visible,
122
131
  button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-visible {
123
- outline: 2px solid var(--pf-accent); outline-offset: 2px;
132
+ outline: none;
133
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pf-accent) 35%, transparent);
124
134
  }
125
135
 
126
136
  /* part tabs, floated top-centre over the viewport */
@@ -130,7 +140,8 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
130
140
  }
131
141
  #topbar .seg {
132
142
  margin: 0; padding: 4px; background: var(--pf-surface); border: 1px solid var(--pf-border);
133
- border-radius: 9px; box-shadow: 0 6px 24px rgba(0,0,0,.35);
143
+ border-radius: 14px;
144
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);
134
145
  }
135
146
  #topbar .seg button { min-width: 70px; padding: 7px 10px; }
136
147
 
@@ -139,16 +150,17 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
139
150
  position: fixed; top: 12px; right: 12px; z-index: 15;
140
151
  display: flex; gap: 4px; padding: 4px;
141
152
  background: var(--pf-surface); border: 1px solid var(--pf-border);
142
- border-radius: 9px; box-shadow: 0 6px 24px rgba(0,0,0,.35);
153
+ border-radius: 14px;
154
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);
143
155
  }
144
156
  #viewbar button {
145
- width: 34px; height: 34px; border: 1px solid var(--pf-border); border-radius: 7px;
146
- background: var(--pf-surface-2); color: var(--pf-muted-2); cursor: pointer;
157
+ width: 34px; height: 34px; border: 0; border-radius: 10px;
158
+ background: transparent; color: var(--pf-muted-2); cursor: pointer;
147
159
  font-size: 15px; line-height: 1;
148
160
  display: flex; align-items: center; justify-content: center;
149
161
  }
150
- #viewbar button:hover { color: var(--pf-text); }
151
- #viewbar button.on { background: var(--pf-accent); color: var(--pf-on-accent); border-color: var(--pf-accent); }
162
+ #viewbar button:hover { color: var(--pf-text); background: var(--pf-surface-2); }
163
+ #viewbar button.on { background: var(--pf-accent); color: var(--pf-on-accent); }
152
164
 
153
165
  #busy {
154
166
  position: fixed; inset: 0; z-index: 20; pointer-events: none;
@@ -161,7 +173,7 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
161
173
  border: 4px solid var(--pf-border); border-top-color: var(--pf-accent);
162
174
  animation: spin 0.9s linear infinite;
163
175
  }
164
- #busy .phase { color: var(--pf-text); font-size: 13px; text-shadow: 0 1px 6px rgba(0,0,0,.6); }
176
+ #busy .phase { color: var(--pf-text); font-size: 13px; }
165
177
  @keyframes spin { to { transform: rotate(360deg); } }
166
178
 
167
179
  /* info glyph + description popover */
@@ -171,15 +183,17 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
171
183
  vertical-align: middle;
172
184
  }
173
185
  .info:hover { color: var(--pf-text-2); }
174
- .info:focus-visible { outline: 2px solid var(--pf-accent); outline-offset: 2px; border-radius: 3px; }
186
+ .info:focus-visible { outline: none; border-radius: 4px;
187
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--pf-accent) 35%, transparent); }
175
188
  .popover {
176
189
  position: fixed; z-index: 50; max-width: 280px; max-height: 50vh; overflow: auto;
177
190
  background: var(--pf-surface); color: var(--pf-text); border: 1px solid var(--pf-border);
178
- border-radius: 8px; padding: 10px 12px; box-shadow: 0 6px 24px rgba(0,0,0,.35);
191
+ border-radius: 14px; padding: 10px 12px;
192
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);
179
193
  font-size: 12px; line-height: 1.5;
180
194
  }
181
195
  .popover[hidden] { display: none; }
182
- .popover img { max-width: 100%; height: auto; border-radius: 4px; }
196
+ .popover img { max-width: 100%; height: auto; border-radius: 6px; }
183
197
  .popover code { font-family: var(--pf-mono); background: var(--pf-surface-2); padding: 0.05em 0.35em; border-radius: 4px; font-size: 0.9em; }
184
198
  .popover a { color: var(--pf-accent); }
185
199
  .popover p:first-child { margin-top: 0; }
@@ -193,10 +207,10 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
193
207
  /* hover feature-label tooltip (selection/hover.js) */
194
208
  #pf-hover-tip {
195
209
  position: fixed; z-index: 30; pointer-events: none; display: none;
196
- padding: 4px 9px; border-radius: 6px; max-width: 260px;
210
+ padding: 4px 9px; border-radius: 8px; max-width: 260px;
197
211
  background: var(--pf-surface); border: 1px solid var(--pf-border);
198
212
  color: var(--pf-text-strong); font-size: 12px; line-height: 1.35;
199
- box-shadow: 0 2px 10px rgba(0, 0, 0, .25);
213
+ box-shadow: 0 2px 4px -2px rgb(0 0 0 / .15);
200
214
  }
201
215
  #pf-hover-tip.show { display: block; }
202
216
  #pf-hover-tip .pf-hover-sub { color: var(--pf-muted); font-size: 11px; margin-left: 7px; }
@@ -209,8 +223,8 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
209
223
  z-index: 30; max-width: min(56ch, calc(100vw - 24px));
210
224
  padding: 10px 36px 10px 12px;
211
225
  background: var(--pf-surface); color: var(--pf-text);
212
- border: 1px solid var(--pf-border); border-radius: 10px;
213
- box-shadow: 0 6px 24px rgba(0,0,0,.35);
226
+ border: 1px solid var(--pf-border); border-radius: 14px;
227
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);
214
228
  font-size: 12px; line-height: 1.45;
215
229
  animation: pf-pick-in .18s ease;
216
230
  }
@@ -227,7 +241,7 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
227
241
  position: absolute; top: 6px; right: 6px; appearance: none;
228
242
  width: 20px; height: 20px; padding: 0;
229
243
  border: 1px solid var(--pf-border); border-radius: 6px;
230
- background: var(--pf-surface-2); color: var(--pf-muted);
244
+ background: transparent; color: var(--pf-muted);
231
245
  cursor: pointer; font-size: 13px; line-height: 1;
232
246
  display: flex; align-items: center; justify-content: center;
233
247
  }
@@ -242,11 +256,12 @@ button.action:focus-visible, .adv-toggle:focus-visible, #viewbar button:focus-vi
242
256
  position: fixed; left: 12px; bottom: 12px; z-index: 9999;
243
257
  font: 12px system-ui, sans-serif; padding: 6px 10px; cursor: pointer;
244
258
  }
245
- #pf-pick.on { outline: 2px solid #ffcc33; }
259
+ #pf-pick.on { outline: 2px solid var(--pf-accent); }
246
260
  #pf-pick-toast {
247
261
  position: fixed; left: 12px; bottom: 48px; z-index: 9999; max-width: 60ch;
248
- font: 12px ui-monospace, monospace; padding: 6px 10px; border-radius: 4px;
249
- background: rgba(20,24,29,0.92); color: #d8e0ea;
262
+ font: 12px var(--pf-mono); padding: 6px 10px; border-radius: 8px;
263
+ background: var(--pf-surface); color: var(--pf-text);
264
+ border: 1px solid var(--pf-border);
250
265
  white-space: pre-wrap; word-break: break-word; display: none;
251
266
  }
252
267
  #pf-pick-toast.show { display: block; }
@@ -3,16 +3,16 @@
3
3
  consumers (e.g. partforge-cloud's app chrome) to share one source of truth. */
4
4
  :root {
5
5
  color-scheme: dark;
6
- --pf-bg: #15181d; --pf-surface: #1f242c; --pf-surface-2: #20262e; --pf-border: #2c333d;
7
- --pf-text: #d6dbe2; --pf-text-strong: #e7ebf1; --pf-text-2: #cdd4dd;
8
- --pf-muted: #7d8794; --pf-muted-2: #aab2bd; --pf-status: #8b94a0; --pf-hint: #6b7480;
9
- --pf-accent: #3f7bf0; --pf-accent-soft: #26314a; --pf-on-accent: #fff; --pf-input-bg: #161a20; --pf-err: #f8746c;
6
+ --pf-bg: oklch(0.19 0.01 262); --pf-surface: oklch(0.23 0.011 262); --pf-surface-2: oklch(0.274 0.006 286.033); --pf-border: oklch(1 0 0 / 12%);
7
+ --pf-text: oklch(0.985 0 0); --pf-text-strong: oklch(1 0 0); --pf-text-2: oklch(0.92 0.004 286.32);
8
+ --pf-muted: oklch(0.705 0.015 286.067); --pf-muted-2: oklch(0.80 0.01 286); --pf-status: oklch(0.705 0.015 286.067); --pf-hint: oklch(0.552 0.016 285.938);
9
+ --pf-accent: #3f7bf0; --pf-accent-soft: #26314a; --pf-on-accent: #fff; --pf-input-bg: oklch(0.165 0.009 262); --pf-err: oklch(0.704 0.191 22.216);
10
10
  --pf-mono: ui-monospace, "SF Mono", SFMono-Regular, "JetBrains Mono", "Cascadia Code", Menlo, Consolas, monospace;
11
11
  }
12
12
  :root[data-theme="light"] {
13
13
  color-scheme: light;
14
- --pf-bg: #eef1f5; --pf-surface: #ffffff; --pf-surface-2: #f4f6f9; --pf-border: #d4dae2;
15
- --pf-text: #2b333d; --pf-text-strong: #1a2129; --pf-text-2: #3a434e;
16
- --pf-muted: #6b7480; --pf-muted-2: #59636f; --pf-status: #6b7480; --pf-hint: #8a93a0;
17
- --pf-accent: #1f5bd6; --pf-accent-soft: #e6edfc; --pf-on-accent: #fff; --pf-input-bg: #ffffff; --pf-err: #d8453d;
14
+ --pf-bg: oklch(1 0 0); --pf-surface: oklch(1 0 0); --pf-surface-2: oklch(0.967 0.001 286.375); --pf-border: oklch(0.92 0.004 286.32);
15
+ --pf-text: oklch(0.141 0.005 285.823); --pf-text-strong: oklch(0.10 0.005 285.823); --pf-text-2: oklch(0.21 0.006 285.885);
16
+ --pf-muted: oklch(0.552 0.016 285.938); --pf-muted-2: oklch(0.44 0.015 285.9); --pf-status: oklch(0.552 0.016 285.938); --pf-hint: oklch(0.705 0.015 286.067);
17
+ --pf-accent: #1f5bd6; --pf-accent-soft: #e6edfc; --pf-on-accent: #fff; --pf-input-bg: #ffffff; --pf-err: oklch(0.577 0.245 27.325);
18
18
  }