Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

editor_observe

What an editor action committed, and why it committed less than it was asked for.

Every editor action — a gizmo drag, a delete, a duplicate, a command dispatch, a selection gesture — closes by publishing one record here, and returns that same record to its caller. Nothing is measured per frame: a record is written where the work happens and read lazily.

local Obs = require("@builtin::modules.api.editor.editor_observe")

Obs.observe()          -- the whole document: last of each kind, history, counts
Obs.last()             -- the most recent action of any kind
Obs.last("drag")       -- the most recent drag
Obs.history()          -- every retained action, oldest first

The same reading is a tool: tools.use("editor", "observe").

What every record carries

  • action — drag, grab, delete, duplicate, command or select.
  • outcome — committed, partial, refused, cancelled or noop.
  • reason — the nearest cause, from the closed set below, when the outcome is anything but a clean commit.
  • detail — the engine's own words for that cause.
  • entities — one row per entity the action touched or tried to, each with before, requested and after, and its own reason when it is not a clean commit.
  • committed / changed / refused — how many rows fall in each.
  • seq, atMs, durationMs — which action this is and how long it was open.

The reason set

selectionEmpty, entityMissing, writeRefused, writeDiverged, pivotLost, userCancelled, commitFailed, duplicateRefused, despawnRefused, unchanged, commandMissing, commandDisabled, predicateRaised, bodyRaised, hitNothing, pointerBlocked. Obs.REASONS maps each to its one-line meaning, so a caller can enumerate the set rather than guess at it.

A drag that moved less than asked

The drag record separates the three quantities that are usually conflated:

  • pointerAsked — what the pointer's position asked for, before snapping.
  • applied — what the gizmo handed the engine, after snapping. snapping and snapIncrement say why the two differ.
  • each entity's after — the transform the engine holds, read back from the engine rather than recomputed from the drag's own arithmetic.

An entity whose after differs from its requested reads writeDiverged; one whose write raised reads writeRefused with the message; one despawned mid-drag reads entityMissing. A drag that ended on Esc reads cancelled / userCancelled, and one whose selection emptied under it reads cancelled / pivotLost — three terminal states a single "the object did not move" cannot tell apart.

A drag that never began

A press that lands on a handle and starts no drag publishes a grab record instead — Obs.last("grab"), or Gizmo.lastGrab(). pointerBlocked says the UI layer held pointer focus, so the press never reached the handle. A press away from every handle is a selection click rather than a grab, and records nothing. One record per press: a frame that ticks the gizmo more than once reports the press once.

unit names what pointerAsked and applied are measured in: metres for a translate or plane drag (a world-space {x,y,z} delta), radians for a rotate ({radians}), factor for a scale ({factor}).

Per-frame cost

The editor's own per-frame work is named in the profiler rather than pooled into lua_update: script.editor.gizmo.tick, script.editor.viewport.select, script.editor.selection.highlight, and script.editor.panel.<id> for each dock panel's rebuild. Read them with profiler.stats().