HomeDeveloper docsBlueprint kind lever: a two-state switch and an Empty Object
Examples by kind 4 min read

Blueprint kind lever: a two-state switch and an Empty Object

A complete off/on toggle, with the same kind reused by an image-free private controller.

Goal

Make an ordinary switch alternate off → on → off. The JSON retains the existing artwork in both states; state actions alone do not choose different sprites. An Empty Object uses this same lever kind, not a fifth kind named empty.

These JSON files describe the stored Blueprint v2 subdocument. They are development fixtures, not an installable module, a complete Builder project or a campaign archive. Recreate the nodes in the editor, or use the fixtures in isolated contributor tests. This guide does not assume a JSON import button in the Smart Object editor.

Download the complete example bundle or the validator. Every example uses original synthetic data. The host's internal Python evaluator is for source development; browser modules must use the public SDK.

Build it in the editor

  1. Place an Object image, select it and choose Panels → Selection → Behavior → Lever. Set Initial state to Deactivated.

  2. Open Edit behavior. Connect On interaction → Check state: Deactivated.

  3. Connect True → Change state: Activated and False → Change state: Deactivated.

  4. For an image-free controller instead, place Library → Objects → Empty Object. Use the same graph; retain inherit appearances and do not attach image actions to Self.

  5. To show different artwork on a visible lever, choose a valid Object image for each state appearance, or append explicit Change sprite actions. That requires real campaign asset IDs beyond this self-contained fixture.

Complete JSON

Download lever-toggle.json

json
{
  "version": 2,
  "kind": "lever",
  "states": {
    "off": {
      "appearance": "inherit"
    },
    "on": {
      "appearance": "inherit"
    }
  },
  "graphs": {
    "interact": {
      "nodes": [
        {
          "id": "start",
          "type": "event",
          "x": 40,
          "y": 80,
          "event": "interact"
        },
        {
          "id": "isOff",
          "type": "condition",
          "x": 300,
          "y": 80,
          "state": "off"
        },
        {
          "id": "activate",
          "type": "state",
          "x": 560,
          "y": 40,
          "targetState": "on"
        },
        {
          "id": "deactivate",
          "type": "state",
          "x": 560,
          "y": 220,
          "targetState": "off"
        }
      ],
      "edges": [
        {
          "from": "start",
          "to": "isOff",
          "output": "next",
          "kind": "execution"
        },
        {
          "from": "isOff",
          "to": "activate",
          "output": "true",
          "kind": "execution"
        },
        {
          "from": "isOff",
          "to": "deactivate",
          "output": "false",
          "kind": "execution"
        }
      ]
    }
  }
}

Expected result

Initial stateBranchPredicted action
offtruestate → on
onfalsestate → off

Each evaluation reads the starting state. A state action does not emit another interact event.

Run the fixture in a development installation

Extract the example bundle to data/blueprint-examples inside a disposable checkout of the documented host. From the checkout root, run:

sh
uv run --locked python data/blueprint-examples/check-examples.py --host .

The checker configures an in-memory database, blocks database queries and calls the real clean_blueprint and evaluate_graph functions. It validates all four object kinds, both connection kinds and all 44 node types, including requestRoll and setQuestStatus. It checks both roll visibilities, all six quest statuses and continuing execution without drawing dice or changing journals. This verifies document shape and predicted actions. Test behavior is still needed to check real targets, authorization and the complete server chain.

To inspect this recipe in the development Django shell after extracting the files:

sh
uv run --locked python manage.py shell --no-imports
python
import json
from pathlib import Path
from gravewright.maps.blueprints import clean_blueprint, evaluate_graph

raw = json.loads(Path("data/blueprint-examples/lever-toggle.json").read_text(encoding="utf-8"))
blueprint = clean_blueprint(raw, asset_ids=set(), light_ids=set(), track_ids=set())
result = evaluate_graph(blueprint, "interact", "off")
print(result["trace"])
print(result["actions"])
assert result["actions"][0]["targetState"] == "on"

Test as GM and player

Run Simulate to inspect one local event. Then use Test behavior to rehearse through the server; its changes are rolled back. Generate or update the scene as GM, then test a synthetic scene with a GM and an authorized player. Verify that a streamer cannot write. After editing the project again, use Update scene before expecting different live behavior.

Test a visible lever on the Game layer as GM and authorized player. A single click selects; double-click runs the configured interaction. Then test the Empty Object as GM: it stays private on the GM layer, and players receive no marker or direct click target. Players can still trigger an Empty Object’s authored presence graphs through eligible token movement; this fixture only defines interact.

Common failures

  • “The image did not change”: inherit deliberately keeps the native image. Add state appearances or sprite actions to the visible variant.

  • “The Empty Object is absent for players”: that is its privacy contract; it is a GM controller, not a public invisible button.

  • “The lever still toggles after deleting a node”: distinguish no blueprint/native behavior from an authored interaction path. Keep a connected complete graph when testing this example.

How to use AI to adapt this example

text
Using lever-toggle.json and the Gravewright 0.3.1 validator, add a separate presence:enter graph that activates a visible lever only when the occupancy count is 1. Keep off/on states and explicit state actions. Explain the visible lever versus Empty Object permissions. Return complete JSON, correctly typed count comparison, editor steps and two-token tests. Do not invent kind empty or grant player access to private markers.

All Blueprint kinds · execution/data connections · All 44 node examples