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.
Open-source · TypeScript · built on Google Blockly
Morphic Blocks is an embeddable TypeScript library built on top of Google Blockly. One block model renders in any number of custom representations, from icons to real source code.
npm install morphic-blocks

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.
Blocks in JSON, behaviors in TypeScript, and one CSS file per mode. An environment is extended or restyled by editing config, not through Blockly's multi-file imperative setup.
The same program can be shown as icons, blocks, or text, scaffolding the gradual path from block-based to text-based programming, with one framework across many learning stages.
The framework never contacts another server. So the site alone decides which requests a browser makes during a visit, Blockly's images and sounds included: they load from the same site by default.
Install the package, pass in the definitions and behaviors, mount.
That is the whole loop. The docs cover modes, toolbox, codespace, and behaviors in depth.
Read the full guide →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);
// One call sets up every view it gets a container for.
engine.mount({
workspaceContainer: document.getElementById("workspace")!,
toolboxContainer: document.getElementById("toolbox")!,
});
// Switch representation at runtime; the same blocks re-render.
engine.setModes({ workspaceMode: "python", toolboxMode: "python" });{
"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" }
}
}
]
}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`;
},
};