Tags

Group nodes. Query in formulas.

Tags are string labels you attach to nodes. Tag a row of bricks #brick. In a formula, Tag.brick.length returns the count. Destroy a brick — the count updates reactively.


Adding tags

Select a node. In the properties panel header, click the tag area. Type comma-separated tags:

brick, destructible, row1

Tags appear as badges in the properties panel and element tree. Multiple nodes can share the same tag. One node can have multiple tags.


Using tags in formulas

Access the group

Tag.brick // → array of all nodes tagged "brick"
Tag.brick.length // → count of brick nodes
Tag.brick[0] // → first brick node
Tag.brick[0].x // → x position of first brick

Reactive updates

Tag.brick.length is reactive. When a brick is destroyed, every formula that reads Tag.brick.length re-evaluates automatically.

title: "Brick counter"
description: "Score tracks how many bricks remain — click bricks to destroy them"
nodes:
  - type: RECT, name: "Brick1", x: 100, y: 100, w: 60, h: 30, fill: "#3498DB", tags: ["brick"]
  - type: RECT, name: "Brick2", x: 180, y: 100, w: 60, h: 30, fill: "#2ECC71", tags: ["brick"]
  - type: RECT, name: "Brick3", x: 260, y: 100, w: 60, h: 30, fill: "#E74C3C", tags: ["brick"]
  - type: RECT, name: "ScoreBox", x: 180, y: 250, w: 100, h: 40, fill: "#2C3E50", cornerRadius: 6
formulas:
  - node: "ScoreBox", prop: "width", value: "Tag.brick.length * 40 + 20"
events:
  - node: "Brick1", event: "click", code: "this.destroy()"
  - node: "Brick2", event: "click", code: "this.destroy()"
  - node: "Brick3", event: "click", code: "this.destroy()"
tools_visible: [select, play]
ui_visible: [properties, formulas, layers]

Tag registry

Tags are stored in a global registry: Map<tag, Set<nodeId>>. Lookups are O(1).

When a node is destroyed:

  1. It's removed from all tag sets
  2. markDep('Tag', tagName) fires for each tag
  3. All formulas reading that tag re-evaluate

When tags are added/removed via setTags():

  1. Registry updates
  2. Change callback fires
  3. Dependent formulas re-evaluate

Type checking with tags

The is() method checks both type and tag:

node.is("RECT")     // true if node type is RECT
node.is("brick")    // true if node has tag "brick"
node.is("enemy")    // true if node has tag "enemy"

In collision events:

if (event.target.is("brick")) {
  event.target.destroy()
}

Visual features

Canvas highlight

Hover a tag badge in the properties panel — all nodes with that tag show a diagonal stripe fill and blue outline on the canvas.

Element tree highlight

Hovering a tag also highlights matching nodes in the layer tree with a CSS class.

Select by tag

Shift+click a tag badge — selects all nodes with that tag. Useful for bulk operations.


Autocomplete

Type Tag. in a formula — autocomplete shows all registered tag names from getAllTags(). Type Tag.brick. — autocomplete shows VNode properties (x, y, width, height, rotation, etc.).


Serialization

Tags serialize as an array on each node:

{ "type": "RECT", "tags": ["brick", "row1"], ... }

Backward-compatible migration handles old tag string format → tags array.


Common patterns

Win condition

WinText.visible = Tag.brick.length === 0

Enemy count display

Counter.text = Tag.enemy.length

Spawn tracking

// In a method: create node, tag it, formula sees it
newBullet.setTags(["bullet"])
// Tag.bullet.length increases automatically

Group operations

// In an event handler: destroy all enemies
for (const enemy of Tag.enemy) {
  enemy.destroy()
}

Back to formulasEvents systemCollision events

Дальше →Reactive Signals