@liquidcars/atlas-geometry-processes 0.1.1 → 0.3.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 (3) hide show
  1. package/README.md +30 -12
  2. package/index.js +144 -107
  3. package/package.json +8 -4
package/README.md CHANGED
@@ -37,6 +37,10 @@ not depend on Three.js.
37
37
  | process.annotation | Note attached to a symbol |
38
38
  | process.control-transfer | Control-flow transfer |
39
39
  | process.condition | Condition/rule gate |
40
+ | process.rocket | Project / startup rocket |
41
+ | process.laurel-wreath | Epic / laurel wreath |
42
+ | process.rabbit | Sprint / running rabbit |
43
+ | process.wrench | Task / open-ended wrench |
40
44
 
41
45
  The symbols are intentionally process-oriented rather than generic primitives:
42
46
  they preserve the visual vocabulary of flowcharts while remaining volumetric,
@@ -61,7 +65,6 @@ stable and backwards compatible.
61
65
  geometry: process.activity
62
66
  geometryOptions:
63
67
  variant: task
64
- icon: "✓"
65
68
 
66
69
  - id: order-valid
67
70
  name: Order valid?
@@ -73,7 +76,7 @@ stable and backwards compatible.
73
76
  name: Rejected
74
77
  geometry: process.document
75
78
  geometryOptions:
76
- icon: "!"
79
+ copies: 2
77
80
 
78
81
  relations:
79
82
  - from: receive-order
