import { objectRef, type RuntimeContext, } from "@quixos/camino-package-runtime"; export type PlacementInput = { canvas_id: string; subject_id: string; x: number; y: number; width: number; height: number; z: number; }; const finiteNumber = (value: unknown, fallback: number) => typeof value === "number" && Number.isFinite(value) ? value : fallback; const objectId = (value: unknown, field: string) => { if (typeof value !== "string" || !value.startsWith("obj:")) { throw new Error(`${field} must be a Camino object ID`); } return value; }; export const normalizePlacementInput = ( input: Record, ): PlacementInput => ({ canvas_id: objectId(input.canvas_id, "canvas_id"), subject_id: objectId(input.subject_id, "subject_id"), x: finiteNumber(input.x, 0), y: finiteNumber(input.y, 0), width: Math.max(220, finiteNumber(input.width, 420)), height: Math.max(150, finiteNumber(input.height, 320)), z: Math.trunc(finiteNumber(input.z, 0)), }); export const createCanvas = (context: RuntimeContext) => objectRef(context.objectId); export const createPlacement = async (context: RuntimeContext) => { const input = normalizePlacementInput(context.input); await Promise.all([ context.state("port:web-studio-placement-constructor:x").set(input.x), context.state("port:web-studio-placement-constructor:y").set(input.y), context.state("port:web-studio-placement-constructor:width").set(input.width), context.state("port:web-studio-placement-constructor:height").set(input.height), context.state("port:web-studio-placement-constructor:z").set(input.z), ]); await context.edge("port:web-studio-placement-constructor:subject").connect(input.subject_id); await context.edge("port:web-studio-placement-constructor:canvas").connect(input.canvas_id); return objectRef(context.objectId); };