One pattern, every object.

Every GeoScript statement has the same shape. Once you've written three lines, you know the syntax for everything.

the pattern
type  Name: (arg1, arg2, arg3, …)

The type says what kind of thing you're creating. The name lets you reference it later. The arguments describe it. That's it.

scene.gs runnable
// Every line follows the same pattern
axes     A:  ((-6, 6), (-5, 5))
grid     G:  (A, 1)
point    O:  (0, 0, teal, 4)
circle   C:  (O, 3, teal, 1.5, teal.alpha(0.06))
pointOn   P:  (C, 45, amber, 5)
segment  s:  (O, P, amber, 1)
label    lP: (P, "P", amber, 11)
axes must come first. It sets the coordinate system everything else lives in. The canvas is blank until axes are defined.

Two ways to pass arguments.

Arguments can be positional (in order) or named (by key). You can't mix them in a single statement — pick one style and use it consistently.

✗ WRONG — mixed
circle C: (O, 3, color=teal)
✓ RIGHT — positional
circle C: (O, 3, teal)
✗ WRONG — mixed
circle C: (center=O, 3, teal)
✓ RIGHT — named
circle C: (center=O, radius=3, color=teal)

Optional arguments with defaults can be dropped from the right. So circle C: (O, 3) is perfectly valid — it just inherits the auto-colour and default stroke width.

One universal exception: zIndex= can always be appended as a named arg regardless of whether the rest are positional — segment s: (A, B, teal, 1.5, zIndex=2).

Points everywhere.

Any argument that expects a point accepts two forms interchangeably.

named A defined point object

point   A: (0, 0, white, 4)
segment s: (A, B, teal)    // A and B are point objects

inline A literal coordinate pair

segment s: ((0, 0), (4, 3), teal)   // inline pairs, no point objects needed

math Expressions work in coordinates

segment s: ((0, 0), (pi/2, sin(pi/2)), orange)
point   P: (pi, F(pi), white, 5)   // F is a defined fn object

The dot-access system (see below) means you can also derive points from existing objects — s1.mid, cc.center, T.centroid.

Colour without friction.

GeoScript has a built-in palette of named colours — type them directly as arguments. You can also define your own palette with col and reuse it with alpha variants.

all the colour forms
// Built-in names — just use them
circle C: (O, 3, teal, 2)

// Name.method for transparency
circle C: (O, 3, teal, 2, teal.alpha(0.08))