@@ -94,8 +97,7 @@ semantics:
94
97
  {
95
98
  "geometry": "process.display",
96
99
  "geometryOptions": {
97
- "screen": "active",
98
- "icon": "UI"
100
+ "screen": "active"
99
101
  },
100
102
  "geometryPalette": {
101
103
  "body": "#263746",
@@ -104,17 +106,18 @@ semantics:
104
106
  }
105
107
  ~~~
106
108
 
107
- Icons and images are optional. A symbol stays clean when no marker is supplied.
108
- Images accept browser-loadable URLs or data URIs; external hosts must permit
109
- cross-origin loading when required by the browser.
109
+ Images are optional on the few symbols where a real visual asset is useful.
110
+ The pack deliberately avoids text-based icon fields because entity labels are
111
+ the semantic caption and front-face text competes with them. Images accept
112
+ browser-loadable URLs or data URIs; external hosts must permit cross-origin
113
+ loading when required by the browser.
110
114
 
111
115
  ## Design notes
112
116
 
113
- The first release follows common flowchart semantics visible in standard
114
- process-symbol libraries. Some symbols, such as a document's curved lower edge
115
- or a manual-input parallelogram, are represented as stylized 3D compounds so
116
- they remain legible from the interactive camera instead of pretending to be
117
- flat 2D SVG glyphs.
117
+ The symbols follow common flowchart semantics while remaining volumetric. The
118
+ terminator is a single rounded pill, documents use a light paper face with a
119
+ wave at the lower edge, connectors face the camera as compact discs, and notes
120
+ use the familiar folded-corner Post-it silhouette.
118
121
 
119
122
  The pack uses namespace process and registers itself on import:
120
123
 
@@ -123,3 +126,18 @@ import processGeometryPack from "@liquidcars/atlas-geometry-processes";
123
126
 
124
127
  console.log(processGeometryPack.geometries.map(geometry => geometry.id));
125
128
  ~~~
129
+
130
+ ## Work management (0.3.0)
131
+
132
+ The four work-management symbols appear under **Processes · Work management**.
133
+ Their ids describe reusable shapes, independently of the host application’s entity types.
134
+ The suggested mapping is project → `process.rocket`, epic → `process.laurel-wreath`,
135
+ sprint → `process.rabbit`, task → `process.wrench`. Existing geometry ids are unchanged.
136
+
137
+ The silhouettes use solid SVG extrusions with real thickness and local palette colors.
138
+ Atlas derives 2D diagrams and thumbnails from the same geometry used in 3D; no emoji,
139
+ font, remote image or Three.js dependency is required by the pack. Atlas >= 0.1.40
140
+ is required for SVG extrusion support. Colors use `workPrimary`, `workPaper`,
141
+ `workWindow`, `workGold`, `workGreen`, `workMetal` and `workFlame`.
142
+
143
+ Run `npm test` to check the pack contract and backwards-compatible symbol ids.
package/index.js CHANGED
@@ -2,16 +2,14 @@ import { registerGeometryPack } from "@liquidcars/atlas";
2
2
 
3
3
  const clamp = (value, minimum, maximum) => Math.min(maximum, Math.max(minimum, Number(value) || minimum));
4
4
 
5
- const frontMarker = (parameters, color = "accent", position = [0, 0, .54], size = [.3, .24, 1]) => {
6
- if (!parameters?.icon && !parameters?.image) return [];
5
+ const frontImage = (parameters, position = [0, 0, .54], size = [.3, .24, 1]) => {
6
+ if (!parameters?.image) return [];
7
7
  return [{
8
8
  shape: "plane",
9
9
  size,
10
10
  position,
11
- color: parameters.image ? "#ffffff" : color,
12
- icon: parameters.icon,
11
+ color: "#ffffff",
13
12
  image: parameters.image,
14
- iconColor: "#ffffff",
15
13
  edges: false,
16
14
  doubleSided: true
17
15
  }];
@@ -26,6 +24,17 @@ const frontLine = (position, size, color = "accent") => ({
26
24
  metalness: .12
27
25
  });
28
26
 
27
+ const frontWave = (y = -.29, z = .175, color = "body") => Array.from({ length: 15 }, (_, index) => {
28
+ const progress = index / 14;
29
+ return {
30
+ shape: "sphere",
31
+ size: [.09, .026, .018],
32
+ position: [-.42 + progress * .84, y + Math.sin(progress * Math.PI * 2) * .045, z],
33
+ color,
34
+ edges: false
35
+ };
36
+ });
37
+
29
38
  const processPalette = {
30
39
  body: "#496879",
31
40
  edge: "#8fd3ee",
@@ -33,7 +42,10 @@ const processPalette = {
33
42
  decision: "#d19a54",
34
43
  data: "#5e9f9a",
35
44
  input: "#6c8fb7",
36
- paper: "#8ca9b7",
45
+ paper: "#f4f1e8",
46
+ note: "#efcf62",
47
+ fold: "#fff0ae",
48
+ screen: "#173541",
37
49
  storage: "#597887",
38
50
  accent: "#72dbc9",
39
51
  positive: "#8bd8a8",
@@ -44,7 +56,7 @@ const processPalette = {
44
56
  export const processGeometryPack = {
45
57
  namespace: "process",
46
58
  name: "Process Symbols",
47
- version: "0.1.1",
59
+ version: "0.3.0",
48
60
  category: "Processes",
49
61
  palette: processPalette,
50
62
  geometries: [
@@ -55,19 +67,14 @@ export const processGeometryPack = {
55
67
  category: "Processes · Essentials",
56
68
  canonicalSize: [3, 1.35, 1.5],
57
69
  parameters: {
58
- kind: { type: "select", label: "Kind", options: ["start", "end"], default: "start" },
59
- icon: { type: "icon", label: "Front icon", default: "" },
60
- image: { type: "image", label: "Front image URL", default: "" }
70
+ kind: { type: "select", label: "Kind", options: ["start", "end"], default: "start" }
61
71
  },
62
72
  anchors: { input: [-1, 0, 0], output: [1, 0, 0] },
63
73
  create({ parameters }) {
64
74
  const color = parameters.kind === "end" ? "negative" : "positive";
65
75
  return {
66
76
  parts: [
67
- { shape: "box", size: [.72, .8, .82], color, radius: .16, edgeColor: "edge" },
68
- { shape: "sphere", size: [.62, .8, .82], position: [-.35, 0, 0], color, edges: false },
69
- { shape: "sphere", size: [.62, .8, .82], position: [.35, 0, 0], color, edges: false },
70
- ...frontMarker(parameters, "ink", [0, 0, .45], [.34, .26, 1])
77
+ { shape: "box", size: [1, .72, .7], color, radius: .36, segments: 10, edgeColor: "edge" }
71
78
  ]
72
79
  };
73
80
  }
@@ -81,7 +88,6 @@ export const processGeometryPack = {
81
88
  parameters: {
82
89
  variant: { type: "select", label: "Variant", options: ["task", "subprocess", "call"], default: "task" },
83
90
  radius: { type: "number", label: "Corner radius", min: 0, max: .2, step: .01, default: .05 },
84
- icon: { type: "icon", label: "Front icon", default: "" },
85
91
  image: { type: "image", label: "Front image URL", default: "" }
86
92
  },
87
93
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], detail: [0, 0, 1] },
@@ -96,7 +102,7 @@ export const processGeometryPack = {
96
102
  );
97
103
  }
98
104
  if (parameters.variant === "call") parts.push(frontLine([0, .39, .42], [.72, .035, .035], "accent"));
99
- return { parts: [...parts, ...frontMarker(parameters)] };
105
+ return { parts: [...parts, ...frontImage(parameters)] };
100
106
  }
101
107
  },
102
108
  {
@@ -106,16 +112,14 @@ export const processGeometryPack = {
106
112
  category: "Processes · Essentials",
107
113
  canonicalSize: [2.25, 1.8, 2.25],
108
114
  parameters: {
109
- outcome: { type: "select", label: "Expected outcome", options: ["neutral", "positive", "negative"], default: "neutral" },
110
- icon: { type: "icon", label: "Front icon", default: "" }
115
+ outcome: { type: "select", label: "Expected outcome", options: ["neutral", "positive", "negative"], default: "neutral" }
111
116
  },
112
117
  anchors: { input: [-1, 0, 0], yes: [1, 0, 0], no: [0, -1, 0], detail: [0, 0, 1] },
113
118
  create({ parameters }) {
114
119
  const color = parameters.outcome === "positive" ? "positive" : parameters.outcome === "negative" ? "negative" : "decision";
115
120
  return {
116
121
  parts: [
117
- { shape: "box", size: [.88, .22, .88], rotation: [0, 0, Math.PI / 4], color, edgeColor: "edge", radius: .04 },
118
- ...frontMarker(parameters, "ink", [0, 0, .15], [.25, .2, 1])
122
+ { shape: "box", size: [.88, .22, .88], rotation: [0, 0, Math.PI / 4], color, edgeColor: "edge", radius: .04 }
119
123
  ]
120
124
  };
121
125
  }
@@ -128,7 +132,6 @@ export const processGeometryPack = {
128
132
  canonicalSize: [2.7, 1.55, 1.7],
129
133
  parameters: {
130
134
  direction: { type: "select", label: "Direction", options: ["input", "output", "both"], default: "input" },
131
- icon: { type: "icon", label: "Front icon", default: "" },
132
135
  image: { type: "image", label: "Front image URL", default: "" }
133
136
  },
134
137
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], detail: [0, 0, 1] },
@@ -137,7 +140,7 @@ export const processGeometryPack = {
137
140
  return {
138
141
  parts: [
139
142
  { shape: "box", size: [1, .58, .78], rotation: [0, 0, -.16], color, edgeColor: "edge", radius: .03 },
140
- ...frontMarker(parameters, "ink", [0, 0, .43], [.3, .23, 1])
143
+ ...frontImage(parameters, [0, 0, .43], [.3, .23, 1])
141
144
  ]
142
145
  };
143
146
  }
@@ -148,15 +151,12 @@ export const processGeometryPack = {
148
151
  description: "A manually performed operation.",
149
152
  category: "Processes · Advanced",
150
153
  canonicalSize: [2.75, 1.6, 1.7],
151
- parameters: {
152
- icon: { type: "icon", label: "Front icon", default: "" }
153
- },
154
+ parameters: {},
154
155
  anchors: { input: [-1, 0, 0], output: [1, 0, 0] },
155
156
  create({ parameters }) {
156
157
  return {
157
158
  parts: [
158
- { shape: "frustum-pyramid", size: [1, .64, .84], color: "input", edgeColor: "edge" },
159
- ...frontMarker(parameters, "ink", [0, 0, .44], [.28, .22, 1])
159
+ { shape: "frustum-pyramid", size: [1, .64, .84], color: "input", edgeColor: "edge" }
160
160
  ]
161
161
  };
162
162
  }
@@ -166,11 +166,9 @@ export const processGeometryPack = {
166
166
  name: "Document",
167
167
  description: "A document or generated record.",
168
168
  category: "Processes · Essentials",
169
- canonicalSize: [2.65, 2, 1.65],
169
+ canonicalSize: [2.65, 2, .72],
170
170
  parameters: {
171
- copies: { type: "number", label: "Copies", min: 1, max: 3, step: 1, default: 1 },
172
- icon: { type: "icon", label: "Front icon", default: "" },
173
- image: { type: "image", label: "Front image URL", default: "" }
171
+ copies: { type: "number", label: "Copies", min: 1, max: 3, step: 1, default: 1 }
174
172
  },
175
173
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], archive: [0, -1, 0] },
176
174
  create({ parameters }) {
@@ -179,18 +177,14 @@ export const processGeometryPack = {
179
177
  for (let index = copies - 1; index >= 0; index--) {
180
178
  parts.push({
181
179
  shape: "box",
182
- size: [1, .72, .78],
183
- position: [index * .06, index * .04, index * -.05],
180
+ size: [1, .76, .34],
181
+ position: [index * .055, index * .04, index * -.08],
184
182
  color: index === 0 ? "paper" : "body",
185
183
  edgeColor: "edge",
186
184
  radius: .04
187
185
  });
188
186
  }
189
- parts.push(
190
- frontLine([-.28, -.22, .43], [.42, .035, .035], "ink"),
191
- frontLine([.22, -.22, .43], [.22, .035, .035], "ink"),
192
- ...frontMarker(parameters, "ink", [0, .12, .44], [.25, .2, 1])
193
- );
187
+ parts.push(...frontWave(-.29, .185, "body"));
194
188
  return { parts };
195
189
  }
196
190
  },
@@ -201,7 +195,6 @@ export const processGeometryPack = {
201
195
  category: "Processes · Advanced",
202
196
  canonicalSize: [2.9, 1.8, 1.8],
203
197
  parameters: {
204
- icon: { type: "icon", label: "Front icon", default: "" },
205
198
  image: { type: "image", label: "Front image URL", default: "" }
206
199
  },
207
200
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], call: [0, 0, 1] },
@@ -211,7 +204,7 @@ export const processGeometryPack = {
211
204
  { shape: "box", size: [1, .76, .8], color: "process", edgeColor: "edge", radius: .07 },
212
205
  frontLine([-.42, 0, .43], [.035, .68, .035], "accent"),
213
206
  frontLine([.42, 0, .43], [.035, .68, .035], "accent"),
214
- ...frontMarker(parameters)
207
+ ...frontImage(parameters)
215
208
  ]
216
209
  };
217
210
  }
@@ -223,8 +216,7 @@ export const processGeometryPack = {
223
216
  category: "Processes · Essentials",
224
217
  canonicalSize: [2.45, 1.9, 2.1],
225
218
  parameters: {
226
- tiers: { type: "number", label: "Tiers", min: 1, max: 4, step: 1, default: 2 },
227
- icon: { type: "icon", label: "Front icon", default: "" }
219
+ tiers: { type: "number", label: "Tiers", min: 1, max: 4, step: 1, default: 2 }
228
220
  },
229
221
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], query: [0, 0, 1] },
230
222
  create({ parameters }) {
@@ -239,7 +231,7 @@ export const processGeometryPack = {
239
231
  edgeColor: "accent"
240
232
  });
241
233
  }
242
- return { parts: [...parts, ...frontMarker(parameters, "accent", [0, 0, .46], [.27, .22, 1])] };
234
+ return { parts };
243
235
  }
