Files
ApiCore/ApiCore-Frontend/src/lib/hive/fresh-part.ts
T
Nick SzaunigandClaude Opus 5.5 45274f4301
Backend Image / build-and-push (push) Successful in 7m57s
Frontend Image / build-and-push (push) Successful in 18m33s
Manifests / validate (push) Successful in 23s
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]>
2026-10-16 10:03:43 +02:00

23 lines
1.0 KiB
TypeScript

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;
}