Skip to content

Quick Start

This walkthrough builds the smallest useful setup: one block, two modes, a toolbox, and a workspace — with a runtime mode switch at the end.

  1. Define your blocks in a definitions JSON. A block declares named elements (its visual parts); the global elementTypes registry says what each element name is; modes pick which elements are shown.

    definitions.json
    {
    "elementTypes": {
    "title": "text",
    "concept": "code",
    "python": "code"
    },
    "modes": [
    { "name": "concept-tiles", "elements": ["title", "concept"] },
    { "name": "python-tiles", "elements": ["title", "python"] }
    ],
    "categories": [
    { "name": "Output", "color": "#5C81A6" }
    ],
    "blocks": [
    {
    "identifier": "text_print",
    "category": "Output",
    "elements": {
    "title": "Print",
    "concept": "Output %1",
    "python": "print(%1)"
    },
    "inputSlots": {
    "1": { "kind": "value", "name": "TEXT" }
    }
    }
    ]
    }

    %1 is an input slot — it becomes a Blockly input on the block and a substitution point in text renderings.

  2. Write a behavior for the block. Behaviors generate the executable JavaScript, one function per block identifier:

    behaviors.ts
    import type { MorphicBehaviorMap } from "morphic-blocks";
    export const behaviors: MorphicBehaviorMap = {
    text_print(proxy) {
    return `console.log(${proxy.inputs.TEXT ?? "undefined"});\n`;
    },
    };
  3. Add containers to your page:

    <div id="toolbox"></div>
    <div id="workspace"></div>
  4. Mount the engine:

    main.ts
    import { MorphicBlocks } from "morphic-blocks";
    import definitions from "./definitions.json";
    import { behaviors } from "./behaviors";
    // The constructor takes the whole definitions file plus your behaviors.
    // mount() inherits its modes / presets / code settings / categories, so the
    // call only carries runtime concerns.
    const engine = new MorphicBlocks(definitions, behaviors);
    // One call sets up every view it gets a container for.
    engine.mount({
    workspaceContainer: document.getElementById("workspace")!,
    toolboxContainer: document.getElementById("toolbox")!,
    // No presets here, so the first mode ("concept-tiles") is used.
    });

    Drag the Print tile from the toolbox into the workspace — it creates a real Blockly block.

  5. Switch at runtime. The same blocks re-render with the python element as their template:

    engine.show({ toolbox: "python-tiles", views: { workspace: "python" } });
  6. Generate code from the workspace via your behaviors:

    const js = engine.generateJavaScript();

    Blockly’s own options go under blockly and are passed through, e.g. the block look: mount({ blockly: { renderer: "zelos" } }) (default geras).