244
236
  },
245
237
  {
@@ -248,22 +240,14 @@ export const processGeometryPack = {
248
240
  description: "A store managed inside the process boundary.",
249
241
  category: "Processes · Advanced",
250
242
  canonicalSize: [2.55, 2, 1.8],
251
- parameters: {
252
- partitions: { type: "number", label: "Partitions", min: 1, max: 4, step: 1, default: 2 },
253
- icon: { type: "icon", label: "Front icon", default: "" }
254
- },
243
+ parameters: {},
255
244
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], access: [0, 0, 1] },
256
- create({ parameters }) {
257
- const partitions = Math.round(clamp(parameters.partitions, 1, 4));
258
- const parts = [
245
+ create() {
246
+ return { parts: [
259
247
  { shape: "box", size: [1, .78, .8], color: "storage", edgeColor: "edge", radius: .03 },
260
- frontLine([0, 0, .43], [.035, .7, .035], "accent")
261
- ];
262
- for (let index = 1; index < partitions; index++) {
263
- const x = -.36 + index * (.72 / partitions);
264
- parts.push(frontLine([x, 0, .44], [.022, .66, .035], "accent"));
265
- }
266
- return { parts: [...parts, ...frontMarker(parameters)] };
248
+ frontLine([-.36, 0, .43], [.025, .66, .035], "accent"),
249
+ frontLine([0, .28, .43], [.72, .025, .035], "accent")
250
+ ] };
267
251
  }
268
252
  },
