@liquidcars/atlas-geometry-processes 0.1.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 +120 -0
  2. package/index.js +489 -0
  3. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # @liquidcars/atlas-geometry-processes
2
+
3
+ Independent 3D geometry pack for standard process and flowchart symbols in
4
+ @liquidcars/atlas.
5
+
6
+ ~~~js
7
+ import "@liquidcars/atlas";
8
+ import "@liquidcars/atlas-geometry-processes";
9
+ ~~~
10
+
11
+ The import registers the process.* geometry namespace. The pack is declarative
12
+ from the host's point of view: it contributes canonical sizes, typed
13
+ parameters, local palette colors, named anchors and compound parts, but does
14
+ not depend on Three.js.
15
+
16
+ ## Included symbols
17
+
18
+ | Geometry | Use |
19
+ | --- | --- |
20
+ | process.terminator | Start/end |
21
+ | process.activity | Task, subprocess or call activity |
22
+ | process.decision | Decision/gateway |
23
+ | process.data | Data input/output |
24
+ | process.manual-operation | Manual operation |
25
+ | process.document | Document or record |
26
+ | process.predefined-process | Reusable named routine |
27
+ | process.stored-data | Persistent data store |
28
+ | process.internal-storage | Internal storage |
29
+ | process.direct-data | Disk/drum-like direct data |
30
+ | process.manual-input | Manual data entry |
31
+ | process.preparation | Preparation/setup |
32
+ | process.parallel-mode | Parallel execution |
33
+ | process.loop-limit | Bounded loop |
34
+ | process.display | User-facing display |
35
+ | process.connector | In-page sequence/junction |
36
+ | process.off-page-reference | Continuation on another page |
37
+ | process.annotation | Note attached to a symbol |
38
+ | process.control-transfer | Control-flow transfer |
39
+ | process.condition | Condition/rule gate |
40
+
41
+ The symbols are intentionally process-oriented rather than generic primitives:
42
+ they preserve the visual vocabulary of flowcharts while remaining volumetric,
43
+ selectable and compatible with Atlas relations.
44
+
45
+ ## Example
46
+
47
+ ~~~yaml
48
+ - id: receive-order
49
+ name: Receive order
50
+ geometry: process.terminator
51
+ geometryOptions:
52
+ kind: start
53
+
54
+ - id: validate-order
55
+ name: Validate order
56
+ geometry: process.activity
57
+ geometryOptions:
58
+ variant: task
59
+ icon: "✓"
60
+
61
+ - id: order-valid
62
+ name: Order valid?
63
+ geometry: process.decision
64
+ geometryOptions:
65
+ outcome: neutral
66
+
67
+ - id: rejected
68
+ name: Rejected
69
+ geometry: process.document
70
+ geometryOptions:
71
+ icon: "!"
72
+
73
+ relations:
74
+ - from: receive-order
75
+ to: validate-order
76
+ label: begins
77
+ - from: validate-order
78
+ to: order-valid
79
+ label: checks
80
+ - from: order-valid
81
+ to: rejected
82
+ label: "no"
83
+ ~~~
84
+
85
+ A local palette can override the default colors without changing the model
86
+ semantics:
87
+
88
+ ~~~json
89
+ {
90
+ "geometry": "process.display",
91
+ "geometryOptions": {
92
+ "screen": "active",
93
+ "icon": "UI"
94
+ },
95
+ "geometryPalette": {
96
+ "body": "#263746",
97
+ "accent": "#f4d35e"
98
+ }
99
+ }
100
+ ~~~
101
+
102
+ Icons and images are optional. A symbol stays clean when no marker is supplied.
103
+ Images accept browser-loadable URLs or data URIs; external hosts must permit
104
+ cross-origin loading when required by the browser.
105
+
106
+ ## Design notes
107
+
108
+ The first release follows common flowchart semantics visible in standard
109
+ process-symbol libraries. Some symbols, such as a document's curved lower edge
110
+ or a manual-input parallelogram, are represented as stylized 3D compounds so
111
+ they remain legible from the interactive camera instead of pretending to be
112
+ flat 2D SVG glyphs.
113
+
114
+ The pack uses namespace process and registers itself on import:
115
+
116
+ ~~~js
117
+ import processGeometryPack from "@liquidcars/atlas-geometry-processes";
118
+
119
+ console.log(processGeometryPack.geometries.map(geometry => geometry.id));
120
+ ~~~
package/index.js ADDED
@@ -0,0 +1,489 @@
1
+ import { registerGeometryPack } from "@liquidcars/atlas";
2
+
3
+ const clamp = (value, minimum, maximum) => Math.min(maximum, Math.max(minimum, Number(value) || minimum));
4
+
5
+ const frontMarker = (parameters, color = "accent", position = [0, 0, .54], size = [.3, .24, 1]) => {
6
+ if (!parameters?.icon && !parameters?.image) return [];
7
+ return [{
8
+ shape: "plane",
9
+ size,
10
+ position,
11
+ color: parameters.image ? "#ffffff" : color,
12
+ icon: parameters.icon,
13
+ image: parameters.image,
14
+ iconColor: "#ffffff",
15
+ edges: false,
16
+ doubleSided: true
17
+ }];
18
+ };
19
+
20
+ const frontLine = (position, size, color = "accent") => ({
21
+ shape: "box",
22
+ size,
23
+ position,
24
+ color,
25
+ edges: false,
26
+ metalness: .12
27
+ });
28
+
29
+ const processPalette = {
30
+ body: "#496879",
31
+ edge: "#8fd3ee",
32
+ process: "#4d7d91",
33
+ decision: "#d19a54",
34
+ data: "#5e9f9a",
35
+ input: "#6c8fb7",
36
+ paper: "#8ca9b7",
37
+ storage: "#597887",
38
+ accent: "#72dbc9",
39
+ positive: "#8bd8a8",
40
+ negative: "#ed8f98",
41
+ ink: "#dceaf0"
42
+ };
43
+
44
+ export const processGeometryPack = {
45
+ namespace: "process",
46
+ name: "Process Symbols",
47
+ version: "0.1.0",
48
+ category: "Processes",
49
+ palette: processPalette,
50
+ geometries: [
51
+ {
52
+ id: "terminator",
53
+ name: "Terminator",
54
+ description: "Start or end of a process.",
55
+ canonicalSize: [3, 1.35, 1.5],
56
+ parameters: {
57
+ kind: { type: "select", label: "Kind", options: ["start", "end"], default: "start" },
58
+ icon: { type: "icon", label: "Front icon", default: "" },
59
+ image: { type: "image", label: "Front image URL", default: "" }
60
+ },
61
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0] },
62
+ create({ parameters }) {
63
+ const color = parameters.kind === "end" ? "negative" : "positive";
64
+ return {
65
+ parts: [
66
+ { shape: "box", size: [.72, .8, .82], color, radius: .16, edgeColor: "edge" },
67
+ { shape: "sphere", size: [.62, .8, .82], position: [-.35, 0, 0], color, edges: false },
68
+ { shape: "sphere", size: [.62, .8, .82], position: [.35, 0, 0], color, edges: false },
69
+ ...frontMarker(parameters, "ink", [0, 0, .45], [.34, .26, 1])
70
+ ]
71
+ };
72
+ }
73
+ },
74
+ {
75
+ id: "activity",
76
+ name: "Process",
77
+ description: "A normal process activity or task.",
78
+ canonicalSize: [2.8, 1.8, 1.8],
79
+ parameters: {
80
+ variant: { type: "select", label: "Variant", options: ["task", "subprocess", "call"], default: "task" },
81
+ radius: { type: "number", label: "Corner radius", min: 0, max: .2, step: .01, default: .05 },
82
+ icon: { type: "icon", label: "Front icon", default: "" },
83
+ image: { type: "image", label: "Front image URL", default: "" }
84
+ },
85
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], detail: [0, 0, 1] },
86
+ create({ parameters }) {
87
+ const parts = [
88
+ { shape: "box", size: [1, .76, .8], color: "process", edgeColor: "edge", radius: clamp(parameters.radius, 0, .2) }
89
+ ];
90
+ if (parameters.variant !== "task") {
91
+ parts.push(
92
+ frontLine([-.42, 0, .42], [.035, .66, .035], parameters.variant === "call" ? "accent" : "edge"),
93
+ frontLine([.42, 0, .42], [.035, .66, .035], parameters.variant === "call" ? "accent" : "edge")
94
+ );
95
+ }
96
+ if (parameters.variant === "call") parts.push(frontLine([0, .39, .42], [.72, .035, .035], "accent"));
97
+ return { parts: [...parts, ...frontMarker(parameters)] };
98
+ }
99
+ },
100
+ {
101
+ id: "decision",
102
+ name: "Decision",
103
+ description: "A branching decision or gateway.",
104
+ canonicalSize: [2.25, 1.8, 2.25],
105
+ parameters: {
106
+ outcome: { type: "select", label: "Expected outcome", options: ["neutral", "positive", "negative"], default: "neutral" },
107
+ icon: { type: "icon", label: "Front icon", default: "" }
108
+ },
109
+ anchors: { input: [-1, 0, 0], yes: [1, 0, 0], no: [0, -1, 0], detail: [0, 0, 1] },
110
+ create({ parameters }) {
111
+ const color = parameters.outcome === "positive" ? "positive" : parameters.outcome === "negative" ? "negative" : "decision";
112
+ return {
113
+ parts: [
114
+ { shape: "box", size: [.88, .22, .88], rotation: [0, 0, Math.PI / 4], color, edgeColor: "edge", radius: .04 },
115
+ ...frontMarker(parameters, "ink", [0, 0, .15], [.25, .2, 1])
116
+ ]
117
+ };
118
+ }
119
+ },
120
+ {
121
+ id: "data",
122
+ name: "Data",
123
+ description: "Data entering or leaving a process.",
124
+ canonicalSize: [2.7, 1.55, 1.7],
125
+ parameters: {
126
+ direction: { type: "select", label: "Direction", options: ["input", "output", "both"], default: "input" },
127
+ icon: { type: "icon", label: "Front icon", default: "" },
128
+ image: { type: "image", label: "Front image URL", default: "" }
129
+ },
130
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], detail: [0, 0, 1] },
131
+ create({ parameters }) {
132
+ const color = parameters.direction === "output" ? "data" : parameters.direction === "both" ? "accent" : "input";
133
+ return {
134
+ parts: [
135
+ { shape: "box", size: [1, .58, .78], rotation: [0, 0, -.16], color, edgeColor: "edge", radius: .03 },
136
+ ...frontMarker(parameters, "ink", [0, 0, .43], [.3, .23, 1])
137
+ ]
138
+ };
139
+ }
140
+ },
141
+ {
142
+ id: "manual-operation",
143
+ name: "Manual Operation",
144
+ description: "A manually performed operation.",
145
+ canonicalSize: [2.75, 1.6, 1.7],
146
+ parameters: {
147
+ icon: { type: "icon", label: "Front icon", default: "" }
148
+ },
149
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0] },
150
+ create({ parameters }) {
151
+ return {
152
+ parts: [
153
+ { shape: "frustum-pyramid", size: [1, .64, .84], color: "input", edgeColor: "edge" },
154
+ ...frontMarker(parameters, "ink", [0, 0, .44], [.28, .22, 1])
155
+ ]
156
+ };
157
+ }
158
+ },
159
+ {
160
+ id: "document",
161
+ name: "Document",
162
+ description: "A document or generated record.",
163
+ canonicalSize: [2.65, 2, 1.65],
164
+ parameters: {
165
+ copies: { type: "number", label: "Copies", min: 1, max: 3, step: 1, default: 1 },
166
+ icon: { type: "icon", label: "Front icon", default: "" },
167
+ image: { type: "image", label: "Front image URL", default: "" }
168
+ },
169
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], archive: [0, -1, 0] },
170
+ create({ parameters }) {
171
+ const copies = Math.round(clamp(parameters.copies, 1, 3));
172
+ const parts = [];
173
+ for (let index = copies - 1; index >= 0; index--) {
174
+ parts.push({
175
+ shape: "box",
176
+ size: [1, .72, .78],
177
+ position: [index * .06, index * .04, index * -.05],
178
+ color: index === 0 ? "paper" : "body",
179
+ edgeColor: "edge",
180
+ radius: .04
181
+ });
182
+ }
183
+ parts.push(
184
+ frontLine([-.28, -.22, .43], [.42, .035, .035], "ink"),
185
+ frontLine([.22, -.22, .43], [.22, .035, .035], "ink"),
186
+ ...frontMarker(parameters, "ink", [0, .12, .44], [.25, .2, 1])
187
+ );
188
+ return { parts };
189
+ }
190
+ },
191
+ {
192
+ id: "predefined-process",
193
+ name: "Predefined Process",
194
+ description: "A reusable subprocess or named routine.",
195
+ canonicalSize: [2.9, 1.8, 1.8],
196
+ parameters: {
197
+ icon: { type: "icon", label: "Front icon", default: "" },
198
+ image: { type: "image", label: "Front image URL", default: "" }
199
+ },
200
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], call: [0, 0, 1] },
201
+ create({ parameters }) {
202
+ return {
203
+ parts: [
204
+ { shape: "box", size: [1, .76, .8], color: "process", edgeColor: "edge", radius: .07 },
205
+ frontLine([-.42, 0, .43], [.035, .68, .035], "accent"),
206
+ frontLine([.42, 0, .43], [.035, .68, .035], "accent"),
207
+ ...frontMarker(parameters)
208
+ ]
209
+ };
210
+ }
211
+ },
212
+ {
213
+ id: "stored-data",
214
+ name: "Stored Data",
215
+ description: "Persisted data or a data store.",
216
+ canonicalSize: [2.45, 1.9, 2.1],
217
+ parameters: {
218
+ tiers: { type: "number", label: "Tiers", min: 1, max: 4, step: 1, default: 2 },
219
+ icon: { type: "icon", label: "Front icon", default: "" }
220
+ },
221
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], query: [0, 0, 1] },
222
+ create({ parameters }) {
223
+ const tiers = Math.round(clamp(parameters.tiers, 1, 4));
224
+ const parts = [];
225
+ for (let index = 0; index < tiers; index++) {
226
+ parts.push({
227
+ shape: "cylinder",
228
+ size: [.82, .28, .82],
229
+ position: [0, -.32 + index * (.64 / Math.max(1, tiers - 1)), 0],
230
+ color: index % 2 ? "storage" : "body",
231
+ edgeColor: "accent"
232
+ });
233
+ }
234
+ return { parts: [...parts, ...frontMarker(parameters, "accent", [0, 0, .46], [.27, .22, 1])] };
235
+ }
236
+ },
237
+ {
238
+ id: "internal-storage",
239
+ name: "Internal Storage",
240
+ description: "A store managed inside the process boundary.",
241
+ canonicalSize: [2.55, 2, 1.8],
242
+ parameters: {
243
+ partitions: { type: "number", label: "Partitions", min: 1, max: 4, step: 1, default: 2 },
244
+ icon: { type: "icon", label: "Front icon", default: "" }
245
+ },
246
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], access: [0, 0, 1] },
247
+ create({ parameters }) {
248
+ const partitions = Math.round(clamp(parameters.partitions, 1, 4));
249
+ const parts = [
250
+ { shape: "box", size: [1, .78, .8], color: "storage", edgeColor: "edge", radius: .03 },
251
+ frontLine([0, 0, .43], [.035, .7, .035], "accent")
252
+ ];
253
+ for (let index = 1; index < partitions; index++) {
254
+ const x = -.36 + index * (.72 / partitions);
255
+ parts.push(frontLine([x, 0, .44], [.022, .66, .035], "accent"));
256
+ }
257
+ return { parts: [...parts, ...frontMarker(parameters)] };
258
+ }
259
+ },
260
+ {
261
+ id: "direct-data",
262
+ name: "Direct Data",
263
+ description: "Direct-access data, typically represented by a drum or disk.",
264
+ canonicalSize: [2.6, 1.9, 2.15],
265
+ parameters: {
266
+ medium: { type: "select", label: "Medium", options: ["disk", "drum"], default: "disk" },
267
+ icon: { type: "icon", label: "Front icon", default: "" }
268
+ },
269
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], read: [0, 0, 1] },
270
+ create({ parameters }) {
271
+ const color = parameters.medium === "drum" ? "storage" : "data";
272
+ return {
273
+ parts: [
274
+ { shape: "cylinder", size: [.86, 1.02, .86], rotation: [0, 0, Math.PI / 2], color, edgeColor: "edge" },
275
+ { shape: "cylinder", size: [.48, 1.04, .48], rotation: [0, 0, Math.PI / 2], color: "accent", edges: false },
276
+ ...frontMarker(parameters, "ink", [0, 0, .5], [.27, .2, 1])
277
+ ]
278
+ };
279
+ }
280
+ },
281
+ {
282
+ id: "manual-input",
283
+ name: "Manual Input",
284
+ description: "Data entered manually by an operator.",
285
+ canonicalSize: [2.75, 1.65, 1.75],
286
+ parameters: {
287
+ icon: { type: "icon", label: "Front icon", default: "" },
288
+ image: { type: "image", label: "Front image URL", default: "" }
289
+ },
290
+ anchors: { input: [-1, .15, 0], output: [1, 0, 0], operator: [0, 1, 0] },
291
+ create({ parameters }) {
292
+ return {
293
+ parts: [
294
+ { shape: "box", size: [1, .62, .8], rotation: [0, 0, .16], color: "input", edgeColor: "edge", radius: .03 },
295
+ ...frontMarker(parameters, "ink", [0, 0, .43], [.3, .22, 1])
296
+ ]
297
+ };
298
+ }
299
+ },
300
+ {
301
+ id: "preparation",
302
+ name: "Preparation",
303
+ description: "Preparation, setup or initialization step.",
304
+ canonicalSize: [2.7, 1.8, 1.8],
305
+ parameters: {
306
+ icon: { type: "icon", label: "Front icon", default: "" }
307
+ },
308
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], setup: [0, 1, 0] },
309
+ create({ parameters }) {
310
+ return {
311
+ parts: [
312
+ { shape: "prism", size: [1, .74, .82], color: "process", edgeColor: "edge" },
313
+ ...frontMarker(parameters)
314
+ ]
315
+ };
316
+ }
317
+ },
318
+ {
319
+ id: "parallel-mode",
320
+ name: "Parallel Mode",
321
+ description: "A process that can execute in parallel.",
322
+ canonicalSize: [2.8, 1.9, 1.8],
323
+ parameters: {
324
+ lanes: { type: "number", label: "Lanes", min: 2, max: 4, step: 1, default: 2 },
325
+ icon: { type: "icon", label: "Front icon", default: "" }
326
+ },
327
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], lane: [0, 0, 1] },
328
+ create({ parameters }) {
329
+ const lanes = Math.round(clamp(parameters.lanes, 2, 4));
330
+ const parts = [
331
+ { shape: "box", size: [1, .76, .8], color: "process", edgeColor: "edge", radius: .04 }
332
+ ];
333
+ for (let index = 0; index < lanes; index++) {
334
+ const y = -.27 + index * (.54 / Math.max(1, lanes - 1));
335
+ parts.push(frontLine([0, y, .43], [.66, .025, .035], index % 2 ? "accent" : "edge"));
336
+ }
337
+ return { parts: [...parts, ...frontMarker(parameters)] };
338
+ }
339
+ },
340
+ {
341
+ id: "loop-limit",
342
+ name: "Loop Limit",
343
+ description: "A bounded loop or iteration limit.",
344
+ canonicalSize: [2.7, 1.9, 1.8],
345
+ parameters: {
346
+ limit: { type: "number", label: "Limit", min: 1, max: 99, step: 1, default: 3 },
347
+ icon: { type: "icon", label: "Front icon", default: "" }
348
+ },
349
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], loop: [0, 0, 1] },
350
+ create({ parameters }) {
351
+ const limit = Math.round(clamp(parameters.limit, 1, 99));
352
+ return {
353
+ parts: [
354
+ { shape: "pyramid-square", size: [1, .72, .82], color: "decision", edgeColor: "edge" },
355
+ frontLine([0, -.17, .45], [.34, .035, .035], "ink"),
356
+ ...frontMarker({ ...parameters, icon: parameters.icon || String(limit) }, "ink", [0, .12, .45], [.28, .2, 1])
357
+ ]
358
+ };
359
+ }
360
+ },
361
+ {
362
+ id: "display",
363
+ name: "Display",
364
+ description: "A user-facing display or presentation step.",
365
+ canonicalSize: [2.9, 1.8, 1.8],
366
+ parameters: {
367
+ screen: { type: "select", label: "Screen state", options: ["idle", "active", "warning"], default: "active" },
368
+ image: { type: "image", label: "Screen image URL", default: "" },
369
+ icon: { type: "icon", label: "Screen icon", default: "" }
370
+ },
371
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], user: [0, 0, 1] },
372
+ create({ parameters }) {
373
+ const color = parameters.screen === "warning" ? "negative" : parameters.screen === "active" ? "accent" : "body";
374
+ return {
375
+ parts: [
376
+ { shape: "box", size: [.9, .68, .76], color: "body", edgeColor: "edge", radius: .12 },
377
+ { shape: "box", size: [.72, .5, .05], position: [0, .02, .41], color: "screen", edgeColor: color, radius: .03 },
378
+ ...frontMarker(parameters, color, [0, .02, .45], [.25, .18, 1])
379
+ ]
380
+ };
381
+ }
382
+ },
383
+ {
384
+ id: "connector",
385
+ name: "Connector",
386
+ description: "An in-page connector or continuation point.",
387
+ canonicalSize: [1.55, 1.55, 1.55],
388
+ parameters: {
389
+ kind: { type: "select", label: "Kind", options: ["sequence", "junction"], default: "sequence" },
390
+ icon: { type: "icon", label: "Connector icon", default: "" }
391
+ },
392
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], continuation: [0, 0, 1] },
393
+ create({ parameters }) {
394
+ const color = parameters.kind === "junction" ? "decision" : "accent";
395
+ return {
396
+ parts: [
397
+ { shape: "cylinder", size: [.72, .22, .72], rotation: [0, 0, Math.PI / 2], color, edgeColor: "edge" },
398
+ { shape: "sphere", size: [.32, .32, .32], position: [0, 0, .39], color: "ink", edges: false },
399
+ ...frontMarker(parameters, "ink", [0, 0, .51], [.2, .16, 1])
400
+ ]
401
+ };
402
+ }
403
+ },
404
+ {
405
+ id: "off-page-reference",
406
+ name: "Off-page Reference",
407
+ description: "A continuation to another page or diagram.",
408
+ canonicalSize: [2.2, 2.1, 1.7],
409
+ parameters: {
410
+ target: { type: "string", label: "Target", default: "" },
411
+ icon: { type: "icon", label: "Reference icon", default: "" }
412
+ },
413
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0], continuation: [0, -1, 0] },
414
+ create({ parameters }) {
415
+ return {
416
+ parts: [
417
+ { shape: "pyramid-square", size: [1, .72, .82], rotation: [0, 0, Math.PI / 4], color: "paper", edgeColor: "edge" },
418
+ ...frontMarker({ ...parameters, icon: parameters.icon || parameters.target }, "ink", [0, 0, .2], [.25, .18, 1])
419
+ ]
420
+ };
421
+ }
422
+ },
423
+ {
424
+ id: "annotation",
425
+ name: "Annotation",
426
+ description: "A note linked to a process symbol.",
427
+ canonicalSize: [2.7, 1.9, 1.6],
428
+ parameters: {
429
+ icon: { type: "icon", label: "Annotation icon", default: "i" },
430
+ image: { type: "image", label: "Annotation image URL", default: "" }
431
+ },
432
+ anchors: { target: [-1, 0, 0], note: [1, 0, 0] },
433
+ create({ parameters }) {
434
+ return {
435
+ parts: [
436
+ { shape: "box", size: [.72, .58, .58], color: "paper", edgeColor: "edge", radius: .04 },
437
+ frontLine([.58, 0, 0], [.62, .035, .035], "accent"),
438
+ ...frontMarker(parameters, "ink", [0, 0, .32], [.22, .16, 1])
439
+ ]
440
+ };
441
+ }
442
+ },
443
+ {
444
+ id: "control-transfer",
445
+ name: "Control Transfer",
446
+ description: "A control or flow transfer marker.",
447
+ canonicalSize: [2.5, 1.55, 1.55],
448
+ parameters: {
449
+ direction: { type: "select", label: "Direction", options: ["forward", "back"], default: "forward" },
450
+ icon: { type: "icon", label: "Transfer icon", default: "" }
451
+ },
452
+ anchors: { input: [-1, 0, 0], output: [1, 0, 0] },
453
+ create({ parameters }) {
454
+ const rotation = parameters.direction === "back" ? -Math.PI / 2 : Math.PI / 2;
455
+ return {
456
+ parts: [
457
+ { shape: "box", size: [.62, .16, .16], position: [-.17, 0, 0], color: "accent", edges: false },
458
+ { shape: "cone", size: [.42, .42, .42], position: [.28, 0, 0], rotation: [0, 0, rotation], color: "accent", edgeColor: "edge" },
459
+ ...frontMarker(parameters, "ink", [0, 0, .24], [.2, .16, 1])
460
+ ]
461
+ };
462
+ }
463
+ },
464
+ {
465
+ id: "condition",
466
+ name: "Condition",
467
+ description: "A condition or rule gate.",
468
+ canonicalSize: [2.25, 1.8, 2.1],
469
+ parameters: {
470
+ state: { type: "select", label: "State", options: ["true", "false", "unknown"], default: "unknown" },
471
+ icon: { type: "icon", label: "Condition icon", default: "" }
472
+ },
473
+ anchors: { input: [-1, 0, 0], true: [1, .35, 0], false: [1, -.35, 0] },
474
+ create({ parameters }) {
475
+ const color = parameters.state === "true" ? "positive" : parameters.state === "false" ? "negative" : "decision";
476
+ return {
477
+ parts: [
478
+ { shape: "pyramid-triangle", size: [1, .68, .84], color, edgeColor: "edge" },
479
+ ...frontMarker(parameters, "ink", [0, 0, .45], [.22, .18, 1])
480
+ ]
481
+ };
482
+ }
483
+ }
484
+ ]
485
+ };
486
+
487
+ registerGeometryPack(processGeometryPack);
488
+
489
+ export default processGeometryPack;
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@liquidcars/atlas-geometry-processes",
3
+ "version": "0.1.0",
4
+ "description": "Standard process and flowchart geometry pack for LiquidCars Atlas",
5
+ "type": "module",
6
+ "main": "./index.js",
7
+ "module": "./index.js",
8
+ "exports": {
9
+ ".": "./index.js"
10
+ },
11
+ "files": [
12
+ "index.js",
13
+ "README.md"
14
+ ],
15
+ "sideEffects": true,
16
+ "peerDependencies": {
17
+ "@liquidcars/atlas": ">=0.1.25"
18
+ },
19
+ "keywords": [
20
+ "liquidcars",
21
+ "atlas",
22
+ "3d",
23
+ "geometry-pack",
24
+ "process",
25
+ "flowchart",
26
+ "bpmn"
27
+ ],
28
+ "license": "MIT"
29
+ }