// Hex colour
circle C: (O, 3, #4fd1c5, 2)

// Custom palette — define once, use everywhere
col brand: (#2563eb)
circle C: (O, 3, brand, 2, brand.alpha(0.1))

Named colours: teal · mint · amber · violet · rose · orange · indigo · sky · emerald · lime · cyan · red · blue · green · yellow · pink · purple · white · grey

Colour methods: .alpha(0–1) for transparency, .lighter and .darker for tints.

If you omit a colour entirely, GeoScript auto-assigns from a rotating palette — useful for quick sketches where aesthetics don't matter yet.

The dot system.

Every referenceable object exposes computed properties via dot access. This is how GeoScript constructions compose — the output of one object becomes the input to the next.

dot access in practice
segment s: (A, B, white, 1.5)

// Use the midpoint as a label anchor
label lm: (s.mid, "midpoint", teal, 10)

// Use derived coordinates directly
point M: (s.mid.x, s.mid.y, teal, 4)

// Chain: midpoint of the segment's midpoint to another point
midpoint MM: (s.mid, C, violet, 4)

A few common examples across different types:

ExpressionWhat it gives you
segment.midMidpoint as a point object — usable anywhere a point is expected
segment.lengthEuclidean length as a number
circle.centerCentre point
circle.radiusRadius as a number
triangle.centroidCentroid point
circumcircle.centerCircumcenter of the triangle
integral.valueComputed definite integral as a number
crossing.x / .yCoordinates of the intersection point
diff.slopeDerivative value at the given x
tangentTo.t1 / .t2The two tangent points on the circle
You don't need to memorise these. The in-app search shows dot-access props for every type when you open a type's detail panel. See In-App Search below.

Math inline.

Arithmetic works anywhere a number is expected. Defined fn objects are callable by name.

expressions in arguments
// Arithmetic — all four operators plus power
point P: (2*pi, 3^2 - 1, white)

// Math functions and constants
point Q: (pi/4, sin(pi/4), amber, 5)

// fn objects are callable
fn    F: (x^2 - 2*x, violet, 2)
point R: (3, F(3), rose, 5)

// These all work as integral bounds
integral I: (F, 0, 2*pi, true, teal.alpha(0.25))

Available functions: sin cos tan asin acos atan sqrt abs exp ln log2 pow min max floor ceil round

Constants: pi tau inf

Operators: + − * / ^  (power is right-associative: 2^3^2 = 2^(3^2))

Comments & style.

// Full-line comment — anything after // is ignored
point O: (0, 0, white, 3)   // inline comment works too

Names must be unique across the whole diagram. Beyond that, GeoScript doesn't enforce naming conventions — use single letters for brevity, descriptive names for clarity, whichever serves the diagram.

Blank lines are fine and encouraged — group related statements visually, separate setup from construction from annotation.

The number scrubber.

Select any bare number in the editor and a slider appears at the bottom of the code panel. Drag it and the canvas updates in real time — no retyping, no re-running. Every frame is a live render.

editor — number selected
num h: (1.0)
point Q: (1+h, sin(1+h), violet, 5)
1.0
−5 … 5

The slider range is inferred from the value's magnitude — a small number gets a tight range, a large one gets more headroom. Press Escape or click elsewhere to dismiss.

SHIFT Fine control

Hold Shift while dragging to switch to fine mode — step drops to 0.01 and precision increases to two decimal places. A FINE badge appears on the slider bar while the key is held. Release to return to normal step.

editor — shift held
num h: (0.42)
point Q: (1+h, sin(1+h), violet, 5)
0.42
FINE −5 … 5

num Parametric diagrams

A single scrubbed number only updates the one literal you selected. To make a value flow through an entire construction — animating multiple objects at once — declare it as a num variable and reference it by name everywhere it's needed.

chord approaching tangent runnable
// Scrub h toward 0 — watch the chord rotate to meet the tangent
axes    A: ((-1, 3), (-1, 2))
grid    G: (A, 1)
ticks   T: (A, 1)
num     h: (1.0)
fn      F: (sin(x), teal, 2)
point   P: (1, sin(1), orange, 5)
point   Q: (1+h, sin(1+h), violet, 5)
segment chord: (P, Q, violet, 2)
diff    D: (F, 1, true, orange, 2)
label   lP: (P, "x=1", orange, 11)

Select the 1.0 in num h: (1.0) and drag left toward zero. Both P and Q update together because they both reference h — the chord rotates in real time until it meets the tangent line drawn by diff. A limit made visible.

Teaching tip: declare all the "moveable" parameters as num at the top of the script — angles, lengths, positions — and leave the rest of the diagram expressed in terms of them. The whole construction becomes interactive with a single selection.

The AI tab.

The AI tab understands GeoScript completely — the full type system, all the syntax rules, how constructions compose. Describe what you want to draw, and it writes the script.

GeoScript AI — powered by Claude
👤
Show the relationship between a triangle's incircle, circumcircle, and three classical centres. Nice colour scheme.
↓ 10 seconds later
GS
Here's your diagram ↗I've placed a scalene triangle with its circumcircle, incircle, circumcenter, incenter, and centroid — each labelled and colour-coded. Adjust any coordinate or colour to taste.

The generated code lands directly in the editor. Every number is adjustable — move a point, change a colour, add a construction on top. The AI writes the scaffold; you make it yours.

BYOK Bring your own API key

GeoScript AI uses your Anthropic API key, pasted once and stored only in your browser. Requests go browser → Anthropic directly — nothing touches our servers. Get a key at console.anthropic.com — no subscription required, costs fractions of a cent per diagram.

Prompt tips: Be specific about what relationships to show. Mention types you want to see — "use circumcircle and incircle types". Ask for a colour scheme. The AI reads the type system directly so geometric terminology works exactly as you'd expect.

Example — geometry.

Triangle with its three classical centres, incircle, and circumcircle.

triangle-centres.gs runnable
axes A: ((-5, 5), (-4, 5))
grid G: (A, 1)

point P1: (-3, -2, violet, 5)
point P2: ( 4, -2, violet, 5)
point P3: ( 1,  4, violet, 5)

triangle     T:  (P1, P2, P3, violet, 1.5, violet.alpha(0.07))
circumcircle cc: (P1, P2, P3, teal,   1.5, teal.alpha(0.05))
incircle     ic: (P1, P2, P3, orange, 1.5, orange.alpha(0.1))

// Helper types: invisible by default, visible with a colour
circumcenter O:  (P1, P2, P3, teal,   5)
incenter     I:  (P1, P2, P3, orange, 5)
centroid     G:  (P1, P2, P3, rose,   5)

label lO: (O, "circumcenter", teal,   10)
label lI: (I, "incenter",     orange, 10)
label lG: (G, "centroid",     rose,   10)

Example — functions.

Two curves, their intersections, and the filled area between them.

area-between-curves.gs runnable
axes A: ((-1, 7), (-2, 2))
grid G: (A, 1)
ticks T: (A, 1)

fn F1: (sin(x),  teal,   2)
fn F2: (x/3,     amber,  2)

// Find crossing points — near= picks which one
crossing C1: (F1, F2, 0, white,  5)
crossing C2: (F1, F2, 3, violet, 5)

// Fill region between the crossings
integral I1: (F1, C1.x, C2.x, true, teal.alpha(0.2), 1)
integral I2: (F2, C1.x, C2.x, true, amber.alpha(0.2), 1)

label l1: (C1, "A", white,  11)
label l2: (C2, "B", violet, 11)

Note how C1.x and C2.x are used directly as the integral bounds — the crossing type is referenceable as a point, so its coordinates flow naturally into subsequent definitions.