269
253
  {
@@ -273,8 +257,7 @@ export const processGeometryPack = {
273
257
  category: "Processes · Advanced",
274
258
  canonicalSize: [2.6, 1.9, 2.15],
275
259
  parameters: {
276
- medium: { type: "select", label: "Medium", options: ["disk", "drum"], default: "disk" },
277
- icon: { type: "icon", label: "Front icon", default: "" }
260
+ medium: { type: "select", label: "Medium", options: ["disk", "drum"], default: "disk" }
278
261
  },
279
262
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], read: [0, 0, 1] },
280
263
  create({ parameters }) {
@@ -282,8 +265,7 @@ export const processGeometryPack = {
282
265
  return {
283
266
  parts: [
284
267
  { shape: "cylinder", size: [.86, 1.02, .86], rotation: [0, 0, Math.PI / 2], color, edgeColor: "edge" },
285
- { shape: "cylinder", size: [.48, 1.04, .48], rotation: [0, 0, Math.PI / 2], color: "accent", edges: false },
286
- ...frontMarker(parameters, "ink", [0, 0, .5], [.27, .2, 1])
268
+ { shape: "cylinder", size: [.48, 1.04, .48], rotation: [0, 0, Math.PI / 2], color: "accent", edges: false }
287
269
  ]
288
270
  };
289
271
  }
@@ -295,7 +277,6 @@ export const processGeometryPack = {
295
277
  category: "Processes · Advanced",
296
278
  canonicalSize: [2.75, 1.65, 1.75],
297
279
  parameters: {
298
- icon: { type: "icon", label: "Front icon", default: "" },
299
280
  image: { type: "image", label: "Front image URL", default: "" }
300
281
  },
301
282
  anchors: { input: [-1, .15, 0], output: [1, 0, 0], operator: [0, 1, 0] },
@@ -303,7 +284,7 @@ export const processGeometryPack = {
303
284
  return {
304
285
  parts: [
305
286
  { shape: "box", size: [1, .62, .8], rotation: [0, 0, .16], color: "input", edgeColor: "edge", radius: .03 },
306
- ...frontMarker(parameters, "ink", [0, 0, .43], [.3, .22, 1])
287
+ ...frontImage(parameters, [0, 0, .43], [.3, .22, 1])
307
288
  ]
308
289
  };
309
290
  }
@@ -314,15 +295,12 @@ export const processGeometryPack = {
314
295
  description: "Preparation, setup or initialization step.",
315
296
  category: "Processes · Advanced",
316
297
  canonicalSize: [2.7, 1.8, 1.8],
317
- parameters: {
318
- icon: { type: "icon", label: "Front icon", default: "" }
319
- },
298
+ parameters: {},
320
299
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], setup: [0, 1, 0] },
321
300
  create({ parameters }) {
322
301
  return {
323
302
  parts: [
324
- { shape: "prism", size: [1, .74, .82], color: "process", edgeColor: "edge" },
325
- ...frontMarker(parameters)
303
+ { shape: "prism", size: [1, .74, .82], color: "process", edgeColor: "edge" }
326
304
  ]
327
305
  };
328
306
  }
@@ -334,8 +312,7 @@ export const processGeometryPack = {
334
312
  category: "Processes · Advanced",
335
313
  canonicalSize: [2.8, 1.9, 1.8],
336
314
  parameters: {
337
- lanes: { type: "number", label: "Lanes", min: 2, max: 4, step: 1, default: 2 },
338
- icon: { type: "icon", label: "Front icon", default: "" }
315
+ lanes: { type: "number", label: "Lanes", min: 2, max: 4, step: 1, default: 2 }
339
316
  },
340
317
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], lane: [0, 0, 1] },
341
318
  create({ parameters }) {
@@ -347,7 +324,7 @@ export const processGeometryPack = {
347
324
  const y = -.27 + index * (.54 / Math.max(1, lanes - 1));
348
325
  parts.push(frontLine([0, y, .43], [.66, .025, .035], index % 2 ? "accent" : "edge"));
349
326
  }
350
- return { parts: [...parts, ...frontMarker(parameters)] };
327
+ return { parts };
351
328
  }
