Blocks
Blocks are the visual elements on your canvas — shapes, text, images, sticky notes, and anything else you can see. Every block is an ECS entity with a Block component that stores its core properties.
Block Properties
Section titled “Block Properties”The Block component contains:
interface Block { tag: string; // Block type identifier position: [number, number]; // [x, y] in world coordinates size: [number, number]; // [width, height] in pixels rank: string; // Z-order (fractional indexing) rotateZ: number; // Rotation in radians flip: [boolean, boolean]; // [flipX, flipY] for mirroring}Built-in Block Types
Section titled “Built-in Block Types”Woven Canvas includes the following block types:
| Tag | Description | Components |
|---|---|---|
sticky-note | Colored sticky notes | Block, Color, Text |
text | Rich text blocks | Block, Text |
shape | Geometric shapes | Block, Shape, Text |
image | Images | Block, Image, Asset |
pen-stroke | Freehand drawings | Block, PenStroke, Color |
elbow-arrow | Right-angle connectors | Block, ElbowArrow, Connector |
How Blocks Render
Section titled “How Blocks Render”The WovenCanvas component renders blocks using named slots. For each block, it looks for a slot named block:<tag>:
<template> <WovenCanvas> <!-- Override how sticky notes render --> <template #block:sticky-note="props"> <MyStickyNote v-bind="props" /> </template>
<!-- Add a new block type --> <template #block:my-block="props"> <MyBlock v-bind="props" /> </template> </WovenCanvas></template>The slot receives a BlockData object in props:
interface BlockData { entityId: number; // The entity ID block: Block; // Block component data stratum: Stratum; // Render layer selected: boolean; // Is selected? hovered: boolean; // Is mouse over? edited: boolean; // Is being edited? held: HeldData; // Who is dragging this? opacity: number; // Current opacity}Strata (Layers)
Section titled “Strata (Layers)”Blocks are rendered in three layers:
| Stratum | Purpose |
|---|---|
background | Background elements |
content | Main content (default) |
overlay | Selection UI, handles |
Within each stratum, blocks are sorted by their rank property.
Reading Block Data
Section titled “Reading Block Data”Use useComponent to reactively read block data:
import { useComponent } from "@woven-canvas/vue";import { Block, Color, Text } from "@woven-canvas/core";
const props = defineProps<{ entityId: number }>();
const block = useComponent(props.entityId, Block);const color = useComponent(props.entityId, Color);const text = useComponent(props.entityId, Text);
// React to changeswatchEffect(() => { console.log("Position:", block.value?.position); console.log( "Color:", color.value?.red, color.value?.green, color.value?.blue, );});Writing Block Data
Section titled “Writing Block Data”Use nextEditorTick to modify blocks, this ensures your changes are applied at the start of the next editor tick. It’s important to use nextEditorTick to apply updates, otherwise the update may be applied mid-frame, potentially causing visual glitches and inconsistent state.
import { useEditorContext } from "@woven-canvas/vue";import { Block, Color } from "@woven-canvas/core";
const { nextEditorTick } = useEditorContext();
function moveBlock(entityId: number, dx: number, dy: number) { nextEditorTick((ctx) => { const block = Block.write(ctx, entityId); block.position[0] += dx; block.position[1] += dy; });}
function setColor(entityId: number, r: number, g: number, b: number) { nextEditorTick((ctx) => { const color = Color.write(ctx, entityId); color.red = r; color.green = g; color.blue = b; });}Querying Blocks
Section titled “Querying Blocks”Use useQuery to find blocks matching criteria:
import { useQuery } from "@woven-canvas/vue";import { Block, Selected } from "@woven-canvas/core";
// All blocksconst allBlocks = useQuery([Block]);
// Selected blocks onlyconst selectedBlocks = useQuery([Block, Selected]);
// React to selection changeswatchEffect(() => { console.log("Selected count:", selectedBlocks.value.length);});