Blockst renders Scratch-style programming blocks directly in Typst documents. It is made for worksheets, tutorials, teaching material, and visual programming explanations.
The current renderer is text-based: Typst passes Scratch text to a bundled WASM plugin, the plugin parses and renders SVG, and Typst embeds the SVG output.
⚠️ BREAKING CHANGE (since
0.2.0)❌ The old pre-
0.2.0syntax is removed and no longer available.✅ From
0.2.0onward, Blockst supports only the text-to-WASM pipeline.🔧 Documents that still rely on the previous native Typst renderer syntax must be migrated.
Starting with version 0.2.0, Blockst uses only the WASM-based text parser and renderer. The earlier native Typst rendering approach was dropped because it ran into Typst’s limits on more complex Scratch layouts.
Contents
- Highlights
- Install and Import
- Quick Start
- Example Gallery
- SB3 Import via Typst Plugin WASM
- Catalog
- Contributing
Highlights
- Scratchblocks-style syntax for scripts, reporters, booleans, inputs, dropdowns, and nested control blocks
- Themes: normal, high-contrast, print
- Localized text rendering through the WASM locale data
- experimental: SB3 import helpers for scripts, lists, variables, images, and static screen previews
Install and Import
#import "@preview/blockst:0.2.0": blockst, scratch, raw-scratch, sb3
Font requirement: Blockst is designed for Helvetica Neue (Scratch-like look). On Linux/Windows install a compatible font, for example Nimbus Sans, or override globally with
set-blockst(font: "...").
Quick Start
Show code
#scratch("
when green flag clicked
move (10) steps
turn cw (15) degrees
")
Source: examples/example-quickstart.typ
Example Gallery
All long snippets below use the same pattern: result first, code in a collapsible block.
Localized Text
Show code
#set-blockst(scale: 67.5%)
#scratch("Wenn die grüne Flagge angeklickt
wiederhole (4) mal
gehe (30) er Schritt
drehe dich nach rechts um (90) Grad
end", language: "de")
Source: examples/example-de.typ
Inline Usage Without blockst Container
Show code
#grid(
columns: (1fr, auto),
gutter: 6mm,
[*Step 1*\
Trigger the script and walk forward.],
[#scratch("when green flag clicked\nmove (20) steps")],
[*Step 2*\
Repeat a square movement.],
[#scratch("repeat (4)\nmove (40) steps\nturn cw (90) degrees\nend")],
)
Source: examples/example-inline.typ
Markdown Code Blocks with raw-scratch
Show code
#show: raw-scratch()
```scratch
when green flag clicked
repeat (4)
move (30) steps
turn cw (90) degrees
end
```
Source: examples/example-raw-scratch.typ
Theme and Scale
Show code
#let script = "when green flag clicked
go to (random position v)
turn cw (30) degrees"
#blockst[
#scratch(script)
]
#v(5mm)
#blockst(theme: "high-contrast")[
#scratch(script)
]
#v(5mm)
#blockst(theme: "print")[
#scratch(script)
]
Source: examples/example-theme.typ
Executable Preview (scratch-run)
Show code
#let square-program = "
go to x: (-45) y: (-45)
pen down
set pen [color v] to (0)
set pen size to (45)
repeat (4)
move (90) steps
turn cw (90) degrees
change pen [color v] by (25)
end"
#let star-rosette-program = "
go to x: (0) y: (0)
point in direction (90)
pen down
set pen size to (3)
repeat (9)
repeat (5)
move (90) steps
turn cw (144) degrees
end
turn cw (40) degrees
change pen [color v] by (18)
end"
#let spiral-program = "
go to x: (-95) y: (-10)
point in direction (90)
pen down
set pen size to (50)
repeat (60)
move (10) steps
turn cw (6) degrees
change pen [color v] by (8)
change pen size by (-0.5)
end"
#let custom-block-program = "
define triangle (var [size]) (color)
set pen [color v] to (var [color])
pen down
repeat (3)
move (var [size]) steps
turn cw (120) degrees
end
pen up
when green flag clicked
set pen size to (8)
go to x: (-50) y: (-50)
call triangle (100) (200)
go to x: (50) y: (50)
call triangle (50) (60)
"
#set-scratch-run(
width: 300,
height: 240,
start-x: 0,
start-y: 0,
start-angle: 90,
show-grid: 10,
show-axes: false,
show-cursor: true,
)
#stack(
spacing: 6mm,
[*1) Hue Square*],
grid(
columns: (auto, auto),
gutter: 6mm,
[#scratch(square-program)],
[#scratch-run(..scratch-execute(square-program), unit: 2)],
),
[*2) Star Rosette (Nested repeat)*],
grid(
columns: (auto, auto),
gutter: 6mm,
[#scratch(star-rosette-program)],
[#scratch-run(..scratch-execute(star-rosette-program), unit: 2)],
),
[*3) Colored Spiral (Hue + pen size)*],
grid(
columns: (auto, auto),
gutter: 6mm,
[#scratch(spiral-program)],
[#scratch-run(..scratch-execute(spiral-program), unit: 2)],
),
[*4) Custom Block: Triangle Pattern*],
grid(
columns: (auto, auto),
gutter: 6mm,
[#scratch(custom-block-program)],
[#scratch-run(..scratch-execute(custom-block-program), unit: 2, show-cursor: false)],
),
)
Source: examples/example-executable.typ
Experimental: SB3 Import via Typst Plugin WASM
Recommended workflow:
- Read
.sb3as bytes viaread(..., encoding: none). - Use the
sb3helpers to extract scripts, monitors, images, or screen previews. - Render imported scripts through the same text-to-WASM pipeline as
scratch(...).
SB3 Scripts and Screen Preview
Show code
#let project = read("Mampf-Matze Lösung.sb3", encoding: none)
#blockst[
#sb3.sb3-screen-preview(project, unit: 1.5)
#v(4mm)
#sb3.render-sb3-scripts(
project,
language: "en",
target: "Pacman",
target-script-number: 2,
show-headers: true,
)
]
Source: examples/example-sb3-import.typ
Variable and List Monitors
Show code
#let project = read("Mampf-Matze Lösung.sb3", encoding: none)
#stack(
spacing: 4mm,
sb3.render-sb3-variables(project, language: "en", show-target-headers: false),
sb3.render-sb3-lists(project, language: "en", show-target-headers: false),
)
Source: examples/example-monitors.typ
SB3 API at a Glance
- Scripts:
sb3.render-sb3-scripts(...)with target and script filters - Lists:
sb3.render-sb3-lists(...)by target, name, or local index - Variables:
sb3.render-sb3-variables(...)by target, name, or local index - Images:
sb3.sb3-images-catalog(...),sb3.sb3-image(...) - Screen:
sb3.sb3-screen-preview(...) - Catalogs:
sb3.sb3-scripts-catalog(...),sb3.sb3-state-catalog(...)
Catalog
The catalog is split by Scratch 3 category so each file stays readable and can be regenerated independently.
Contributing
Contributions are welcome: bug reports, missing blocks, parser improvements, rendering polish, docs, and new localizations.