--- title: "Edit Operations" description: "The complete EditOp catalog for dispatch(), can(), and batch()." --- Every mutation in the SDK is expressed as an `EditOp` — a plain data object with a discriminated `type` field. You can submit ops individually through `dispatch()`, validate them with `can()`, or group them into a single undo/persist step with `batch()`. Every element op requires an explicit `target` (an `HfId` string or `HfId[]` array). There is no selection-implicit mutation — the SDK never reads the current selection to decide what to edit. The typed methods on `Composition` (such as `comp.setText()` and `comp.setStyle()`) are convenience sugar that construct and dispatch these same ops. ## dispatch, batch, and can ### dispatch ```typescript comp.dispatch(op: EditOp, opts?: { origin?: unknown }): void ``` Applies `op` immediately. Emits a `patch` event, persists if an adapter is attached, and records a history entry. The optional `origin` is forwarded verbatim in the resulting `PatchEvent`; use it to label the source of the change (e.g. `"user"`, `"agent"`, or your own string constant). ```typescript comp.dispatch( { type: "setStyle", target: "hf-title", styles: { color: "#FFD60A" } }, { origin: "agent" }, ); ``` ### batch ```typescript comp.batch(fn: () => void, opts?: { origin?: unknown }): void ``` Groups all `dispatch()` calls made inside `fn` into a single undo step, a single persist write, and a single `patch` event. Use `batch()` when several mutations belong together logically. ```typescript comp.batch(() => { comp.dispatch({ type: "setText", target: "hf-title", value: "Launch Day" }); comp.dispatch({ type: "setStyle", target: "hf-title", styles: { fontSize: "96px" } }); comp.dispatch({ type: "setTiming", target: "hf-title", start: 0.5, duration: 3 }); }); ``` ### can ```typescript comp.can(op: EditOp): CanResult ``` Dry-runs `op` without mutating the document. Returns `{ ok: true }` when `dispatch(op)` would succeed, or `{ ok: false; code: string; message: string; hint?: string }` when it would be a no-op or error. Use `can()` as a feature-detection gate before rendering controls or applying optional operations: ```typescript const result = comp.can({ type: "setGsapTween", animationId: "anim-1", properties: { ease: "power3.out" }, }); if (result.ok) { comp.setGsapTween("anim-1", { ease: "power3.out" }); } else { console.warn(result.code, result.message); } ``` Stable `code` values for `ok: false`: | Code | Meaning | |------|---------| | `E_TARGET_NOT_FOUND` | The `target` hf-id does not exist in the document. | | `E_NO_ROOT` | The document has no root element (empty HTML). | | `E_NO_GSAP_TIMELINE` | Op requires a parsed GSAP timeline; parser engine not yet active. | | `E_NO_GSAP_SCRIPT` | Op requires a GSAP `