Pure scene-mutation and hit-test operations for the editor — the server-authoritative core the editor LiveComponent and its JS hook drive. Keeping them pure (no LiveView, no DOM) makes the editing model fully testable without a browser; the interactive layer is a thin shell over these.
All coordinates are canvas pixels (the same space scenes use). The drag gestures the browser reports are converted to canvas deltas by the hook, then applied here.
Summary
Functions
Move an element to the top of the z-order (rendered last / on top).
Remove an element by id.
The id of the top-most element containing {x, y} (canvas px), or nil.
Translate an element's box by (dx, dy).
Resize an element by dragging a corner handle (0 TL, 1 TR, 2 BR,
3 BL) by (dx, dy). Width/height are clamped to a small minimum and
normalized if a corner is dragged past its opposite.
Set an element's box directly (absolute canvas px), clamped/normalized.
Functions
@spec bring_to_front(OpenFresco.Scene.t(), String.t()) :: OpenFresco.Scene.t()
Move an element to the top of the z-order (rendered last / on top).
@spec delete(OpenFresco.Scene.t(), String.t()) :: OpenFresco.Scene.t()
Remove an element by id.
@spec hit_test(OpenFresco.Scene.t(), number(), number()) :: String.t() | nil
The id of the top-most element containing {x, y} (canvas px), or nil.
@spec move(OpenFresco.Scene.t(), String.t(), number(), number()) :: OpenFresco.Scene.t()
Translate an element's box by (dx, dy).
@spec resize(OpenFresco.Scene.t(), String.t(), 0..3, number(), number()) :: OpenFresco.Scene.t()
Resize an element by dragging a corner handle (0 TL, 1 TR, 2 BR,
3 BL) by (dx, dy). Width/height are clamped to a small minimum and
normalized if a corner is dragged past its opposite.
@spec set_box(OpenFresco.Scene.t(), String.t(), map()) :: OpenFresco.Scene.t()
Set an element's box directly (absolute canvas px), clamped/normalized.