Open-source · TypeScript · built on Google Blockly

One definition, multiple representations.

Morphic Blocks is an embeddable TypeScript library built on top of Google Blockly. One block model renders in as many representations as you define, from icons to real source code.

npm install morphic-blocks
View on npm →
Same statement, three modes
SimpleThe Print block in simple mode: a printer icon, the label Print, and a one line description
PseudoThe Print block in pseudo mode: a block labelled Output with an empty input slot
Syntax-JSThe Print block in syntax-js mode: console.log with an empty argument

One block, many modes

A single morphic block carries several visual elements: icons, natural-language labels, and code templates. Modes decide which are shown, and switch at runtime without remounting.

Declarative & config-driven

Define blocks in JSON, behaviors in TypeScript, and one CSS file per mode. Extend or restyle an environment by editing config, not Blockly's multi-file imperative setup.

Built for transition

Render the same program as icons, blocks, or text to scaffold the gradual path from block-based to text-based programming, with one framework across many learning stages.

Quick start

Install the package, hand it your definitions and behaviors, and mount.

That is the whole loop. The docs cover modes, toolbox, codespace, and behaviors in depth.

Read the full guide →
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.
const engine = new MorphicBlocks(definitions, behaviors);

engine.mount({
  workspaceContainer: document.getElementById("workspace")!,
  workspaceMode: "conceptual",
  toolboxMode: "conceptual",
});

engine.mountToolbox(document.getElementById("toolbox")!);

// Switch representation at runtime; the same blocks re-render.
engine.setModes({ workspaceMode: "python", toolboxMode: "python" });
definitions.json
{
  "elementTypes": {
    "title":      "text",
    "conceptual": "code",
    "python":     "code"
  },
  "modes": [
    { "name": "conceptual", "elements": ["title", "conceptual"] },
    { "name": "python",     "elements": ["title", "python"] }
  ],
  "blocks": [
    {
      "identifier": "text_print",
      "elements": {
        "title":      "Print",
        "conceptual": "Output %1",
        "python":     "print(%1)"
      },
      "inputSlots": {
        "1": { "kind": "value", "name": "TEXT" }
      }
    }
  ]
}
behaviors.ts
import type { MorphicBehaviorMap } from "morphic-blocks";

// One function per block identifier, returning the executable JavaScript.
export const behaviors: MorphicBehaviorMap = {
  text_print(proxy) {
    return `console.log(${proxy.inputs.TEXT ?? "undefined"});\n`;
  },
};

See it in action

Try the playground
The editor in its hybrid preset: an icon toolbox on the left, a block workspace in pseudo mode, and the same program as Python and JavaScript source beside it, with the program output below
Toolbox, workspace and two source views of one program