@rslsp1/fa-app-tools 10.3.2 → 10.3.4
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/StageEngine-O5I654LD.js +1243 -0
- package/dist/StageEngine-PYWITIIY.mjs +1243 -0
- package/dist/{chunk-ACB2543O.js → chunk-DDH2SGZM.js} +113 -20
- package/dist/{chunk-TFWIMFNF.mjs → chunk-GKLCL2VQ.mjs} +111 -18
- package/dist/{chunk-HFX6D53W.js → chunk-VSHSZEGV.js} +1810 -606
- package/dist/{chunk-JP7LIWDR.mjs → chunk-XLNA2BD6.mjs} +1448 -244
- package/dist/index.d.mts +107 -2
- package/dist/index.d.ts +107 -2
- package/dist/index.js +437 -108
- package/dist/index.mjs +703 -374
- package/dist/szenen.d.mts +610 -279
- package/dist/szenen.d.ts +610 -279
- package/dist/szenen.js +75 -29
- package/dist/szenen.mjs +48 -2
- package/package.json +1 -1
- package/dist/StageEngine-3MOBM2WX.mjs +0 -590
- package/dist/StageEngine-5VR3KEZB.js +0 -590
|
@@ -74,33 +74,102 @@ function frozenCameraAspectRatio(input) {
|
|
|
74
74
|
|
|
75
75
|
// src/lib/szenen/stage3d.ts
|
|
76
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] }
|
|
77
|
+
{ label: "Mensch", type: "subject", dimensions: [0.55, 0.35, 1.75], primitive: "humanoid_proxy", pose_ref: "standing" },
|
|
78
|
+
{ label: "Stuhl", type: "object", dimensions: [0.5, 0.5, 0.9], primitive: "furniture_proxy", variant: "chair" },
|
|
79
|
+
{ label: "Tisch", type: "surface", dimensions: [1.2, 0.7, 0.75], primitive: "furniture_proxy", variant: "table" },
|
|
80
|
+
{ label: "Lampe", type: "light", dimensions: [0.35, 0.35, 1.5], primitive: "furniture_proxy", variant: "floor_lamp" },
|
|
81
|
+
{ label: "Raum", type: "object", dimensions: [5, 4, 2.8], primitive: "room_shell" }
|
|
81
82
|
];
|
|
82
83
|
var stageColor = (type) => _nullishCoalesce(({ subject: "#df995f", light: "#ffe084", surface: "#65aabc", object: "#b998d9" })[type], () => ( "#9bafbc"));
|
|
84
|
+
var PREVIEW_COLOR_PATTERN = /^#[0-9a-f]{6}$/;
|
|
85
|
+
var PREVIEW_COLOR_MIN_DISTANCE = 75;
|
|
86
|
+
function normalizePreviewColor(value) {
|
|
87
|
+
if (typeof value !== "string") return null;
|
|
88
|
+
const hex = value.trim().toLowerCase();
|
|
89
|
+
return PREVIEW_COLOR_PATTERN.test(hex) ? hex : null;
|
|
90
|
+
}
|
|
91
|
+
function rgb(hex) {
|
|
92
|
+
return [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
|
|
93
|
+
}
|
|
94
|
+
function previewColorDistance(a, b) {
|
|
95
|
+
const [r1, g1, b1] = rgb(a), [r2, g2, b2] = rgb(b);
|
|
96
|
+
const r = (r1 + r2) / 2, dr = r1 - r2, dg = g1 - g2, db = b1 - b2;
|
|
97
|
+
return Math.sqrt((2 + r / 256) * dr * dr + 4 * dg * dg + (2 + (255 - r) / 256) * db * db);
|
|
98
|
+
}
|
|
99
|
+
var HUE_NAMES = [
|
|
100
|
+
[15, "red"],
|
|
101
|
+
[40, "orange"],
|
|
102
|
+
[70, "yellow"],
|
|
103
|
+
[160, "green"],
|
|
104
|
+
[200, "cyan"],
|
|
105
|
+
[255, "blue"],
|
|
106
|
+
[290, "purple"],
|
|
107
|
+
[345, "pink"],
|
|
108
|
+
[360, "red"]
|
|
109
|
+
];
|
|
110
|
+
function previewColorName(hex) {
|
|
111
|
+
const [r, g, b] = rgb(hex).map((c) => c / 255);
|
|
112
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b), d = max - min;
|
|
113
|
+
if (d < 0.08) return `${max > 0.8 ? "white" : max < 0.25 ? "black" : "grey"} (${hex})`;
|
|
114
|
+
const hue = max === r ? ((g - b) / d + 6) % 6 : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
115
|
+
const grad = hue * 60;
|
|
116
|
+
const l = (max + min) / 2;
|
|
117
|
+
const stufe = l < 0.3 ? "dark " : l > 0.82 ? "light " : "";
|
|
118
|
+
return `${stufe}${HUE_NAMES.find(([grenze]) => grad < grenze)[1]} (${hex})`;
|
|
119
|
+
}
|
|
120
|
+
function fallbackCandidate(n) {
|
|
121
|
+
const hue = (n * 137.508 + 25) % 360;
|
|
122
|
+
const channel = (k0) => {
|
|
123
|
+
const k = (k0 + hue / 30) % 12;
|
|
124
|
+
return Math.round(255 * (0.62 - 0.29 * Math.max(-1, Math.min(k - 3, 9 - k, 1)))).toString(16).padStart(2, "0");
|
|
125
|
+
};
|
|
126
|
+
return `#${channel(0)}${channel(8)}${channel(4)}`;
|
|
127
|
+
}
|
|
83
128
|
function stageColors(nodes) {
|
|
84
129
|
const result = /* @__PURE__ */ Object.create(null);
|
|
85
|
-
const used =
|
|
130
|
+
const used = [];
|
|
86
131
|
const names = { subject: "orange", light: "yellow", surface: "cyan", object: "purple" };
|
|
132
|
+
for (const node of nodes) {
|
|
133
|
+
const hex = normalizePreviewColor(_optionalChain([node, 'access', _15 => _15.proxy_3d, 'optionalAccess', _16 => _16.preview_color]));
|
|
134
|
+
if (hex) {
|
|
135
|
+
used.push(hex);
|
|
136
|
+
result[node.node_id] = { hex, name: previewColorName(hex), explicit: true };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const nah = (hex) => used.some((u) => previewColorDistance(u, hex) < PREVIEW_COLOR_MIN_DISTANCE);
|
|
87
140
|
let next = 0;
|
|
88
|
-
for (const node of [...nodes].sort((a, b) => a.node_id.localeCompare(b.node_id))) {
|
|
141
|
+
for (const node of [...nodes].filter((n) => !result[n.node_id]).sort((a, b) => a.node_id.localeCompare(b.node_id))) {
|
|
89
142
|
let hex = stageColor(node.type), name = _nullishCoalesce(names[node.type], () => ( "blue grey"));
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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})`;
|
|
143
|
+
for (let tries = 0; nah(hex) && tries < 64; tries++) {
|
|
144
|
+
hex = fallbackCandidate(next++);
|
|
145
|
+
name = previewColorName(hex);
|
|
98
146
|
}
|
|
99
|
-
used.
|
|
100
|
-
result[node.node_id] = { hex, name };
|
|
147
|
+
used.push(hex);
|
|
148
|
+
result[node.node_id] = { hex, name, explicit: false };
|
|
101
149
|
}
|
|
102
150
|
return result;
|
|
103
151
|
}
|
|
152
|
+
function previewColorLegibility(hex) {
|
|
153
|
+
const [r, g, b] = rgb(hex).map((c) => c / 255);
|
|
154
|
+
const l = (Math.max(r, g, b) + Math.min(r, g, b)) / 2;
|
|
155
|
+
return l < 0.3 ? "too_dark" : l > 0.85 ? "too_light" : null;
|
|
156
|
+
}
|
|
157
|
+
function previewColorConflicts(nodes) {
|
|
158
|
+
const colors = stageColors(nodes);
|
|
159
|
+
const ids = Object.keys(colors).sort();
|
|
160
|
+
const out = [];
|
|
161
|
+
for (let i = 0; i < ids.length; i++) for (let j = i + 1; j < ids.length; j++) {
|
|
162
|
+
const a = colors[ids[i]].hex, b = colors[ids[j]].hex, distance = previewColorDistance(a, b);
|
|
163
|
+
if (distance < PREVIEW_COLOR_MIN_DISTANCE) out.push({ node_ids: [ids[i], ids[j]], hexes: [a, b], distance: Math.round(distance), identical: a === b });
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
function distinctPreviewColor(type, taken) {
|
|
168
|
+
const nah = (hex2) => taken.some((u) => previewColorDistance(u, hex2) < PREVIEW_COLOR_MIN_DISTANCE);
|
|
169
|
+
let hex = stageColor(type);
|
|
170
|
+
for (let n = 0; nah(hex) && n < 64; n++) hex = fallbackCandidate(n);
|
|
171
|
+
return hex;
|
|
172
|
+
}
|
|
104
173
|
var stageTypeLabel = (type) => _nullishCoalesce(({ subject: "Person", light: "Licht", surface: "Fl\xE4che", object: "Objekt" })[type], () => ( type));
|
|
105
174
|
function vector3(value, label) {
|
|
106
175
|
if (!Array.isArray(value) || value.length !== 3 || value.some((n) => typeof n !== "number" || !Number.isFinite(n))) {
|
|
@@ -123,6 +192,9 @@ function stageNode(node) {
|
|
|
123
192
|
type: node.type,
|
|
124
193
|
primitive: node.proxy_3d.primitive,
|
|
125
194
|
dimensions,
|
|
195
|
+
variant: node.proxy_3d.variant,
|
|
196
|
+
pose_ref: node.proxy_3d.pose_ref,
|
|
197
|
+
morph: node.proxy_3d.morph,
|
|
126
198
|
position: vector3(node.placement.position, `Position von ${node.node_id}`),
|
|
127
199
|
rotation: vector3(_nullishCoalesce(node.placement.rotation_euler_deg, () => ( [0, 0, 0])), "Rotation"),
|
|
128
200
|
scale: vector3(_nullishCoalesce(node.placement.scale, () => ( [1, 1, 1])), "Skalierung"),
|
|
@@ -133,14 +205,14 @@ function stageFrame(input) {
|
|
|
133
205
|
if (input.capabilities.can_place !== "yes") throw new Error("Die Szene ben\xF6tigt Meterma\xDFe und ein Scene Setup in Z-up-Koordinaten.");
|
|
134
206
|
const visible = input.scene.nodes.filter((n) => !n.hidden);
|
|
135
207
|
const colors = stageColors(visible);
|
|
136
|
-
const nodes = visible.map((n) => ({ ...stageNode(n), preview_color: colors[n.node_id] }));
|
|
208
|
+
const nodes = visible.map((n) => ({ ...stageNode(n), preview_color: { hex: colors[n.node_id].hex, name: colors[n.node_id].name } }));
|
|
137
209
|
if (!input.camera) throw new Error("Bitte eine Kamera ausw\xE4hlen.");
|
|
138
210
|
const optical = cameraPerspective(input.camera);
|
|
139
211
|
const placement = input.camera.placement;
|
|
140
|
-
if (_optionalChain([placement, 'optionalAccess',
|
|
212
|
+
if (_optionalChain([placement, 'optionalAccess', _17 => _17.mode]) !== "absolute") throw new Error("Diese Kamera verwendet eine Pattern-Platzierung. F\xFCr den MVP bitte eine explizite Weltposition speichern.");
|
|
141
213
|
const position = vector3(placement.position, "Kameraposition");
|
|
142
214
|
const orientation = input.camera.orientation;
|
|
143
|
-
if (_optionalChain([orientation, 'optionalAccess',
|
|
215
|
+
if (_optionalChain([orientation, 'optionalAccess', _18 => _18.mode]) !== "explicit" && _optionalChain([orientation, 'optionalAccess', _19 => _19.mode]) !== "look_at") throw new Error("Bitte eine explizite Kameraausrichtung oder ein Blickziel festlegen.");
|
|
144
216
|
if (orientation.mode === "explicit") vector3(orientation.rotation_euler_deg, "Kameraausrichtung");
|
|
145
217
|
return { nodes, camera: { ...input.camera, ...optical, position, orientation } };
|
|
146
218
|
}
|
|
@@ -190,6 +262,27 @@ function withStagePositions(input, nodes, camera) {
|
|
|
190
262
|
return next;
|
|
191
263
|
}
|
|
192
264
|
var roundMeters = (value) => Math.round(value * 1e3) / 1e3;
|
|
265
|
+
function facingRotationZ(position, target) {
|
|
266
|
+
const dx = target[0] - position[0], dy = target[1] - position[1];
|
|
267
|
+
if (!Number.isFinite(dx) || !Number.isFinite(dy) || Math.hypot(dx, dy) < 1e-8) throw new Error("F\xFCr die Ausrichtung m\xFCssen Quelle und Ziel unterschiedliche Bodenpositionen haben.");
|
|
268
|
+
return Math.round(Math.atan2(dx, -dy) * 180 / Math.PI * 1e3) / 1e3;
|
|
269
|
+
}
|
|
270
|
+
var snapRotationZ = (degrees) => Math.round(degrees / 15) * 15;
|
|
271
|
+
function stagePreviewResolution(aspectRatio) {
|
|
272
|
+
const [rw, rh] = aspectRatio.split(":").map(Number), scale = 768 / Math.max(rw, rh);
|
|
273
|
+
const width = Math.round(rw * scale), height = Math.round(rh * scale);
|
|
274
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width < 1 || height < 1 || Math.abs(width / height - rw / rh) > 1e-9) throw new Error("Dieses Kameraformat l\xE4sst sich mit der Preview-Aufl\xF6sung nicht exakt abbilden. Bitte ein Format-Preset w\xE4hlen.");
|
|
275
|
+
return { width, height };
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
193
286
|
|
|
194
287
|
|
|
195
288
|
|
|
@@ -215,4 +308,4 @@ var roundMeters = (value) => Math.round(value * 1e3) / 1e3;
|
|
|
215
308
|
|
|
216
309
|
|
|
217
310
|
|
|
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;
|
|
311
|
+
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.PREVIEW_COLOR_MIN_DISTANCE = PREVIEW_COLOR_MIN_DISTANCE; exports.normalizePreviewColor = normalizePreviewColor; exports.previewColorDistance = previewColorDistance; exports.stageColors = stageColors; exports.previewColorLegibility = previewColorLegibility; exports.previewColorConflicts = previewColorConflicts; exports.distinctPreviewColor = distinctPreviewColor; 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; exports.facingRotationZ = facingRotationZ; exports.snapRotationZ = snapRotationZ; exports.stagePreviewResolution = stagePreviewResolution;
|
|
@@ -74,33 +74,102 @@ function frozenCameraAspectRatio(input) {
|
|
|
74
74
|
|
|
75
75
|
// src/lib/szenen/stage3d.ts
|
|
76
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] }
|
|
77
|
+
{ label: "Mensch", type: "subject", dimensions: [0.55, 0.35, 1.75], primitive: "humanoid_proxy", pose_ref: "standing" },
|
|
78
|
+
{ label: "Stuhl", type: "object", dimensions: [0.5, 0.5, 0.9], primitive: "furniture_proxy", variant: "chair" },
|
|
79
|
+
{ label: "Tisch", type: "surface", dimensions: [1.2, 0.7, 0.75], primitive: "furniture_proxy", variant: "table" },
|
|
80
|
+
{ label: "Lampe", type: "light", dimensions: [0.35, 0.35, 1.5], primitive: "furniture_proxy", variant: "floor_lamp" },
|
|
81
|
+
{ label: "Raum", type: "object", dimensions: [5, 4, 2.8], primitive: "room_shell" }
|
|
81
82
|
];
|
|
82
83
|
var stageColor = (type) => ({ subject: "#df995f", light: "#ffe084", surface: "#65aabc", object: "#b998d9" })[type] ?? "#9bafbc";
|
|
84
|
+
var PREVIEW_COLOR_PATTERN = /^#[0-9a-f]{6}$/;
|
|
85
|
+
var PREVIEW_COLOR_MIN_DISTANCE = 75;
|
|
86
|
+
function normalizePreviewColor(value) {
|
|
87
|
+
if (typeof value !== "string") return null;
|
|
88
|
+
const hex = value.trim().toLowerCase();
|
|
89
|
+
return PREVIEW_COLOR_PATTERN.test(hex) ? hex : null;
|
|
90
|
+
}
|
|
91
|
+
function rgb(hex) {
|
|
92
|
+
return [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
|
|
93
|
+
}
|
|
94
|
+
function previewColorDistance(a, b) {
|
|
95
|
+
const [r1, g1, b1] = rgb(a), [r2, g2, b2] = rgb(b);
|
|
96
|
+
const r = (r1 + r2) / 2, dr = r1 - r2, dg = g1 - g2, db = b1 - b2;
|
|
97
|
+
return Math.sqrt((2 + r / 256) * dr * dr + 4 * dg * dg + (2 + (255 - r) / 256) * db * db);
|
|
98
|
+
}
|
|
99
|
+
var HUE_NAMES = [
|
|
100
|
+
[15, "red"],
|
|
101
|
+
[40, "orange"],
|
|
102
|
+
[70, "yellow"],
|
|
103
|
+
[160, "green"],
|
|
104
|
+
[200, "cyan"],
|
|
105
|
+
[255, "blue"],
|
|
106
|
+
[290, "purple"],
|
|
107
|
+
[345, "pink"],
|
|
108
|
+
[360, "red"]
|
|
109
|
+
];
|
|
110
|
+
function previewColorName(hex) {
|
|
111
|
+
const [r, g, b] = rgb(hex).map((c) => c / 255);
|
|
112
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b), d = max - min;
|
|
113
|
+
if (d < 0.08) return `${max > 0.8 ? "white" : max < 0.25 ? "black" : "grey"} (${hex})`;
|
|
114
|
+
const hue = max === r ? ((g - b) / d + 6) % 6 : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
115
|
+
const grad = hue * 60;
|
|
116
|
+
const l = (max + min) / 2;
|
|
117
|
+
const stufe = l < 0.3 ? "dark " : l > 0.82 ? "light " : "";
|
|
118
|
+
return `${stufe}${HUE_NAMES.find(([grenze]) => grad < grenze)[1]} (${hex})`;
|
|
119
|
+
}
|
|
120
|
+
function fallbackCandidate(n) {
|
|
121
|
+
const hue = (n * 137.508 + 25) % 360;
|
|
122
|
+
const channel = (k0) => {
|
|
123
|
+
const k = (k0 + hue / 30) % 12;
|
|
124
|
+
return Math.round(255 * (0.62 - 0.29 * Math.max(-1, Math.min(k - 3, 9 - k, 1)))).toString(16).padStart(2, "0");
|
|
125
|
+
};
|
|
126
|
+
return `#${channel(0)}${channel(8)}${channel(4)}`;
|
|
127
|
+
}
|
|
83
128
|
function stageColors(nodes) {
|
|
84
129
|
const result = /* @__PURE__ */ Object.create(null);
|
|
85
|
-
const used =
|
|
130
|
+
const used = [];
|
|
86
131
|
const names = { subject: "orange", light: "yellow", surface: "cyan", object: "purple" };
|
|
132
|
+
for (const node of nodes) {
|
|
133
|
+
const hex = normalizePreviewColor(node.proxy_3d?.preview_color);
|
|
134
|
+
if (hex) {
|
|
135
|
+
used.push(hex);
|
|
136
|
+
result[node.node_id] = { hex, name: previewColorName(hex), explicit: true };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const nah = (hex) => used.some((u) => previewColorDistance(u, hex) < PREVIEW_COLOR_MIN_DISTANCE);
|
|
87
140
|
let next = 0;
|
|
88
|
-
for (const node of [...nodes].sort((a, b) => a.node_id.localeCompare(b.node_id))) {
|
|
141
|
+
for (const node of [...nodes].filter((n) => !result[n.node_id]).sort((a, b) => a.node_id.localeCompare(b.node_id))) {
|
|
89
142
|
let hex = stageColor(node.type), name = names[node.type] ?? "blue grey";
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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})`;
|
|
143
|
+
for (let tries = 0; nah(hex) && tries < 64; tries++) {
|
|
144
|
+
hex = fallbackCandidate(next++);
|
|
145
|
+
name = previewColorName(hex);
|
|
98
146
|
}
|
|
99
|
-
used.
|
|
100
|
-
result[node.node_id] = { hex, name };
|
|
147
|
+
used.push(hex);
|
|
148
|
+
result[node.node_id] = { hex, name, explicit: false };
|
|
101
149
|
}
|
|
102
150
|
return result;
|
|
103
151
|
}
|
|
152
|
+
function previewColorLegibility(hex) {
|
|
153
|
+
const [r, g, b] = rgb(hex).map((c) => c / 255);
|
|
154
|
+
const l = (Math.max(r, g, b) + Math.min(r, g, b)) / 2;
|
|
155
|
+
return l < 0.3 ? "too_dark" : l > 0.85 ? "too_light" : null;
|
|
156
|
+
}
|
|
157
|
+
function previewColorConflicts(nodes) {
|
|
158
|
+
const colors = stageColors(nodes);
|
|
159
|
+
const ids = Object.keys(colors).sort();
|
|
160
|
+
const out = [];
|
|
161
|
+
for (let i = 0; i < ids.length; i++) for (let j = i + 1; j < ids.length; j++) {
|
|
162
|
+
const a = colors[ids[i]].hex, b = colors[ids[j]].hex, distance = previewColorDistance(a, b);
|
|
163
|
+
if (distance < PREVIEW_COLOR_MIN_DISTANCE) out.push({ node_ids: [ids[i], ids[j]], hexes: [a, b], distance: Math.round(distance), identical: a === b });
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
function distinctPreviewColor(type, taken) {
|
|
168
|
+
const nah = (hex2) => taken.some((u) => previewColorDistance(u, hex2) < PREVIEW_COLOR_MIN_DISTANCE);
|
|
169
|
+
let hex = stageColor(type);
|
|
170
|
+
for (let n = 0; nah(hex) && n < 64; n++) hex = fallbackCandidate(n);
|
|
171
|
+
return hex;
|
|
172
|
+
}
|
|
104
173
|
var stageTypeLabel = (type) => ({ subject: "Person", light: "Licht", surface: "Fl\xE4che", object: "Objekt" })[type] ?? type;
|
|
105
174
|
function vector3(value, label) {
|
|
106
175
|
if (!Array.isArray(value) || value.length !== 3 || value.some((n) => typeof n !== "number" || !Number.isFinite(n))) {
|
|
@@ -123,6 +192,9 @@ function stageNode(node) {
|
|
|
123
192
|
type: node.type,
|
|
124
193
|
primitive: node.proxy_3d.primitive,
|
|
125
194
|
dimensions,
|
|
195
|
+
variant: node.proxy_3d.variant,
|
|
196
|
+
pose_ref: node.proxy_3d.pose_ref,
|
|
197
|
+
morph: node.proxy_3d.morph,
|
|
126
198
|
position: vector3(node.placement.position, `Position von ${node.node_id}`),
|
|
127
199
|
rotation: vector3(node.placement.rotation_euler_deg ?? [0, 0, 0], "Rotation"),
|
|
128
200
|
scale: vector3(node.placement.scale ?? [1, 1, 1], "Skalierung"),
|
|
@@ -133,7 +205,7 @@ function stageFrame(input) {
|
|
|
133
205
|
if (input.capabilities.can_place !== "yes") throw new Error("Die Szene ben\xF6tigt Meterma\xDFe und ein Scene Setup in Z-up-Koordinaten.");
|
|
134
206
|
const visible = input.scene.nodes.filter((n) => !n.hidden);
|
|
135
207
|
const colors = stageColors(visible);
|
|
136
|
-
const nodes = visible.map((n) => ({ ...stageNode(n), preview_color: colors[n.node_id] }));
|
|
208
|
+
const nodes = visible.map((n) => ({ ...stageNode(n), preview_color: { hex: colors[n.node_id].hex, name: colors[n.node_id].name } }));
|
|
137
209
|
if (!input.camera) throw new Error("Bitte eine Kamera ausw\xE4hlen.");
|
|
138
210
|
const optical = cameraPerspective(input.camera);
|
|
139
211
|
const placement = input.camera.placement;
|
|
@@ -190,6 +262,18 @@ function withStagePositions(input, nodes, camera) {
|
|
|
190
262
|
return next;
|
|
191
263
|
}
|
|
192
264
|
var roundMeters = (value) => Math.round(value * 1e3) / 1e3;
|
|
265
|
+
function facingRotationZ(position, target) {
|
|
266
|
+
const dx = target[0] - position[0], dy = target[1] - position[1];
|
|
267
|
+
if (!Number.isFinite(dx) || !Number.isFinite(dy) || Math.hypot(dx, dy) < 1e-8) throw new Error("F\xFCr die Ausrichtung m\xFCssen Quelle und Ziel unterschiedliche Bodenpositionen haben.");
|
|
268
|
+
return Math.round(Math.atan2(dx, -dy) * 180 / Math.PI * 1e3) / 1e3;
|
|
269
|
+
}
|
|
270
|
+
var snapRotationZ = (degrees) => Math.round(degrees / 15) * 15;
|
|
271
|
+
function stagePreviewResolution(aspectRatio) {
|
|
272
|
+
const [rw, rh] = aspectRatio.split(":").map(Number), scale = 768 / Math.max(rw, rh);
|
|
273
|
+
const width = Math.round(rw * scale), height = Math.round(rh * scale);
|
|
274
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width < 1 || height < 1 || Math.abs(width / height - rw / rh) > 1e-9) throw new Error("Dieses Kameraformat l\xE4sst sich mit der Preview-Aufl\xF6sung nicht exakt abbilden. Bitte ein Format-Preset w\xE4hlen.");
|
|
275
|
+
return { width, height };
|
|
276
|
+
}
|
|
193
277
|
|
|
194
278
|
export {
|
|
195
279
|
CAMERA_ASPECT_RATIOS,
|
|
@@ -199,7 +283,13 @@ export {
|
|
|
199
283
|
frozenCameraAspectRatio,
|
|
200
284
|
STAGE_CATALOGUE,
|
|
201
285
|
stageColor,
|
|
286
|
+
PREVIEW_COLOR_MIN_DISTANCE,
|
|
287
|
+
normalizePreviewColor,
|
|
288
|
+
previewColorDistance,
|
|
202
289
|
stageColors,
|
|
290
|
+
previewColorLegibility,
|
|
291
|
+
previewColorConflicts,
|
|
292
|
+
distinctPreviewColor,
|
|
203
293
|
stageTypeLabel,
|
|
204
294
|
vector3,
|
|
205
295
|
dragPosition,
|
|
@@ -214,5 +304,8 @@ export {
|
|
|
214
304
|
zoomPlaneView,
|
|
215
305
|
gridStep,
|
|
216
306
|
withStagePositions,
|
|
217
|
-
roundMeters
|
|
307
|
+
roundMeters,
|
|
308
|
+
facingRotationZ,
|
|
309
|
+
snapRotationZ,
|
|
310
|
+
stagePreviewResolution
|
|
218
311
|
};
|