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.