@hatiolab/figure-model 0.4.0 → 0.4.2
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/dist/asset-types.d.ts +6 -0
- package/dist/asset-types.d.ts.map +1 -1
- package/dist/asset-types.js.map +1 -1
- package/dist/asset.d.ts +12 -0
- package/dist/asset.d.ts.map +1 -1
- package/dist/asset.js +15 -3
- package/dist/asset.js.map +1 -1
- package/dist/authoring-actions.d.ts +30 -0
- package/dist/authoring-actions.d.ts.map +1 -1
- package/dist/authoring-actions.js +91 -8
- package/dist/authoring-actions.js.map +1 -1
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +71 -11
- package/dist/capabilities.js.map +1 -1
- package/dist/command-preview.d.ts +6 -0
- package/dist/command-preview.d.ts.map +1 -1
- package/dist/command-preview.js +35 -2
- package/dist/command-preview.js.map +1 -1
- package/dist/editor-workspace.d.ts +48 -401
- package/dist/editor-workspace.d.ts.map +1 -1
- package/dist/editor-workspace.js +55 -13
- package/dist/editor-workspace.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel-version.d.ts +1 -1
- package/dist/kernel-version.js +1 -1
- package/dist/proposal.d.ts +1 -1
- package/dist/proposal.d.ts.map +1 -1
- package/dist/proposal.js +8 -0
- package/dist/proposal.js.map +1 -1
- package/dist/release-contract.d.ts +1 -1
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +27 -4
- package/dist/release-contract.js.map +1 -1
- package/dist/slot-layout.d.ts +212 -0
- package/dist/slot-layout.d.ts.map +1 -0
- package/dist/slot-layout.js +333 -0
- package/dist/slot-layout.js.map +1 -0
- package/dist/slot-places.d.ts +45 -0
- package/dist/slot-places.d.ts.map +1 -0
- package/dist/slot-places.js +40 -0
- package/dist/slot-places.js.map +1 -0
- package/dist/work-counter.d.ts +16 -0
- package/dist/work-counter.d.ts.map +1 -0
- package/dist/work-counter.js +13 -0
- package/dist/work-counter.js.map +1 -0
- package/docs/modeller-interaction-performance-2026-10-07.md +60 -0
- package/docs/performance-followup-2026-10-05.md +267 -3
- package/docs/shape-dimension-contract.md +10 -0
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-layout.d.ts","sourceRoot":"","sources":["../src/slot-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Slot layouts (ADR-0118): a holder's tiers, the slots on each tier, how slots are numbered, where an item sits in a
|
|
3
|
+
* slot, and whether it fits. Pure computation; nothing here knows a scene, a graph or a component.
|
|
4
|
+
*
|
|
5
|
+
* A holder has one or more tiers; each tier has its own arrangement (SINGLE, ROW, GRID or CUSTOM). A slot's address is
|
|
6
|
+
* (tier, slot), both counted from 1, and slot numbers restart on every tier. ROW and GRID slots are not stored: they are
|
|
7
|
+
* worked out from the rule, so thousands of slots are one rule. A slot's id is `t{tier}_s{slot}` -- a logical id, not
|
|
8
|
+
* the name of a node in any 3D asset.
|
|
9
|
+
*
|
|
10
|
+
* Coordinates are the holder's own: X and Z put a slot's centre relative to the tier's centre, Y is the tier floor's
|
|
11
|
+
* height above the holder's floor. Lengths are in whatever unit the layout is written in; nothing here converts them.
|
|
12
|
+
* Rotations are in degrees about Y.
|
|
13
|
+
*/
|
|
14
|
+
export function layoutIssue(code, path, params) {
|
|
15
|
+
return params ? { code, path, params } : { code, path };
|
|
16
|
+
}
|
|
17
|
+
/* ── checking a layout ───────────────────────────────────────────────────── */
|
|
18
|
+
const isFiniteNumber = (v) => typeof v === 'number' && Number.isFinite(v);
|
|
19
|
+
const isPositive = (v) => isFiniteNumber(v) && v > 0;
|
|
20
|
+
const isPositiveInt = (v) => Number.isSafeInteger(v) && v > 0;
|
|
21
|
+
function checkSpec(spec, path, issues) {
|
|
22
|
+
const a = spec?.allowed;
|
|
23
|
+
if (!a || typeof a !== 'object')
|
|
24
|
+
issues.push(layoutIssue('OBJECT_REQUIRED', `${path}.allowed`));
|
|
25
|
+
else
|
|
26
|
+
for (const k of ['width', 'depth', 'height'])
|
|
27
|
+
if (!isPositive(a[k]))
|
|
28
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.allowed.${k}`));
|
|
29
|
+
if (spec?.stackLimit !== undefined && !isPositiveInt(spec.stackLimit) && spec.stackLimit !== Infinity)
|
|
30
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.stackLimit`));
|
|
31
|
+
if (spec?.rotation !== undefined && !isFiniteNumber(spec.rotation))
|
|
32
|
+
issues.push(layoutIssue('FINITE_NUMBER_REQUIRED', `${path}.rotation`));
|
|
33
|
+
if (spec?.accepts !== undefined && !Array.isArray(spec.accepts))
|
|
34
|
+
issues.push(layoutIssue('ARRAY_REQUIRED', `${path}.accepts`));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Everything wrong with a layout; an empty list is a sound one. stackLimit may be Infinity (no limit); a layout that is
|
|
38
|
+
* to be stored as JSON is also checked with `persistenceIssues`.
|
|
39
|
+
*/
|
|
40
|
+
export function validateSlotLayout(layout) {
|
|
41
|
+
const issues = [];
|
|
42
|
+
if (!layout || !Array.isArray(layout.tiers) || layout.tiers.length === 0)
|
|
43
|
+
return [layoutIssue('TIERS_REQUIRED', 'tiers')];
|
|
44
|
+
if (!['ON', 'IN', 'HANG'].includes(layout.mount))
|
|
45
|
+
issues.push(layoutIssue('MOUNT_INVALID', 'mount'));
|
|
46
|
+
layout.tiers.forEach((tier, i) => {
|
|
47
|
+
const path = `tiers[${i}]`;
|
|
48
|
+
if (!tier || typeof tier !== 'object') {
|
|
49
|
+
issues.push(layoutIssue('OBJECT_REQUIRED', path));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (tier.tierNo !== i + 1)
|
|
53
|
+
issues.push(layoutIssue('TIER_NUMBER_SEQUENCE', `${path}.tierNo`));
|
|
54
|
+
if (!isFiniteNumber(tier.elevation))
|
|
55
|
+
issues.push(layoutIssue('FINITE_NUMBER_REQUIRED', `${path}.elevation`));
|
|
56
|
+
else if (i > 0 && isFiniteNumber(layout.tiers[i - 1]?.elevation) && tier.elevation <= layout.tiers[i - 1].elevation)
|
|
57
|
+
issues.push(layoutIssue('ELEVATION_NOT_ASCENDING', `${path}.elevation`));
|
|
58
|
+
const l = tier.layout;
|
|
59
|
+
switch (l?.pattern) {
|
|
60
|
+
case 'SINGLE':
|
|
61
|
+
checkSpec(l.slot, `${path}.layout.slot`, issues);
|
|
62
|
+
break;
|
|
63
|
+
case 'ROW':
|
|
64
|
+
if (!isPositiveInt(l.count))
|
|
65
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.layout.count`));
|
|
66
|
+
if (!isPositive(l.pitch))
|
|
67
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.layout.pitch`));
|
|
68
|
+
if (l.axis !== 'X' && l.axis !== 'Z')
|
|
69
|
+
issues.push(layoutIssue('AXIS_INVALID', `${path}.layout.axis`));
|
|
70
|
+
checkSpec(l.slot, `${path}.layout.slot`, issues);
|
|
71
|
+
break;
|
|
72
|
+
case 'GRID':
|
|
73
|
+
if (!isPositiveInt(l.rows))
|
|
74
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.layout.rows`));
|
|
75
|
+
if (!isPositiveInt(l.cols))
|
|
76
|
+
issues.push(layoutIssue('POSITIVE_INTEGER_REQUIRED', `${path}.layout.cols`));
|
|
77
|
+
if (!isPositive(l.pitch?.x))
|
|
78
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.layout.pitch.x`));
|
|
79
|
+
if (!isPositive(l.pitch?.z))
|
|
80
|
+
issues.push(layoutIssue('POSITIVE_NUMBER_REQUIRED', `${path}.layout.pitch.z`));
|
|
81
|
+
checkSpec(l.slot, `${path}.layout.slot`, issues);
|
|
82
|
+
break;
|
|
83
|
+
case 'CUSTOM': {
|
|
84
|
+
const slots = Array.isArray(l.slots) ? l.slots : [];
|
|
85
|
+
const nos = slots.map(s => s?.slotNo).sort((a, b) => a - b);
|
|
86
|
+
if (!nos.length || nos.some((n, k) => n !== k + 1))
|
|
87
|
+
issues.push(layoutIssue('SLOT_NUMBER_SEQUENCE', `${path}.layout.slots`));
|
|
88
|
+
slots.forEach((s, k) => {
|
|
89
|
+
if (!isFiniteNumber(s?.offset?.x) || !isFiniteNumber(s?.offset?.z))
|
|
90
|
+
issues.push(layoutIssue('FINITE_NUMBER_REQUIRED', `${path}.layout.slots[${k}].offset`));
|
|
91
|
+
checkSpec(s, `${path}.layout.slots[${k}]`, issues);
|
|
92
|
+
});
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
default:
|
|
96
|
+
issues.push(layoutIssue('PATTERN_INVALID', `${path}.layout.pattern`));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return issues;
|
|
100
|
+
}
|
|
101
|
+
/** Values JSON turns into null (NaN, Infinity): stored, they would come back as a broken layout. */
|
|
102
|
+
export function persistenceIssues(value, path = '') {
|
|
103
|
+
const issues = [];
|
|
104
|
+
const walk = (v, p) => {
|
|
105
|
+
if (typeof v === 'number' && !Number.isFinite(v))
|
|
106
|
+
issues.push(layoutIssue('NOT_PERSISTABLE', p, { value: String(v) }));
|
|
107
|
+
else if (Array.isArray(v))
|
|
108
|
+
v.forEach((x, i) => walk(x, `${p}[${i}]`));
|
|
109
|
+
else if (v && typeof v === 'object')
|
|
110
|
+
for (const [k, x] of Object.entries(v))
|
|
111
|
+
walk(x, p ? `${p}.${k}` : k);
|
|
112
|
+
};
|
|
113
|
+
walk(value, path);
|
|
114
|
+
return issues;
|
|
115
|
+
}
|
|
116
|
+
/* ── numbering ───────────────────────────────────────────────────────────── */
|
|
117
|
+
export function slotCount(pattern) {
|
|
118
|
+
switch (pattern.pattern) {
|
|
119
|
+
case 'SINGLE':
|
|
120
|
+
return 1;
|
|
121
|
+
case 'ROW':
|
|
122
|
+
return pattern.count;
|
|
123
|
+
case 'GRID':
|
|
124
|
+
return pattern.rows * pattern.cols;
|
|
125
|
+
case 'CUSTOM':
|
|
126
|
+
return pattern.slots.length;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** A GRID slot's number from its row r and column c (from 1), counted from the origin corner. */
|
|
130
|
+
export function gridSlotNo(rows, cols, r, c, order = 'ROW_MAJOR') {
|
|
131
|
+
switch (order) {
|
|
132
|
+
case 'ROW_MAJOR':
|
|
133
|
+
return (r - 1) * cols + c;
|
|
134
|
+
case 'COL_MAJOR':
|
|
135
|
+
return (c - 1) * rows + r;
|
|
136
|
+
case 'SERPENTINE_ROW':
|
|
137
|
+
return (r - 1) * cols + (r % 2 === 1 ? c : cols - c + 1);
|
|
138
|
+
case 'SERPENTINE_COL':
|
|
139
|
+
return (c - 1) * rows + (c % 2 === 1 ? r : rows - r + 1);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** The row and column of a GRID slot number -- the inverse of gridSlotNo. */
|
|
143
|
+
export function gridCellOf(rows, cols, slotNo, order = 'ROW_MAJOR') {
|
|
144
|
+
const i = slotNo - 1;
|
|
145
|
+
switch (order) {
|
|
146
|
+
case 'ROW_MAJOR':
|
|
147
|
+
return { r: Math.floor(i / cols) + 1, c: (i % cols) + 1 };
|
|
148
|
+
case 'COL_MAJOR':
|
|
149
|
+
return { r: (i % rows) + 1, c: Math.floor(i / rows) + 1 };
|
|
150
|
+
case 'SERPENTINE_ROW': {
|
|
151
|
+
const r = Math.floor(i / cols) + 1;
|
|
152
|
+
const k = (i % cols) + 1;
|
|
153
|
+
return { r, c: r % 2 === 1 ? k : cols - k + 1 };
|
|
154
|
+
}
|
|
155
|
+
case 'SERPENTINE_COL': {
|
|
156
|
+
const c = Math.floor(i / rows) + 1;
|
|
157
|
+
const k = (i % rows) + 1;
|
|
158
|
+
return { r: c % 2 === 1 ? k : rows - k + 1, c };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** Flips a sign without making -0. */
|
|
163
|
+
const flip = (v, max) => (max && v !== 0 ? -v : v);
|
|
164
|
+
/**
|
|
165
|
+
* The slot at an address, or null when the tier or the slot is not there. ROW and GRID slots are worked out:
|
|
166
|
+
* ROW centre = ((n - 1) - (count - 1) / 2) × pitch, negated when origin is MAX
|
|
167
|
+
* GRID centre = the row and column the order gives, x = (c - 1 - (cols - 1)/2) × pitch.x,
|
|
168
|
+
* z = (r - 1 - (rows - 1)/2) × pitch.z, each negated when its origin is MAX
|
|
169
|
+
*/
|
|
170
|
+
export function resolveSlot(layout, address, options = {}) {
|
|
171
|
+
const tier = layout?.tiers?.find(t => t?.tierNo === address?.tier);
|
|
172
|
+
if (!tier || !isPositiveInt(address.slot) || address.slot > slotCount(tier.layout))
|
|
173
|
+
return null;
|
|
174
|
+
const l = tier.layout;
|
|
175
|
+
let spec;
|
|
176
|
+
let offset;
|
|
177
|
+
let name;
|
|
178
|
+
switch (l.pattern) {
|
|
179
|
+
case 'SINGLE':
|
|
180
|
+
spec = l.slot;
|
|
181
|
+
offset = { x: 0, z: 0 };
|
|
182
|
+
break;
|
|
183
|
+
case 'ROW': {
|
|
184
|
+
const v = flip((address.slot - 1 - (l.count - 1) / 2) * l.pitch, l.origin === 'MAX');
|
|
185
|
+
spec = l.slot;
|
|
186
|
+
offset = l.axis === 'X' ? { x: v, z: 0 } : { x: 0, z: v };
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'GRID': {
|
|
190
|
+
const { r, c } = gridCellOf(l.rows, l.cols, address.slot, l.order);
|
|
191
|
+
const origin = l.origin ?? { x: 'MIN', z: 'MIN' };
|
|
192
|
+
spec = l.slot;
|
|
193
|
+
offset = {
|
|
194
|
+
x: flip((c - 1 - (l.cols - 1) / 2) * l.pitch.x, origin.x === 'MAX'),
|
|
195
|
+
z: flip((r - 1 - (l.rows - 1) / 2) * l.pitch.z, origin.z === 'MAX')
|
|
196
|
+
};
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case 'CUSTOM': {
|
|
200
|
+
const s = l.slots.find(s => s.slotNo === address.slot);
|
|
201
|
+
if (!s)
|
|
202
|
+
return null;
|
|
203
|
+
spec = s;
|
|
204
|
+
offset = { ...s.offset };
|
|
205
|
+
name = s.name;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
tier: tier.tierNo,
|
|
211
|
+
slotNo: address.slot,
|
|
212
|
+
name,
|
|
213
|
+
elevation: tier.elevation,
|
|
214
|
+
offset,
|
|
215
|
+
allowed: { ...spec.allowed },
|
|
216
|
+
accepts: spec.accepts ? [...spec.accepts] : undefined,
|
|
217
|
+
stackLimit: spec.stackLimit ?? options.defaultStackLimit ?? 1,
|
|
218
|
+
rotation: spec.rotation ?? 0
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
/* ── slot ids ────────────────────────────────────────────────────────────── */
|
|
222
|
+
/** A slot's logical id. */
|
|
223
|
+
export function slotIdOf(address) {
|
|
224
|
+
return `t${address.tier}_s${address.slot}`;
|
|
225
|
+
}
|
|
226
|
+
/** The address a slot id names, or null when it is not one. */
|
|
227
|
+
export function addressOfSlotId(slotId) {
|
|
228
|
+
const m = typeof slotId === 'string' ? /^t(\d+)_s(\d+)$/.exec(slotId) : null;
|
|
229
|
+
return m ? { tier: Number(m[1]), slot: Number(m[2]) } : null;
|
|
230
|
+
}
|
|
231
|
+
/** Every address of a layout, tier by tier. For a big GRID, resolve only the addresses you need. */
|
|
232
|
+
export function* slotAddresses(layout) {
|
|
233
|
+
for (const tier of layout?.tiers ?? [])
|
|
234
|
+
for (let slot = 1; slot <= slotCount(tier.layout); slot++)
|
|
235
|
+
yield { tier: tier.tierNo, slot };
|
|
236
|
+
}
|
|
237
|
+
export const DEFAULT_SEAT_MARGIN = 0.05;
|
|
238
|
+
const knownDims = (d) => !!d && isPositive(d.width) && isPositive(d.depth) && isPositive(d.height);
|
|
239
|
+
/** The X and Z extent of an item turned by `rotation` degrees. */
|
|
240
|
+
export function rotatedFootprint(dims, rotation) {
|
|
241
|
+
const rad = (rotation * Math.PI) / 180;
|
|
242
|
+
const c = Math.abs(Math.cos(rad));
|
|
243
|
+
const s = Math.abs(Math.sin(rad));
|
|
244
|
+
// clears the 6e-17 left at multiples of 90°
|
|
245
|
+
const clean = (v) => Math.round(v * 1e9) / 1e9;
|
|
246
|
+
return { width: clean(dims.width * c + dims.depth * s), depth: clean(dims.width * s + dims.depth * c) };
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Where an item sits in a slot: shrunk to fit the slot's width and depth (by its turned extent, never enlarged), on top
|
|
250
|
+
* of `belowHeight` -- the shown heights (height × scale) of what is stacked under it. `margin` is room left only for
|
|
251
|
+
* showing (0 ≤ margin < 1); whether it fits is judged elsewhere, at full size. Null when a size or value is unusable --
|
|
252
|
+
* never NaN or Infinity.
|
|
253
|
+
*/
|
|
254
|
+
export function seatTransform(dims, slot, mount, belowHeight = 0, margin = DEFAULT_SEAT_MARGIN) {
|
|
255
|
+
if (!knownDims(dims))
|
|
256
|
+
return null;
|
|
257
|
+
if (!isFiniteNumber(belowHeight) || !isFiniteNumber(margin) || margin < 0 || margin >= 1)
|
|
258
|
+
return null;
|
|
259
|
+
const fp = rotatedFootprint(dims, slot.rotation);
|
|
260
|
+
const scale = Math.min(1, Math.min(slot.allowed.width / fp.width, slot.allowed.depth / fp.depth) * (1 - margin));
|
|
261
|
+
const h = dims.height * scale;
|
|
262
|
+
const dir = mount === 'HANG' ? -1 : 1;
|
|
263
|
+
const y = slot.elevation + dir * (belowHeight + h / 2);
|
|
264
|
+
return { position: { x: slot.offset.x, y, z: slot.offset.z }, rotation: slot.rotation, scale };
|
|
265
|
+
}
|
|
266
|
+
/** Where each of a slot's stacked items sits, bottom first. An item of unknown size is null and adds no height. */
|
|
267
|
+
export function stackSeatTransforms(stack, slot, mount, margin = DEFAULT_SEAT_MARGIN) {
|
|
268
|
+
let below = 0;
|
|
269
|
+
return stack.map(dims => {
|
|
270
|
+
const t = dims ? seatTransform(dims, slot, mount, below, margin) : null;
|
|
271
|
+
if (t)
|
|
272
|
+
below += dims.height * t.scale;
|
|
273
|
+
return t;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/** A slot anchor's place in the holder: the slot's offset and the tier's elevation, nothing else. */
|
|
277
|
+
export function slotAnchorPosition(slot) {
|
|
278
|
+
return { x: slot.offset.x, y: slot.elevation, z: slot.offset.z };
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Where an item sits when it hangs off a slot anchor: only the stack height, half its height, scale and turn; x and z are
|
|
282
|
+
* 0 because the anchor already has the offset and elevation.
|
|
283
|
+
* slotAnchorPosition(slot) + seatInAnchor(...).position = seatTransform(...).position
|
|
284
|
+
*/
|
|
285
|
+
export function seatInAnchor(dims, slot, mount, belowHeight = 0, margin = DEFAULT_SEAT_MARGIN) {
|
|
286
|
+
const t = seatTransform(dims, slot, mount, belowHeight, margin);
|
|
287
|
+
if (!t)
|
|
288
|
+
return null;
|
|
289
|
+
return { position: { x: 0, y: t.position.y - slot.elevation, z: 0 }, rotation: t.rotation, scale: t.scale };
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Whether one more item fits in a slot that already holds `occupants`, at full size. The count limit and the height
|
|
293
|
+
* limit are separate checks. accepts left out takes any type; an empty list takes none. UNKNOWN when a type or a size
|
|
294
|
+
* needed to judge is not known.
|
|
295
|
+
*/
|
|
296
|
+
export function judgeItemFit(slot, candidate, occupants = [], options = {}) {
|
|
297
|
+
if (!slot)
|
|
298
|
+
return { verdict: 'NG', reasons: ['SLOT_NOT_FOUND'] };
|
|
299
|
+
const norm = options.normalizeType ?? ((t) => (t === undefined || t === null ? '' : String(t)));
|
|
300
|
+
const reasons = [];
|
|
301
|
+
let unknown = false;
|
|
302
|
+
if (slot.accepts) {
|
|
303
|
+
const type = norm(candidate.type);
|
|
304
|
+
if (!type)
|
|
305
|
+
unknown = true;
|
|
306
|
+
else if (!slot.accepts.map(norm).includes(type))
|
|
307
|
+
reasons.push('TYPE_NOT_ACCEPTED');
|
|
308
|
+
}
|
|
309
|
+
if (occupants.length + 1 > slot.stackLimit)
|
|
310
|
+
reasons.push('STACK_LIMIT_EXCEEDED');
|
|
311
|
+
if (!knownDims(candidate.dims))
|
|
312
|
+
unknown = true;
|
|
313
|
+
else {
|
|
314
|
+
const fp = rotatedFootprint(candidate.dims, slot.rotation);
|
|
315
|
+
if (fp.width > slot.allowed.width)
|
|
316
|
+
reasons.push('WIDTH_EXCEEDED');
|
|
317
|
+
if (fp.depth > slot.allowed.depth)
|
|
318
|
+
reasons.push('DEPTH_EXCEEDED');
|
|
319
|
+
if (occupants.every(o => knownDims(o.dims))) {
|
|
320
|
+
const total = occupants.reduce((sum, o) => sum + o.dims.height, candidate.dims.height);
|
|
321
|
+
if (total > slot.allowed.height)
|
|
322
|
+
reasons.push('HEIGHT_EXCEEDED');
|
|
323
|
+
}
|
|
324
|
+
else
|
|
325
|
+
unknown = true;
|
|
326
|
+
}
|
|
327
|
+
if (reasons.length)
|
|
328
|
+
return { verdict: 'NG', reasons: unknown ? [...reasons, 'SPEC_UNKNOWN'] : reasons };
|
|
329
|
+
if (unknown)
|
|
330
|
+
return { verdict: 'UNKNOWN', reasons: ['SPEC_UNKNOWN'] };
|
|
331
|
+
return { verdict: 'OK', reasons: [] };
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=slot-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-layout.js","sourceRoot":"","sources":["../src/slot-layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { FigureSurfaceReference } from './asset-types.ts';
|
|
2
|
+
import { type SlotLayout, type SlotMount } from './slot-layout.ts';
|
|
3
|
+
export interface FigureSlotLayoutDeclaration {
|
|
4
|
+
label: string;
|
|
5
|
+
role: 'seat' | 'grip';
|
|
6
|
+
/** The frame of the face the layout sits on -- the same rule as a binding's frame. */
|
|
7
|
+
frame: string;
|
|
8
|
+
/** The face the layout sits on. Its slots are laid out in the part's X and Z; tiers rise along its Y. */
|
|
9
|
+
pose: FigureSurfaceReference;
|
|
10
|
+
/** Every slot must name the types it takes (ADR-0087 decision 3). */
|
|
11
|
+
layout: SlotLayout;
|
|
12
|
+
}
|
|
13
|
+
/** One slot unfolded from a layout: a place like a binding, plus where on the face it is. */
|
|
14
|
+
export interface FigureSlotPlace {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
role: 'seat' | 'grip';
|
|
18
|
+
frame: string;
|
|
19
|
+
pose: FigureSurfaceReference;
|
|
20
|
+
accepts: string[];
|
|
21
|
+
/** How many it holds at once: the slot's stackLimit. */
|
|
22
|
+
capacity: number;
|
|
23
|
+
tier: number;
|
|
24
|
+
slot: number;
|
|
25
|
+
name?: string;
|
|
26
|
+
/** The slot's centre on the face, in the part's X and Z. */
|
|
27
|
+
offset: {
|
|
28
|
+
x: number;
|
|
29
|
+
z: number;
|
|
30
|
+
};
|
|
31
|
+
/** The tier floor's height above the face, along the part's Y (below it for HANG). */
|
|
32
|
+
elevation: number;
|
|
33
|
+
/** Degrees about Y. */
|
|
34
|
+
rotation: number;
|
|
35
|
+
mount: SlotMount;
|
|
36
|
+
/** The room a held thing may take: width along X, height along Y, depth along Z. */
|
|
37
|
+
allowed: {
|
|
38
|
+
width: number;
|
|
39
|
+
depth: number;
|
|
40
|
+
height: number;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** The places a declaration unfolds into, tier by tier and slot by slot. None when there is no declaration. */
|
|
44
|
+
export declare function figureSlotPlacesOf(declaration: FigureSlotLayoutDeclaration | undefined): FigureSlotPlace[];
|
|
45
|
+
//# sourceMappingURL=slot-places.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-places.d.ts","sourceRoot":"","sources":["../src/slot-places.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAAwC,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAExG,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAA;IACb,yGAAyG;IACzG,IAAI,EAAE,sBAAsB,CAAA;IAC5B,qEAAqE;IACrE,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,6FAA6F;AAC7F,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,sBAAsB,CAAA;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAChC,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAA;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,SAAS,CAAA;IAChB,oFAAoF;IACpF,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1D;AAED,+GAA+G;AAC/G,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,2BAA2B,GAAG,SAAS,GAAG,eAAe,EAAE,CA0B1G"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A figure's slot layout declaration and the places it unfolds into (ADR-0118).
|
|
3
|
+
*
|
|
4
|
+
* A figure declares one slot layout on a face of one of its parts. Compiling unfolds it into one place per slot, each
|
|
5
|
+
* with the id `t{tier}_s{slot}` -- a logical id, not the name of a node in the asset. The count and the ids are what the
|
|
6
|
+
* author wrote; resizing the figure does not change them. Unfolding reads the declaration only, so the release
|
|
7
|
+
* comparison and the authoring read-back see the same places the compiled figure evaluates.
|
|
8
|
+
*/
|
|
9
|
+
import { resolveSlot, slotAddresses, slotIdOf } from "./slot-layout.js";
|
|
10
|
+
/** The places a declaration unfolds into, tier by tier and slot by slot. None when there is no declaration. */
|
|
11
|
+
export function figureSlotPlacesOf(declaration) {
|
|
12
|
+
if (!declaration?.layout)
|
|
13
|
+
return [];
|
|
14
|
+
const places = [];
|
|
15
|
+
for (const address of slotAddresses(declaration.layout)) {
|
|
16
|
+
const s = resolveSlot(declaration.layout, address);
|
|
17
|
+
if (!s)
|
|
18
|
+
continue;
|
|
19
|
+
const id = slotIdOf(address);
|
|
20
|
+
places.push({
|
|
21
|
+
id,
|
|
22
|
+
label: `${declaration.label} ${id}`,
|
|
23
|
+
role: declaration.role,
|
|
24
|
+
frame: declaration.frame,
|
|
25
|
+
pose: { ...declaration.pose },
|
|
26
|
+
accepts: [...(s.accepts ?? [])],
|
|
27
|
+
capacity: s.stackLimit,
|
|
28
|
+
tier: s.tier,
|
|
29
|
+
slot: s.slotNo,
|
|
30
|
+
...(s.name ? { name: s.name } : {}),
|
|
31
|
+
offset: { ...s.offset },
|
|
32
|
+
elevation: s.elevation,
|
|
33
|
+
rotation: s.rotation,
|
|
34
|
+
mount: declaration.layout.mount,
|
|
35
|
+
allowed: { ...s.allowed }
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return places;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=slot-places.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot-places.js","sourceRoot":"","sources":["../src/slot-places.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAmC,MAAM,kBAAkB,CAAA;AAqCxG,+GAA+G;AAC/G,MAAM,UAAU,kBAAkB,CAAC,WAAoD;IACrF,IAAI,CAAC,WAAW,EAAE,MAAM;QAAE,OAAO,EAAE,CAAA;IACnC,MAAM,MAAM,GAAsB,EAAE,CAAA;IACpC,KAAK,MAAM,OAAO,IAAI,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;QACxD,MAAM,CAAC,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAClD,IAAI,CAAC,CAAC;YAAE,SAAQ;QAChB,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC5B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE;YACF,KAAK,EAAE,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE,EAAE;YACnC,IAAI,EAAE,WAAW,CAAC,IAAI;YACtB,KAAK,EAAE,WAAW,CAAC,KAAK;YACxB,IAAI,EAAE,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE;YAC7B,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAC/B,QAAQ,EAAE,CAAC,CAAC,UAAU;YACtB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,MAAM;YACd,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;YACvB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,KAAK;YAC/B,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE;SAC1B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much whole-figure work has been done: assets compiled (each compile also evaluates the stored inputs once, so a
|
|
3
|
+
* parse, a serialize or a capture is one) and figures evaluated. A count, not a time: the same on every machine and in
|
|
4
|
+
* every run, so a test can hold an interaction to a number of them (the modeller's selection and edit budgets).
|
|
5
|
+
*/
|
|
6
|
+
export declare const figureWork: {
|
|
7
|
+
compiles: number;
|
|
8
|
+
evaluations: number;
|
|
9
|
+
};
|
|
10
|
+
/** The work done while `run` runs. */
|
|
11
|
+
export declare function measureFigureWork<T>(run: () => T): {
|
|
12
|
+
result: T;
|
|
13
|
+
compiles: number;
|
|
14
|
+
evaluations: number;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=work-counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-counter.d.ts","sourceRoot":"","sources":["../src/work-counter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAkC,CAAA;AAEzD,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG;IAAE,MAAM,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAIvG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much whole-figure work has been done: assets compiled (each compile also evaluates the stored inputs once, so a
|
|
3
|
+
* parse, a serialize or a capture is one) and figures evaluated. A count, not a time: the same on every machine and in
|
|
4
|
+
* every run, so a test can hold an interaction to a number of them (the modeller's selection and edit budgets).
|
|
5
|
+
*/
|
|
6
|
+
export const figureWork = { compiles: 0, evaluations: 0 };
|
|
7
|
+
/** The work done while `run` runs. */
|
|
8
|
+
export function measureFigureWork(run) {
|
|
9
|
+
const before = { ...figureWork };
|
|
10
|
+
const result = run();
|
|
11
|
+
return { result, compiles: figureWork.compiles - before.compiles, evaluations: figureWork.evaluations - before.evaluations };
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=work-counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-counter.js","sourceRoot":"","sources":["../src/work-counter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAA;AAEzD,sCAAsC;AACtC,MAAM,UAAU,iBAAiB,CAAI,GAAY;IAC/C,MAAM,MAAM,GAAG,EAAE,GAAG,UAAU,EAAE,CAAA;IAChC,MAAM,MAAM,GAAG,GAAG,EAAE,CAAA;IACpB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAA;AAC9H,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# 모델러 선택·값 변경 성능 측정 (2026-10-07)
|
|
2
|
+
|
|
3
|
+
결정 정본: [ADR-0119](../../operato-application/adr/ADR-0119.md) (안건).
|
|
4
|
+
이 문서는 측정 원자료와 실행 상태를 둔다. 예정 효과를 성과로 적지 않는다.
|
|
5
|
+
|
|
6
|
+
## 대상과 방법
|
|
7
|
+
|
|
8
|
+
- 대상: 지게차 Figure(부품 504개, joint 다수, 소스 112 KB), operato-figure :3300 모델러.
|
|
9
|
+
- 브라우저 측정: Long Task / Long Animation Frame 관찰자, 세션 메서드와 Lit 렌더를 감싼 시간 합산. 정상 상태는 같은 조작을 세 번 해서 읽는다. 콜드 첫 선택은 따로 적는다.
|
|
10
|
+
- 횟수 측정: `work-counter.ts`(`measureFigureWork`)가 전체 컴파일과 평가를 센다. 시간과 달리 머신과 부하에 흔들리지 않는다. 예산 시험은 `editor-workspace.test.ts`의 「interaction budgets」.
|
|
11
|
+
- 시간(ms)은 10-05 `A/A` 변동 때문에 후보를 가르는 근거로 쓰지 않는다. 횟수로 가르고, 시간은 사용자가 느끼는 크기를 보이는 용도로만 쓴다.
|
|
12
|
+
|
|
13
|
+
## 결과 (브라우저, 정상 상태)
|
|
14
|
+
|
|
15
|
+
| 조작 | 시작 | 지금 |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| 파트 클릭 | 2.1초, 첫 클릭 10.5초 | 클릭 처리 약 90 ms, 150 ms 뒤 미리보기 약 100 ms. 콜드 첫 선택 약 230 ms |
|
|
18
|
+
| 값 변경 확정 | 약 970 ms | 약 230 ms. 이어서 늦춘 작업 셋이 각각 별도 작업으로 약 110·약 100·약 70~100 ms |
|
|
19
|
+
|
|
20
|
+
값 변경 확정 프레임 약 230 ms의 구성: `command` 약 100 ms(커널), `figure-links` 첫 렌더 약 50 ms, `figure-editor` 렌더 약 33 ms.
|
|
21
|
+
`figure-links` 쪽은 옵션 504개 DOM 때문으로 추정하지만 확인하지 않았다.
|
|
22
|
+
|
|
23
|
+
## 결과 (횟수, 워크스페이스, 한 번에 일어나는 전체 컴파일)
|
|
24
|
+
|
|
25
|
+
| 조작 | 시작 | 지금 | 예산 시험 |
|
|
26
|
+
| --- | --- | --- | --- |
|
|
27
|
+
| 열기 | 9 | 3 | ≤ 3 |
|
|
28
|
+
| 값 변경 + 읽기 + dirty | 12(시험 도형에서 27까지) | 4 | ≤ 4 |
|
|
29
|
+
| 소스 텍스트(export) | 3 | 1 | ≤ 1 |
|
|
30
|
+
| 다시 읽기 | 매번 전체 | 0 | 0 |
|
|
31
|
+
|
|
32
|
+
시작값은 수정 전 코드에 같은 예산 시험을 돌린 값이다(열기 9, 값 변경 27, undo+redo 31). 값 변경 12는 지게차 한 명령의 호출 스택 분해다.
|
|
33
|
+
|
|
34
|
+
## compileAsset 한 번의 구성 (지게차, node, 10회 평균, 약 21.8 ms)
|
|
35
|
+
|
|
36
|
+
| 단계 | ms |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| jsonOnly | 1.0 |
|
|
39
|
+
| stringify · 크기 · 필드 | 0.2 |
|
|
40
|
+
| structuredClone | 0.4 |
|
|
41
|
+
| compileDocument | 약 3.0 |
|
|
42
|
+
| 저장 입력 evaluate | 0.5 |
|
|
43
|
+
| **자산 검증(나머지)** | **약 16.6** |
|
|
44
|
+
|
|
45
|
+
CPU 프로파일 포함 시간(compileAsset 272 ms 안): `checkFigureJoints` 189 ms(69 %) → `rewriteJoints` 177 → `writeJoint` 130 → `dropIfUnused` 118 → `stringsIn` 103(자체 시간 1위, 26 %).
|
|
46
|
+
|
|
47
|
+
- 평가는 컴파일 비용이 아니다(0.5 ms).
|
|
48
|
+
- 비용은 ADR-0093의 「joint 기록으로 노드를 다시 만들어 보유한 노드와 대조」에 있다. joint마다 `writeJoint`를 되풀이하고, `dropIfUnused`가 호출마다 `stringsIn`으로 occupancy·capabilities·joints 전체의 문자열을 새로 모아 joint 수에 제곱으로 늘어난다.
|
|
49
|
+
- `stringsIn`을 배열 할당 없는 순회로 바꿨다(figure-model 8085989). 컴파일 중앙값 23.47 → 18.25 ms(−22 %, 최솟값 22.6 → 15.7 ms), 시험 806건 통과. 계약 변화 없음. 복사본에서 먼저 쟀을 때는 20.56 → 14.98 ms(−27 %)였고, 이 머신은 변동이 커서 중앙값으로 읽는다.
|
|
50
|
+
- `dropIfUnused` 재귀가 `declared` 집합을 공유하게 하는 시도는 효과가 없었다(15.16 ms). 재귀가 얕다.
|
|
51
|
+
- 수정 뒤에도 `checkFigureJoints`가 61 %로 남는다.
|
|
52
|
+
|
|
53
|
+
## 실행 상태
|
|
54
|
+
|
|
55
|
+
| 항목 | 상태 |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| 워크스페이스 파생 기억·횟수 계측·예산 시험 | figure-model 0.4.1 발행 |
|
|
58
|
+
| 화면 쪽 정리(파싱 1회, `view.geometry` 심기, 미리보기·검사 디바운스, 안 보이는 패널 건너뛰기) | things-factory v10 커밋 둘, 미발행 |
|
|
59
|
+
| `stringsIn` 비할당 순회 | figure-model 8085989 커밋(시험 806 통과), 미발행 |
|
|
60
|
+
| joint 대조 줄이기, 컴파일 결과 기억 | ADR-0119 안건, 미결정 |
|