352
329
  },
353
330
  {
@@ -357,17 +334,17 @@ export const processGeometryPack = {
357
334
  category: "Processes · Advanced",
358
335
  canonicalSize: [2.7, 1.9, 1.8],
359
336
  parameters: {
360
- limit: { type: "number", label: "Limit", min: 1, max: 99, step: 1, default: 3 },
361
- icon: { type: "icon", label: "Front icon", default: "" }
337
+ limit: { type: "number", label: "Limit", min: 1, max: 99, step: 1, default: 3 }
362
338
  },
363
339
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], loop: [0, 0, 1] },
364
340
  create({ parameters }) {
365
341
  const limit = Math.round(clamp(parameters.limit, 1, 99));
342
+ const limitWidth = .2 + Math.log10(limit + 1) / 2 * .5;
366
343
  return {
367
344
  parts: [
368
345
  { shape: "pyramid-square", size: [1, .72, .82], color: "decision", edgeColor: "edge" },
369
346
  frontLine([0, -.17, .45], [.34, .035, .035], "ink"),
370
- ...frontMarker({ ...parameters, icon: parameters.icon || String(limit) }, "ink", [0, .12, .45], [.28, .2, 1])
347
+ frontLine([0, .12, .45], [limitWidth, .045, .035], "ink")
371
348
  ]
372
349
  };
373
350
  }
@@ -380,17 +357,17 @@ export const processGeometryPack = {
380
357
  canonicalSize: [2.9, 1.8, 1.8],
381
358
  parameters: {
382
359
  screen: { type: "select", label: "Screen state", options: ["idle", "active", "warning"], default: "active" },
383
- image: { type: "image", label: "Screen image URL", default: "" },
384
- icon: { type: "icon", label: "Screen icon", default: "" }
360
+ image: { type: "image", label: "Screen image URL", default: "" }
385
361
  },
386
362
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], user: [0, 0, 1] },
387
363
  create({ parameters }) {
388
- const color = parameters.screen === "warning" ? "negative" : parameters.screen === "active" ? "accent" : "body";
364
+ const color = parameters.screen === "warning" ? "negative" : parameters.screen === "active" ? "accent" : "screen";
389
365
  return {
390
366
  parts: [
391
367
  { shape: "box", size: [.9, .68, .76], color: "body", edgeColor: "edge", radius: .12 },
392
- { shape: "box", size: [.72, .5, .05], position: [0, .02, .41], color: "screen", edgeColor: color, radius: .03 },
393
- ...frontMarker(parameters, color, [0, .02, .45], [.25, .18, 1])
368
+ { shape: "box", size: [.72, .5, .05], position: [0, .02, .41], color, edgeColor: color, radius: .03 },
369
+ { shape: "sphere", size: [.055, .055, .035], position: [.36, -.29, .43], color, edges: false },
370
+ ...frontImage(parameters, [0, .02, .45], [.25, .18, 1])
394
371
  ]
395
372
  };
396
373
  }
