@rslsp1/fa-app-tools 10.0.1 → 10.3.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.
@@ -0,0 +1,218 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/lib/szenen/cameraContract.ts
2
+ var CAMERA_ASPECT_RATIOS = ["1:1", "4:3", "3:4", "16:9", "9:16"];
3
+ var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
4
+ function cameraAspectRatioValue(aspectRatio) {
5
+ if (!/^[1-9][0-9]*(\.[0-9]+)?:[1-9][0-9]*(\.[0-9]+)?$/.test(aspectRatio)) {
6
+ throw new Error(`Ung\xFCltiges Kamera-Seitenverh\xE4ltnis \u201E${aspectRatio}\u201C.`);
7
+ }
8
+ const [width, height] = aspectRatio.split(":").map(Number);
9
+ const ratio = width / height;
10
+ if (!Number.isFinite(width) || !Number.isFinite(height) || !Number.isFinite(ratio) || ratio <= 0) {
11
+ throw new Error(`Kamera-Seitenverh\xE4ltnis \u201E${aspectRatio}\u201C ist nicht darstellbar.`);
12
+ }
13
+ return ratio;
14
+ }
15
+ function canonical(value) {
16
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
17
+ const record = object(value);
18
+ if (record) return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonical(record[key])}`).join(",")}}`;
19
+ return _nullishCoalesce(JSON.stringify(value), () => ( "undefined"));
20
+ }
21
+ function camerasOf(payload) {
22
+ const cameras = _optionalChain([object, 'call', _ => _(_optionalChain([object, 'call', _2 => _2(payload), 'optionalAccess', _3 => _3.camera_rig])), 'optionalAccess', _4 => _4.cameras]);
23
+ return Array.isArray(cameras) ? cameras : [];
24
+ }
25
+ function checkCameraAspectRatioChanges(type, payload, previousPayloads = []) {
26
+ if (type !== "scene_setup") return [];
27
+ const previous = previousPayloads.flatMap(camerasOf);
28
+ return camerasOf(payload).flatMap((value, index) => {
29
+ const camera = object(value);
30
+ if (!camera) return [];
31
+ if (typeof camera.aspect_ratio === "string") {
32
+ try {
33
+ cameraAspectRatioValue(camera.aspect_ratio);
34
+ return [];
35
+ } catch (error) {
36
+ return [{ instancePath: `/camera_rig/cameras/${index}/aspect_ratio`, keyword: "aspect_ratio", message: error.message }];
37
+ }
38
+ }
39
+ if (camera.aspect_ratio === void 0 && previous.some((old) => canonical(old) === canonical(camera))) return [];
40
+ return [{
41
+ instancePath: `/camera_rig/cameras/${index}/aspect_ratio`,
42
+ keyword: "required",
43
+ message: `Kamera \u201E${String(_nullishCoalesce(camera.camera_id, () => ( index)))}\u201C wurde neu angelegt oder ge\xE4ndert. Bitte ihr Seitenverh\xE4ltnis ausdr\xFCcklich speichern.`
44
+ }];
45
+ });
46
+ }
47
+ function cameraPerspective(camera) {
48
+ if (!camera.aspect_ratio) throw new Error(`Kamera \u201E${camera.camera_id}\u201C hat kein gespeichertes Seitenverh\xE4ltnis.`);
49
+ const lens = object(_optionalChain([object, 'call', _5 => _5(camera.preset), 'optionalAccess', _6 => _6.lens]));
50
+ const focal = _optionalChain([lens, 'optionalAccess', _7 => _7.focal_length_mm]);
51
+ const sensor = _optionalChain([lens, 'optionalAccess', _8 => _8.sensor_width_mm]);
52
+ if (typeof focal !== "number" || !Number.isFinite(focal) || focal <= 0 || typeof sensor !== "number" || !Number.isFinite(sensor) || sensor <= 0) {
53
+ throw new Error(`Kamera \u201E${camera.camera_id}\u201C hat kein aufgel\xF6stes Objektiv mit Brennweite und Sensorbreite.`);
54
+ }
55
+ if (_optionalChain([object, 'call', _9 => _9(camera.preset), 'optionalAccess', _10 => _10.projection]) !== "perspective") {
56
+ throw new Error(`Kamera \u201E${camera.camera_id}\u201C verwendet keine perspektivische Projektion.`);
57
+ }
58
+ const aspect = cameraAspectRatioValue(camera.aspect_ratio);
59
+ return {
60
+ aspect_ratio: camera.aspect_ratio,
61
+ aspect,
62
+ focal_length_mm: focal,
63
+ sensor_width_mm: sensor,
64
+ vertical_fov_deg: 2 * Math.atan(sensor / (2 * focal * aspect)) * 180 / Math.PI
65
+ };
66
+ }
67
+ function frozenCameraAspectRatio(input) {
68
+ const aspect = _optionalChain([object, 'call', _11 => _11(_optionalChain([object, 'call', _12 => _12(input), 'optionalAccess', _13 => _13.camera])), 'optionalAccess', _14 => _14.aspect_ratio]);
69
+ if (aspect === void 0) return void 0;
70
+ if (typeof aspect !== "string") throw new Error("Das eingefrorene Kamera-Seitenverh\xE4ltnis ist kein Text.");
71
+ cameraAspectRatioValue(aspect);
72
+ return aspect;
73
+ }
74
+
75
+ // src/lib/szenen/stage3d.ts
76
+ var STAGE_CATALOGUE = [
77
+ { label: "Mensch", type: "subject", dimensions: [0.55, 0.35, 1.75] },
78
+ { label: "Stuhl", type: "object", dimensions: [0.5, 0.5, 0.9] },
79
+ { label: "Tisch", type: "surface", dimensions: [1.2, 0.7, 0.75] },
80
+ { label: "Lampe", type: "light", dimensions: [0.35, 0.35, 1.5] }
81
+ ];
82
+ var stageColor = (type) => _nullishCoalesce(({ subject: "#df995f", light: "#ffe084", surface: "#65aabc", object: "#b998d9" })[type], () => ( "#9bafbc"));
83
+ function stageColors(nodes) {
84
+ const result = /* @__PURE__ */ Object.create(null);
85
+ const used = /* @__PURE__ */ new Set();
86
+ const names = { subject: "orange", light: "yellow", surface: "cyan", object: "purple" };
87
+ let next = 0;
88
+ for (const node of [...nodes].sort((a, b) => a.node_id.localeCompare(b.node_id))) {
89
+ let hex = stageColor(node.type), name = _nullishCoalesce(names[node.type], () => ( "blue grey"));
90
+ while (used.has(hex)) {
91
+ const hue = (next++ * 137.508 + 25) % 360;
92
+ const channel = (n) => {
93
+ const k = (n + hue / 30) % 12;
94
+ return Math.round(255 * (0.62 - 0.29 * Math.max(-1, Math.min(k - 3, 9 - k, 1)))).toString(16).padStart(2, "0");
95
+ };
96
+ hex = `#${channel(0)}${channel(8)}${channel(4)}`;
97
+ name = `${["red", "orange", "yellow", "green", "cyan", "blue", "purple", "pink"][Math.round(hue / 45) % 8]} (${hex})`;
98
+ }
99
+ used.add(hex);
100
+ result[node.node_id] = { hex, name };
101
+ }
102
+ return result;
103
+ }
104
+ var stageTypeLabel = (type) => _nullishCoalesce(({ subject: "Person", light: "Licht", surface: "Fl\xE4che", object: "Objekt" })[type], () => ( type));
105
+ function vector3(value, label) {
106
+ if (!Array.isArray(value) || value.length !== 3 || value.some((n) => typeof n !== "number" || !Number.isFinite(n))) {
107
+ throw new Error(`${label}: drei endliche Koordinaten erforderlich.`);
108
+ }
109
+ return [...value];
110
+ }
111
+ function dragPosition(position, point, plane) {
112
+ const p = vector3(position, "Position");
113
+ const q = vector3(point, "Drag");
114
+ return plane === "top" ? [q[0], q[1], p[2]] : plane === "side" ? [q[0], p[1], q[2]] : p;
115
+ }
116
+ function stageNode(node) {
117
+ if (!node.placement) throw new Error(`\u201E${node.node_id}\u201C hat keine Weltplatzierung.`);
118
+ if (!node.proxy_3d) throw new Error(`\u201E${node.node_id}\u201C hat keine Proxy-Geometrie. Bitte Ma\xDFe festlegen.`);
119
+ const dimensions = vector3(node.proxy_3d.dimensions, `Ma\xDFe von ${node.node_id}`);
120
+ if (dimensions.some((d) => d <= 0)) throw new Error(`\u201E${node.node_id}\u201C braucht positive Proxy-Ma\xDFe.`);
121
+ return {
122
+ node_id: node.node_id,
123
+ type: node.type,
124
+ primitive: node.proxy_3d.primitive,
125
+ dimensions,
126
+ position: vector3(node.placement.position, `Position von ${node.node_id}`),
127
+ rotation: vector3(_nullishCoalesce(node.placement.rotation_euler_deg, () => ( [0, 0, 0])), "Rotation"),
128
+ scale: vector3(_nullishCoalesce(node.placement.scale, () => ( [1, 1, 1])), "Skalierung"),
129
+ anchors: node.anchors
130
+ };
131
+ }
132
+ function stageFrame(input) {
133
+ if (input.capabilities.can_place !== "yes") throw new Error("Die Szene ben\xF6tigt Meterma\xDFe und ein Scene Setup in Z-up-Koordinaten.");
134
+ const visible = input.scene.nodes.filter((n) => !n.hidden);
135
+ const colors = stageColors(visible);
136
+ const nodes = visible.map((n) => ({ ...stageNode(n), preview_color: colors[n.node_id] }));
137
+ if (!input.camera) throw new Error("Bitte eine Kamera ausw\xE4hlen.");
138
+ const optical = cameraPerspective(input.camera);
139
+ const placement = input.camera.placement;
140
+ if (_optionalChain([placement, 'optionalAccess', _15 => _15.mode]) !== "absolute") throw new Error("Diese Kamera verwendet eine Pattern-Platzierung. F\xFCr den MVP bitte eine explizite Weltposition speichern.");
141
+ const position = vector3(placement.position, "Kameraposition");
142
+ const orientation = input.camera.orientation;
143
+ if (_optionalChain([orientation, 'optionalAccess', _16 => _16.mode]) !== "explicit" && _optionalChain([orientation, 'optionalAccess', _17 => _17.mode]) !== "look_at") throw new Error("Bitte eine explizite Kameraausrichtung oder ein Blickziel festlegen.");
144
+ if (orientation.mode === "explicit") vector3(orientation.rotation_euler_deg, "Kameraausrichtung");
145
+ return { nodes, camera: { ...input.camera, ...optical, position, orientation } };
146
+ }
147
+ function planeAxes(plane) {
148
+ return plane === "top" ? [0, 1] : [0, 2];
149
+ }
150
+ function snapPosition(position, plane, step) {
151
+ const p = vector3(position, "Position");
152
+ for (const axis of planeAxes(plane)) p[axis] = Math.round(p[axis] / step) * step;
153
+ return p.map((v) => Number(v.toFixed(6)));
154
+ }
155
+ function nudgePosition(position, plane, right, up) {
156
+ const p = vector3(position, "Position");
157
+ const [u, v] = planeAxes(plane);
158
+ p[u] = Number((p[u] + right).toFixed(6));
159
+ p[v] = Number((p[v] + up).toFixed(6));
160
+ return p;
161
+ }
162
+ function fitPlaneView(points, plane, width, height) {
163
+ if (!points.length || width <= 0 || height <= 0) return { center: [0, 0], zoom: 60 };
164
+ const [u, v] = planeAxes(plane);
165
+ const us = points.map((p) => p[u]), vs = points.map((p) => p[v]);
166
+ const [minU, maxU, minV, maxV] = [Math.min(...us), Math.max(...us), Math.min(...vs), Math.max(...vs)];
167
+ const spanU = Math.max(maxU - minU, 2), spanV = Math.max(maxV - minV, 2);
168
+ const zoom = Math.min(width / (spanU * 1.25), height / (spanV * 1.25));
169
+ return { center: [(minU + maxU) / 2, (minV + maxV) / 2], zoom: clampZoom(zoom) };
170
+ }
171
+ var clampZoom = (zoom) => Math.min(800, Math.max(8, zoom));
172
+ function screenToPlane(view, dx, dy) {
173
+ return [view.center[0] + dx / view.zoom, view.center[1] - dy / view.zoom];
174
+ }
175
+ function zoomPlaneView(view, factor, dx, dy) {
176
+ const zoom = clampZoom(view.zoom * factor);
177
+ const [u, v] = screenToPlane(view, dx, dy);
178
+ return { zoom, center: [u - dx / zoom, v + dy / zoom] };
179
+ }
180
+ function gridStep(zoom, minPx = 14) {
181
+ return _nullishCoalesce([0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 25, 50].find((step) => step * zoom >= minPx), () => ( 100));
182
+ }
183
+ function withStagePositions(input, nodes, camera) {
184
+ if (!nodes.size && !camera) return input;
185
+ const next = {
186
+ ...input,
187
+ scene: { ...input.scene, nodes: input.scene.nodes.map((n) => nodes.has(n.node_id) && n.placement ? { ...n, placement: { ...n.placement, position: nodes.get(n.node_id) } } : n) }
188
+ };
189
+ if (camera && input.camera) next.camera = { ...input.camera, placement: { ...input.camera.placement, position: camera } };
190
+ return next;
191
+ }
192
+ var roundMeters = (value) => Math.round(value * 1e3) / 1e3;
193
+
194
+
195
+
196
+
197
+
198
+
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+
208
+
209
+
210
+
211
+
212
+
213
+
214
+
215
+
216
+
217
+
218
+ exports.CAMERA_ASPECT_RATIOS = CAMERA_ASPECT_RATIOS; exports.cameraAspectRatioValue = cameraAspectRatioValue; exports.checkCameraAspectRatioChanges = checkCameraAspectRatioChanges; exports.cameraPerspective = cameraPerspective; exports.frozenCameraAspectRatio = frozenCameraAspectRatio; exports.STAGE_CATALOGUE = STAGE_CATALOGUE; exports.stageColor = stageColor; exports.stageColors = stageColors; exports.stageTypeLabel = stageTypeLabel; exports.vector3 = vector3; exports.dragPosition = dragPosition; exports.stageNode = stageNode; exports.stageFrame = stageFrame; exports.planeAxes = planeAxes; exports.snapPosition = snapPosition; exports.nudgePosition = nudgePosition; exports.fitPlaneView = fitPlaneView; exports.clampZoom = clampZoom; exports.screenToPlane = screenToPlane; exports.zoomPlaneView = zoomPlaneView; exports.gridStep = gridStep; exports.withStagePositions = withStagePositions; exports.roundMeters = roundMeters;
@@ -0,0 +1,157 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/lib/szenen/versionDag.ts
2
+ var VersionDagError = class extends Error {
3
+ };
4
+ function buildVersionDag(versions) {
5
+ if (versions.length === 0) {
6
+ throw new VersionDagError("Versions-DAG ohne Versionen ist nicht aufbaubar.");
7
+ }
8
+ const elementId = versions[0].element_id;
9
+ const nodes = /* @__PURE__ */ new Map();
10
+ const children = /* @__PURE__ */ new Map();
11
+ for (const version of versions) {
12
+ if (!version.version_id) {
13
+ throw new VersionDagError("Version ohne version_id.");
14
+ }
15
+ if (version.element_id !== elementId) {
16
+ throw new VersionDagError(
17
+ `Version ${version.version_id} gehoert zu Element ${version.element_id}, erwartet ${elementId}. Ein DAG umfasst genau ein Element.`
18
+ );
19
+ }
20
+ if (nodes.has(version.version_id)) {
21
+ throw new VersionDagError(`Version ${version.version_id} kommt doppelt vor.`);
22
+ }
23
+ nodes.set(version.version_id, version);
24
+ if (!children.has(version.version_id)) children.set(version.version_id, []);
25
+ }
26
+ for (const version of versions) {
27
+ const seenParents = /* @__PURE__ */ new Set();
28
+ for (const link of version.parents) {
29
+ if (link.parent_version_id === version.version_id) {
30
+ throw new VersionDagError(`Version ${version.version_id} ist ihr eigener Parent.`);
31
+ }
32
+ if (!nodes.has(link.parent_version_id)) {
33
+ throw new VersionDagError(
34
+ `Version ${version.version_id} verweist auf unbekannten Parent ${link.parent_version_id}. Der Graph waere unvollstaendig.`
35
+ );
36
+ }
37
+ if (seenParents.has(link.parent_version_id)) {
38
+ throw new VersionDagError(
39
+ `Version ${version.version_id} nennt Parent ${link.parent_version_id} doppelt.`
40
+ );
41
+ }
42
+ seenParents.add(link.parent_version_id);
43
+ children.get(link.parent_version_id).push(version.version_id);
44
+ }
45
+ }
46
+ assertAcyclic(nodes);
47
+ const versionIds = versions.map((v) => v.version_id);
48
+ const closure = (start, step) => {
49
+ const seen = /* @__PURE__ */ new Set();
50
+ const stack = [...step(start)];
51
+ while (stack.length > 0) {
52
+ const current = stack.pop();
53
+ if (seen.has(current)) continue;
54
+ seen.add(current);
55
+ stack.push(...step(current));
56
+ }
57
+ return seen;
58
+ };
59
+ const parentIdsOf = (id) => (_nullishCoalesce(_optionalChain([nodes, 'access', _ => _.get, 'call', _2 => _2(id), 'optionalAccess', _3 => _3.parents]), () => ( []))).map((p) => p.parent_version_id);
60
+ const childIdsOf = (id) => _nullishCoalesce(children.get(id), () => ( []));
61
+ return {
62
+ elementId,
63
+ versionIds,
64
+ get: (versionId) => nodes.get(versionId),
65
+ parentsOf: (versionId) => _nullishCoalesce(_optionalChain([nodes, 'access', _4 => _4.get, 'call', _5 => _5(versionId), 'optionalAccess', _6 => _6.parents]), () => ( [])),
66
+ childrenOf: (versionId) => childIdsOf(versionId),
67
+ heads: () => versionIds.filter((id) => childIdsOf(id).length === 0),
68
+ roots: () => versionIds.filter((id) => parentIdsOf(id).length === 0),
69
+ hasFork() {
70
+ return this.heads().length > 1;
71
+ },
72
+ ancestorsOf: (versionId) => closure(versionId, parentIdsOf),
73
+ descendantsOf: (versionId) => closure(versionId, childIdsOf),
74
+ isAncestorOf(candidate, versionId) {
75
+ return this.ancestorsOf(versionId).has(candidate);
76
+ }
77
+ };
78
+ }
79
+ function assertAcyclic(nodes) {
80
+ const OPEN = 1;
81
+ const DONE = 2;
82
+ const state = /* @__PURE__ */ new Map();
83
+ for (const start of nodes.keys()) {
84
+ if (state.get(start) === DONE) continue;
85
+ const stack = [
86
+ { id: start, next: 0, path: [start] }
87
+ ];
88
+ state.set(start, OPEN);
89
+ while (stack.length > 0) {
90
+ const frame = stack[stack.length - 1];
91
+ const parents = nodes.get(frame.id).parents;
92
+ if (frame.next >= parents.length) {
93
+ state.set(frame.id, DONE);
94
+ stack.pop();
95
+ continue;
96
+ }
97
+ const parentId = parents[frame.next++].parent_version_id;
98
+ const parentState = state.get(parentId);
99
+ if (parentState === OPEN) {
100
+ throw new VersionDagError(
101
+ `Zyklus im Versions-DAG: ${[...frame.path, parentId].join(" -> ")}`
102
+ );
103
+ }
104
+ if (parentState !== DONE) {
105
+ state.set(parentId, OPEN);
106
+ stack.push({ id: parentId, next: 0, path: [...frame.path, parentId] });
107
+ }
108
+ }
109
+ }
110
+ }
111
+ function resolvePreferredHead(options) {
112
+ const { dag, workingContextId, inheritanceChain = [], owningContextId, selections = [] } = options;
113
+ const heads = dag.heads();
114
+ const ignoredSelections = [];
115
+ const byContext = /* @__PURE__ */ new Map();
116
+ for (const selection of selections) {
117
+ if (!dag.get(selection.version_id)) {
118
+ ignoredSelections.push(selection);
119
+ continue;
120
+ }
121
+ if (!byContext.has(selection.context_id)) byContext.set(selection.context_id, selection);
122
+ }
123
+ const candidates = [
124
+ { contextId: workingContextId, source: "context" },
125
+ ...inheritanceChain.map((contextId) => ({ contextId, source: "inherited" })),
126
+ ...owningContextId ? [{ contextId: owningContextId, source: "owning" }] : []
127
+ ];
128
+ for (const candidate of candidates) {
129
+ const selection = byContext.get(candidate.contextId);
130
+ if (!selection) continue;
131
+ return {
132
+ resolution: {
133
+ kind: "selected",
134
+ versionId: selection.version_id,
135
+ source: candidate.source,
136
+ contextId: candidate.contextId,
137
+ heads,
138
+ stale: !heads.includes(selection.version_id)
139
+ },
140
+ ignoredSelections
141
+ };
142
+ }
143
+ if (heads.length === 1) {
144
+ return { resolution: { kind: "single", versionId: heads[0], heads }, ignoredSelections };
145
+ }
146
+ return { resolution: { kind: "fork", heads }, ignoredSelections };
147
+ }
148
+ function preferredVersionId(resolution) {
149
+ return resolution.kind === "fork" ? null : resolution.versionId;
150
+ }
151
+
152
+
153
+
154
+
155
+
156
+
157
+ exports.VersionDagError = VersionDagError; exports.buildVersionDag = buildVersionDag; exports.resolvePreferredHead = resolvePreferredHead; exports.preferredVersionId = preferredVersionId;