Variables & Assignment
set x = 10
set name = "hello"
set angle = sin(PI / 4) * 100
Loops
# count up
repeat i from 0 to 10 { ... }
# count down
repeat i from 10 to 0 { ... }
# step by 2
repeat i from 0 to 10 step 2 { ... }
Conditionals
if x > 5 {
circle cx=100 cy=100 r=20
} elif x > 2 {
rect x=0 y=0 w=40 h=40
} else {
line x1=0 y1=0 x2=100 y2=100
}
Functions (procedures)
func flower(cx, cy, petals, size) {
repeat i from 1 to petals {
set a = i * 360 / petals
set px = cx + cos(a) * size
set py = cy + sin(a) * size
circle cx=px cy=py r=size/3
}
}
call flower(250, 250, 8, 60)
Shapes
rect x=0 y=0 w=100 h=50
circle cx=250 cy=250 r=40
ellipse cx=250 cy=250 rx=80 ry=40
line x1=0 y1=0 x2=100 y2=100
polyline points="0,0 50,80 100,0"
polygon points="250,50 300,150 200,150"
path d="M10 80 C 40 10, 65 10, 95 80"
text x=100 y=200 content="Hello" font-size="24"
# Common attributes (on any shape):
# fill, stroke, stroke-width, opacity,
# rotate, scale, translate-x, translate-y,
# stroke-dasharray, stroke-linecap
Built-in Complex Shapes
# Star
star cx=250 cy=250 points=5 outer-r=80 inner-r=30 fill="gold"
# Regular polygon (N-gon)
ngon cx=250 cy=250 sides=6 r=80 fill="cyan"
# Diamond
diamond cx=250 cy=250 w=60 h=100 fill="purple"
# Heart
heart cx=250 cy=250 size=80 fill="red"
# Arc (partial circle)
arc cx=250 cy=250 r=80 start=0 end=270 stroke="blue" stroke-width=3
# Ring (donut)
ring cx=250 cy=250 outer-r=80 inner-r=40 fill="teal"
# Pie / wedge
pie cx=250 cy=250 r=80 start=-90 end=45 fill="orange"
# Cross / plus
cross cx=250 cy=250 size=80 thickness=25 fill="red"
# Arrow
arrow x1=50 y1=250 x2=450 y2=250 head=20 stroke="black" stroke-width=2
# Burst (radiating lines)
burst cx=250 cy=250 rays=12 inner-r=20 outer-r=100 stroke="gold"
# Isometric cube
cube cx=250 cy=250 size=60 hue=200
# Wave (sine curve)
wave x=0 y=250 w=500 amplitude=50 frequency=3 phase=0 stroke="blue"
# Spiral
spiral cx=250 cy=250 turns=5 start-r=10 end-r=200 stroke="purple"
# Zigzag line
zigzag x=0 y=250 w=500 amplitude=30 segments=10 stroke="red"
# Grid of lines
grid x=0 y=0 w=500 h=500 cols=10 rows=10 stroke="#ccc"
# Hexagonal grid
hexgrid x=0 y=0 w=500 h=500 size=20 stroke="#ccc"
# Dot grid
dotgrid x=0 y=0 w=500 h=500 cols=10 rows=10 r=3 fill="#333"
Backgrounds
# Solid color
background mode="solid" color="#f0f0f0"
# Linear gradient
background mode="gradient" from="#ff0" to="#f0f" angle=45
# (also: mode="linear-gradient", supports mid="color")
# Radial gradient
background mode="radial" from="#fff" to="#000"
# optional: cx=250 cy=250 r=200
# Checkerboard
background mode="checker" color1="#fff" color2="#ccc" size=25
# Stripes
background mode="stripes" color1="#fff" color2="#ccc" size=10 angle=45
# Polka dots
background mode="dots" color="#333" bg="#fff" spacing=20 r=3
# Grid lines
background mode="grid" color="#ddd" bg="#fff" spacing=25
# SVG noise (feTurbulence)
background mode="noise" base-frequency=0.05 octaves=4 seed=1
# optional: bg="#color" opacity=0.5 turbulence="turbulence"
# Hatching
background mode="hatch" color="#999" bg="#fff" spacing=10 angle=45
# Crosshatch
background mode="crosshatch" color="#999" bg="#fff" spacing=10
Groups & Transforms
group translate-x=100 translate-y=100 rotate=45 opacity=0.5 {
rect x=-25 y=-25 w=50 h=50
circle cx=0 cy=0 r=10
}
Boolean / CSG Operations
# Merge shapes into one outline
union fill="blue" stroke="black" stroke-width=2 {
circle cx=200 cy=250 r=80
circle cx=300 cy=250 r=80
}
# Subtract: first shape minus the rest
difference fill="red" {
rect x=150 y=180 w=200 h=140
circle cx=300 cy=250 r=60
}
# Keep only overlapping area
intersection fill="green" {
circle cx=220 cy=250 r=80
circle cx=320 cy=250 r=80
}
# Keep everything except the overlap
xor fill="purple" {
ngon cx=250 cy=250 sides=6 r=100
circle cx=250 cy=250 r=70
}
# Supported shapes: rect, circle, ellipse,
# polygon, star, ngon, diamond, heart,
# cross, pie, ring
# Supports loops, conditionals, and
# function calls inside boolean blocks.
# Operations can be nested.
# Set resolution for curve smoothness (default: 64)
# union resolution=128 fill="blue" { ... }
Shape Objects
# Create a named shape (does NOT draw it yet)
shape myCircle = circle cx=250 cy=250 r=50 fill="blue"
# Draw the shape
draw myCircle
# Modify properties after creation
set myCircle.cx = 300
set myCircle.fill = "red"
draw myCircle # draws at new position
# Read properties in expressions
set x = myCircle.cx + 100
# Draw with temporary overrides (doesn't change object)
draw myCircle fill="green" r=30
# Copy a shape (independent deep copy)
shape s2 = copy(myCircle)
set s2.cx = 400
draw s2
# Hyphenated properties work too
set myCircle.stroke-width = 3
Point Modification (modify)
# Iterate over a shape's vertices and modify them
# Inside the block: px, py = coordinates,
# pi = point index, pcount = total points
# cx, cy = shape center (mean of all points)
shape s = star cx=250 cy=250 points=5 outer-r=100 inner-r=40
# Move all points below center to the right by 50
modify s {
if py > cy {
set px = px + 50
}
}
draw s fill="gold"
# Scale outward from center (no hardcoded coords!)
modify s {
set px = cx + (px - cx) * 1.2
set py = cy + (py - cy) * 1.2
}
# Supported shapes: rect, circle, ellipse,
# polygon, polyline, line, star, ngon,
# diamond, heart, cross, pie, ring
# Control curve resolution (default: 64 segments)
# Fewer = coarser, more = smoother
shape c = circle cx=250 cy=250 r=80
modify c resolution=16 {
set px = px + sin(pi * 5) * 10
}
draw c
# Constants: PI, TAU (2*PI), E
# Functions: sin(deg), cos(deg), tan(deg),
# abs(x), sqrt(x), pow(x,y), min(x,y), max(x,y),
# floor(x), ceil(x), round(x), random(),
# lerp(a,b,t), map(v,a1,b1,a2,b2),
# hsla(h,s,l,a) -> color string
# Operators: + - * / % (modulo)
# Comparison: == != < > <= >=
# Logical: and or not
Defaults
# Set default fill, stroke, stroke-width
defaults fill="#336699" stroke="black" stroke-width=2
# Now all shapes use those unless overridden
circle cx=100 cy=100 r=40
rect x=200 y=60 w=80 h=80
# Override per shape
circle cx=300 cy=100 r=40 fill="red"
# Reset a default back to normal
defaults fill="none" stroke="none" stroke-width="none"
Linecap
# Set default stroke-linecap for all shapes
linecap round # round | butt | square
# Reset to default (no linecap attribute)
linecap none
Print / Debug
print "x is: " + x # outputs to console below