feat: Beute-Editor mit Ziehen und Ablegen in 3D (Beute L4, Task 18)
- Teile aus der Palette in die Szene ziehen: Stapel öffnet sich, erlaubte Plätze leuchten, Vorschau rastet ein; erlaubte Plätze per applyHiveOps auf einer Kopie (gleiche Regeln wie der Server) - Vorhandene Teile verschieben, auf „Entfernen“ ziehen; Einsätze aus offenen Zargen ziehen, dünne Teile mit Mindest-Trefferhöhe - Drücken auf ein Teil dreht das Modell nie (Prüfung erst beim Dreh- Beginn, passend zur Ereignisfolge von R3F); Abbruch mit Esc, Fenster- wechsel oder Maus ohne Taste - Zoom 0,6–2,5 per Knöpfen (Fokus bleibt an den Grenzen), Rad und Pinch - Verdunster verschieben fragt nicht mehr nach Behandlungsende; Ansage „… verschoben“; gemeinsame Helfer fresh-part und feeder-slots - Neuzeichnen nur bei Zeigerbewegung, geteilte Materialien Gates: Frontend lint, typecheck, 2804 Tests, build; 3D-Chunk 292 kB gzip. Review (Opus) und Browserprüfung Maus/Touch. Refs #21 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
61985afc4b
commit
45274f4301
39 files changed
+1923
-114
No files matched your search
@@ -0,0 +1,22 @@
|
||||
import type { CatalogPartType, HiveFrame, HivePart } from "./types";
|
||||
|
||||
// A new part as the editor adds it (dialog and drag and drop alike): every
|
||||
// state field set to its default, a new box filled with foundation frames.
|
||||
|
||||
/** Level 0, the first option of a choice. */
|
||||
export function defaultPartState(type: CatalogPartType): HivePart["state"] {
|
||||
const state: HivePart["state"] = {};
|
||||
for (const field of type.stateSchema) state[field.key] = field.kind === "level" ? 0 : (field.options[0] ?? "");
|
||||
return state;
|
||||
}
|
||||
|
||||
/** Frames of a new box: every slot a foundation (spec 9.5). */
|
||||
export function newBoxFrames(type: CatalogPartType): HiveFrame[] {
|
||||
return Array.from({ length: type.frameSlots ?? 0 }, (_, index): HiveFrame => ({ slot: index + 1, type: "FOUNDATION" }));
|
||||
}
|
||||
|
||||
export function freshPart(type: CatalogPartType, id: string, state: HivePart["state"] = defaultPartState(type)): HivePart {
|
||||
const part: HivePart = { id, partTypeId: type.id, state };
|
||||
if (type.kind === "BOX") part.frames = newBoxFrames(type);
|
||||
return part;
|
||||
}
|
||||
Reference in new issue
Block a user