@@ -400,19 +377,16 @@ export const processGeometryPack = {
400
377
  name: "Connector",
401
378
  description: "An in-page connector or continuation point.",
402
379
  category: "Processes · Essentials",
403
- canonicalSize: [1.55, 1.55, 1.55],
380
+ canonicalSize: [1.55, 1.55, .55],
404
381
  parameters: {
405
- kind: { type: "select", label: "Kind", options: ["sequence", "junction"], default: "sequence" },
406
- icon: { type: "icon", label: "Connector icon", default: "" }
382
+ kind: { type: "select", label: "Kind", options: ["sequence", "junction"], default: "sequence" }
407
383
  },
408
384
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], continuation: [0, 0, 1] },
409
385
  create({ parameters }) {
410
386
  const color = parameters.kind === "junction" ? "decision" : "accent";
411
387
  return {
412
388
  parts: [
413
- { shape: "cylinder", size: [.72, .22, .72], rotation: [0, 0, Math.PI / 2], color, edgeColor: "edge" },
414
- { shape: "sphere", size: [.32, .32, .32], position: [0, 0, .39], color: "ink", edges: false },
415
- ...frontMarker(parameters, "ink", [0, 0, .51], [.2, .16, 1])
389
+ { shape: "cylinder", size: [.82, .22, .82], rotation: [Math.PI / 2, 0, 0], color, edgeColor: "edge" }
416
390
  ]
417
391
  };
418
392
  }
