# `OpenFresco.Editor`
[🔗](https://github.com/alexdont/open_fresco/blob/v0.2.0/lib/open_fresco/editor.ex#L10)

The browser editor stage — a `Phoenix.LiveComponent` that renders a scene
as a **server-authoritative** SVG preview and lets the user select
(single, shift-click, marquee), drag, resize, reorder, and delete
elements on a Fresco-style artboard.

Design: there is one layout engine — the server. The JS hook
(`priv/static/open_fresco.js`) drives gestures: it hit-tests locally at
pointerdown for instant selection/drag seeding, previews the gesture
with a client-side transform, and commits **one** operation on release;
the server applies it through `OpenFresco.Editor.Ops` against the
*resolved* layout (the same geometry the paint pass used) and
re-renders. So "what you edit is what renders" holds by construction.

The SVG is rendered as **separate defs / body / selection dynamics**
(`OpenFresco.Svg.render_parts/3` with `split_images: true`), so
LiveView patches after a commit don't retransmit inlined image
data-URLs, and selection changes don't retransmit geometry.

## Embedding

    <.live_component
      module={OpenFresco.Editor} id="og-editor"
      scene={@scene} values={@values} globals={@globals} />

Assigns:

  * `:scene` (required) — the `OpenFresco.Scene`.
  * `:values` — slot values, as `OpenFresco.render_svg/3`.
  * `:globals` — `[[global]]` values; the stage resolves them exactly
    like the PNG path does (one shared substitution pass).
  * `:resolver` — the resource-resolver fun (see
    `OpenFresco.render_svg/3`); lets the stage display media that's
    stored as opaque refs instead of the stand-in.
  * `:selected` — pass to drive selection programmatically (e.g. click
    a slot chip in the host → highlight its element). Omit to leave
    selection editor-driven.
  * `:fit` — `true` (default) scales the stage to its container
    (pointer math is transform-safe); `false` renders 1:1.
  * `:notify` — where change messages go: a `pid` (default: the root
    LiveView via `self()`), or `{module, id}` to `send_update/3` into
    a host LiveComponent (which otherwise could never receive them).

## Ownership contract

The scene is **host-owned, editor-driven**: every committed edit is
notified to the host (persist it; echo it back via the `:scene`
assign). Echoed scenes that equal the editor's current scene are
accepted without re-rendering, and gestures preview client-side —
a parent re-render can no longer clobber an in-flight gesture. A
*different* scene from the host always wins (that's programmatic
editing); hosts wanting stricter arbitration can withhold the assign.

On every **committed** edit the component notifies
`{:open_fresco_editor, id, {:scene_changed, scene}}` (every message is
a persist-safe commit — previews never reach the server); on selection
`{:open_fresco_editor, id, {:selected, id_or_nil}}` and — when a
selection set is active — `{:selected_ids, [ids]}`.

Undo material: apply edits through `OpenFresco.Editor.Ops.command/2`
in the host when you need an undo stack — each command returns its
inverse.

## Keyboard

With the stage focused: `Tab`/`Shift+Tab` cycle element selection,
arrows nudge by 1px (`Shift` = 10px), `Delete`/`Backspace` delete the
selection (set-aware), `Escape` deselects, `]`/`[` bring to
front / send to back (`Alt` steps one position).

Requires the optional `:phoenix_live_view` dependency — without it this
module is not compiled.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
