Skip to main content

Locked Shapes

A locked shape ignores all interactive gestures โ€” clicks, drags, and resize hit-test as if it were not there โ€” but it still renders and stays serializable. Locking is controlled by the per-shape locked flag plus the per-layer Layer.locked flag.

Locking a shapeโ€‹

Set locked: true through updateElement.

import { updateElement } from "@oh-just-another/scene";
import { elementId } from "@oh-just-another/types";

const { scene: locked } = updateElement(scene, elementId("r1"), (el) => ({
...el,
locked: true,
}));

Propagation and the effective stateโ€‹

Lock state propagates down the parentId chain: if any ancestor is locked, the descendant is effectively locked. isElementLocked resolves this propagated state โ€” the shape's own flag plus its ancestors'. It does not consult Layer.locked: the layer flag is an independent gate, and either source being true is enough to lock, so callers needing the combined state must || both.

import { isElementLocked, getElement } from "@oh-just-another/scene";
import { elementId } from "@oh-just-another/types";

const el = getElement(scene, elementId("r1"));
if (el) {
const layerLocked = scene.layers.get(el.layerId)?.locked ?? false;
if (isElementLocked(scene, el) || layerLocked) {
// skip interaction
}
}

Because locking only gates interaction, locked shapes are perfect for background images, guide rails, or template chrome you want to keep visible but immovable.

editor.unlockAll() clears the flag on every locked element in one undo step (the canvas menu's "Unlock all").