@@ -423,16 +397,12 @@ export const processGeometryPack = {
423
397
  description: "A continuation to another page or diagram.",
424
398
  category: "Processes · Advanced",
425
399
  canonicalSize: [2.2, 2.1, 1.7],
426
- parameters: {
427
- target: { type: "string", label: "Target", default: "" },
428
- icon: { type: "icon", label: "Reference icon", default: "" }
429
- },
400
+ parameters: {},
430
401
  anchors: { input: [-1, 0, 0], output: [1, 0, 0], continuation: [0, -1, 0] },
431
402
  create({ parameters }) {
432
403
  return {
433
404
  parts: [
434
- { shape: "pyramid-square", size: [1, .72, .82], rotation: [0, 0, Math.PI / 4], color: "paper", edgeColor: "edge" },
435
- ...frontMarker({ ...parameters, icon: parameters.icon || parameters.target }, "ink", [0, 0, .2], [.25, .18, 1])
405
+ { shape: "pyramid-square", size: [1, .72, .82], rotation: [0, 0, Math.PI / 4], color: "paper", edgeColor: "edge" }
436
406
  ]
437
407
  };
438
408
  }
@@ -442,18 +412,15 @@ export const processGeometryPack = {
442
412
  name: "Note",
443
413
  description: "A note linked to a process symbol.",
444
414
  category: "Processes · Essentials",
445
- canonicalSize: [2.7, 1.9, 1.6],
446
- parameters: {
447
- icon: { type: "icon", label: "Annotation icon", default: "i" },
448
- image: { type: "image", label: "Annotation image URL", default: "" }
449
- },
415
+ canonicalSize: [2.35, 2.15, .62],
416
+ parameters: {},
450
417
  anchors: { target: [-1, 0, 0], note: [1, 0, 0] },
451
418
  create({ parameters }) {
452
419
  return {
453
420
  parts: [
454
- { shape: "box", size: [.72, .58, .58], color: "paper", edgeColor: "edge", radius: .04 },
455
- frontLine([.58, 0, 0], [.62, .035, .035], "accent"),
456
- ...frontMarker(parameters, "ink", [0, 0, .32], [.22, .16, 1])
421
+ { shape: "box", size: [.82, .82, .32], color: "note", edgeColor: "edge", radius: .025 },
422
+ { shape: "pyramid-triangle", size: [.22, .035, .22], position: [.31, .31, .18], rotation: [Math.PI / 2, 0, Math.PI / 4], color: "fold", edges: false },
423
+ frontLine([.2, .2, .185], [.24, .025, .018], "body")
457
424
  ]
458
425
  };
459
426
  }
@@ -465,8 +432,7 @@ export const processGeometryPack = {
465
432
  category: "Processes · Advanced",
466
433
  canonicalSize: [2.5, 1.55, 1.55],
467
434
  parameters: {
468
- direction: { type: "select", label: "Direction", options: ["forward", "back"], default: "forward" },
469
- icon: { type: "icon", label: "Transfer icon", default: "" }
435
+ direction: { type: "select", label: "Direction", options: ["forward", "back"], default: "forward" }
470
436
  },
471
437
  anchors: { input: [-1, 0, 0], output: [1, 0, 0] },
472
438
  create({ parameters }) {
@@ -474,8 +440,7 @@ export const processGeometryPack = {
474
440
  return {
475
441
  parts: [
476
442
  { shape: "box", size: [.62, .16, .16], position: [-.17, 0, 0], color: "accent", edges: false },
477
- { shape: "cone", size: [.42, .42, .42], position: [.28, 0, 0], rotation: [0, 0, rotation], color: "accent", edgeColor: "edge" },
478
- ...frontMarker(parameters, "ink", [0, 0, .24], [.2, .16, 1])
443
+ { shape: "cone", size: [.42, .42, .42], position: [.28, 0, 0], rotation: [0, 0, rotation], color: "accent", edgeColor: "edge" }
479
444
  ]
480
445
  };
481
446
  }
@@ -487,16 +452,14 @@ export const processGeometryPack = {
487
452
  category: "Processes · Advanced",
488
453
  canonicalSize: [2.25, 1.8, 2.1],
489
454
  parameters: {
490
- state: { type: "select", label: "State", options: ["true", "false", "unknown"], default: "unknown" },
491
- icon: { type: "icon", label: "Condition icon", default: "" }
455
+ state: { type: "select", label: "State", options: ["true", "false", "unknown"], default: "unknown" }
492
456
  },
493
457
  anchors: { input: [-1, 0, 0], true: [1, .35, 0], false: [1, -.35, 0] },
494
458
  create({ parameters }) {
495
459
  const color = parameters.state === "true" ? "positive" : parameters.state === "false" ? "negative" : "decision";
496
460
  return {
497
461
  parts: [
498
- { shape: "pyramid-triangle", size: [1, .68, .84], color, edgeColor: "edge" },
499
- ...frontMarker(parameters, "ink", [0, 0, .45], [.22, .18, 1])
462
+ { shape: "pyramid-triangle", size: [1, .68, .84], color, edgeColor: "edge" }
500
463
  ]
501
464
  };
502
465
  }
@@ -504,6 +467,80 @@ export const processGeometryPack = {
504
467
  ]
505
468
  };
506
469
 
470
+ // Work-management vocabulary. Every silhouette is a solid SVG extrusion, so
471
+ // Atlas uses the same outline for its 2D diagrams and its volumetric 3D view.
472
+ const workSvg = (paths, size, position = [0, 0, 0], color = "workPrimary") => ({
473
+ shape: "svg-extrude",
474
+ svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">${paths}</svg>`,
475
+ size, position, color, edges: false, bevel: .018, curveSegments: 10,
476
+ metalness: .16, roughness: .48
477
+ });
478
+ const workEye = (position, diameter, color = "workPaper") => ({
479
+ shape: "cylinder", size: [diameter, .055, diameter],
480
+ rotation: [Math.PI / 2, 0, 0], position, color, edges: false
481
+ });
482
+ const rocketOutline = '<path d="M50 3C31 16 27 35 28 57L13 72V88L35 79H65L87 88V72L72 57C73 35 69 16 50 3Z"/>';
483
+ const rocketFlame = '<path d="M24 4Q50 25 76 4Q84 55 50 97Q16 55 24 4Z"/>';
484
+ const rabbitOutline = '<path d="M14 62C6 65 2 57 6 51C9 47 14 49 18 52C24 39 37 37 49 43L59 36L55 18Q54 8 60 13L70 32L74 11Q78 3 82 10L81 34Q90 36 94 44L97 49Q99 54 92 57L81 58L75 64L91 76Q95 83 87 83L70 72L62 70L52 79L32 89Q24 91 26 84L39 75L46 65Q35 60 27 66L18 79L7 83Q0 84 4 77L14 68Z"/>';
485
+ // Opposite contour winding keeps the handle hole without discarding the body caps in Atlas.
486
+ const wrenchOutline = '<path fill-rule="evenodd" d="M63 8L57 10C45 14 38 28 44 40L8 68C0 74 -2 84 5 91C12 98 22 97 29 89L59 55C73 63 87 59 94 45L77 45L70 32L79 20L95 20C90 8 76 2 63 8ZM20 81A5 5 0 1 1 10 81A5 5 0 1 1 20 81Z"/>';
487
+ const laurelOutline = (() => {
488
+ const point = (x, y) => `${x.toFixed(2)} ${y.toFixed(2)}`;
489
+ const leaf = (x, y, tx, ty, width) => {
490
+ const dx = tx - x, dy = ty - y, length = Math.hypot(dx, dy), nx = -dy / length * width, ny = dx / length * width;
491
+ return `<path d="M${point(x,y)}C${point(x+dx*.25+nx,y+dy*.25+ny)} ${point(x+dx*.75+nx,y+dy*.75+ny)} ${point(tx,ty)}C${point(x+dx*.75-nx,y+dy*.75-ny)} ${point(x+dx*.25-nx,y+dy*.25-ny)} ${point(x,y)}Z"/>`;
492
+ };
493
+ let paths = '<path d="M49 94C16 78 9 46 34 10L37 12C16 47 23 75 51 90ZM51 94C84 78 91 46 66 10L63 12C84 47 77 75 49 90Z"/>';
494
+ for (const side of [-1, 1]) for (let i = 0; i < 7; i++) {
495
+ const angle = (90 + side * (20 + i * 22)) * Math.PI / 180;
496
+ const rx = Math.cos(angle), ry = Math.sin(angle), dx = -ry * side, dy = rx * side;
497
+ const x = 50 + rx * 34, y = 50 + ry * 34;
498
+ paths += leaf(x, y, x + rx * 13 + dx * 7, y + ry * 13 + dy * 7, 3.8);
499
+ paths += leaf(x, y, x - rx * 11 + dx * 9, y - ry * 11 + dy * 9, 3.2);
500
+ }
501
+ return paths;
502
+ })();
503
+ Object.assign(processPalette, {
504
+ workPrimary: "#7961c9", workPaper: "#fff9ef", workWindow: "#81d6ec",
505
+ workGold: "#d6a739", workGreen: "#43856b", workMetal: "#55788d", workFlame: "#efa34b"
506
+ });
507
+ processGeometryPack.geometries.push(
508
+ {
509
+ id: "rocket", name: "Project · Rocket", description: "Startup rocket: a project taking off.",
510
+ category: "Processes · Work management", canonicalSize: [1.8, 2.5, .6],
511
+ anchors: { input: [-.9, 0, 0], output: [.9, 0, 0], detail: [0, 0, .3] },
512
+ create() { return { parts: [
513
+ workSvg(rocketFlame, [.48, .65, .22], [0, -.93, -.015], "workFlame"),
514
+ workSvg(rocketOutline, [1.45, 1.85, .32], [0, .18, 0]),
515
+ workEye([0, .49, .18], .46), workEye([0, .49, .215], .30, "workWindow"),
516
+ frontLine([0, -.43, .185], [.48, .07, .05], "workPaper")
517
+ ] }; }
518
+ },
519
+ {
520
+ id: "laurel-wreath", name: "Epic · Laurel wreath", description: "A laurel wreath framing a significant achievement.",
521
+ category: "Processes · Work management", canonicalSize: [2.3, 2.3, .5],
522
+ anchors: { input: [-1.15, 0, 0], output: [1.15, 0, 0], detail: [0, 0, .25] },
523
+ create() { return { parts: [workSvg(laurelOutline, [2, 2.05, .3], [0, 0, 0], "workGold")] }; }
524
+ },
525
+ {
526
+ id: "rabbit", name: "Sprint · Running rabbit", description: "A running hare, with long ears and extended legs, for a short delivery iteration.",
527
+ category: "Processes · Work management", canonicalSize: [2.7, 2.15, .6],
528
+ anchors: { input: [-1.35, 0, 0], output: [1.35, 0, 0], detail: [0, 0, .3] },
529
+ create() { return { parts: [
530
+ workSvg(rabbitOutline, [2.15, 1.95, .3], [.1, .04, 0], "workGreen"),
531
+ workEye([.9, .20, .185], .095),
532
+ { ...frontLine([-.99, -.08, 0], [.54, .075, .12], "workGreen"), radius: .035 },
533
+ { ...frontLine([-1.03, -.35, 0], [.4, .065, .12], "workGreen"), radius: .03 }
534
+ ] }; }
535
+ },
536
+ {
537
+ id: "wrench", name: "Task · Wrench", description: "An open-ended wrench with a pierced handle for concrete work on an asset.",
538
+ category: "Processes · Work management", canonicalSize: [2.3, 2.3, .55],
539
+ anchors: { input: [-1.15, 0, 0], output: [1.15, 0, 0], detail: [0, 0, .275] },
540
+ create() { return { parts: [workSvg(wrenchOutline, [2.05, 2.05, .32], [0, 0, 0], "workMetal")] }; }
541
+ }
542
+ );
543
+
507
544
  registerGeometryPack(processGeometryPack);
508
545
 
509
546
  export default processGeometryPack;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liquidcars/atlas-geometry-processes",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Standard process and flowchart geometry pack for LiquidCars Atlas",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "sideEffects": true,
16
16
  "peerDependencies": {
17
- "@liquidcars/atlas": ">=0.1.25"
17
+ "@liquidcars/atlas": ">=0.1.40"
18
18
  },
19
19
  "keywords": [
20
20
  "liquidcars",
@@ -23,7 +23,11 @@
23
23
  "geometry-pack",
24
24
  "process",
25
25
  "flowchart",
26
- "bpmn"
26
+ "bpmn",
27
+ "work-management"
27
28
  ],
28
- "license": "MIT"
29
+ "license": "MIT",
30
+ "scripts": {
31
+ "test": "node --test test/*.test.mjs"
32
+ }
29
33
  }