Documentation
Geon
DSL Reference
A zero-dependency JavaScript library that renders static 2D geometric scenes from a concise, natural-language-like DSL into SVG — directly in the browser.
Design philosophy: Geon is deliberately minimal. No curly braces, no semicolons, no heavy punctuation. Line-based declarations, lowercase keywords, and order-sensitive evaluation keep programs readable and predictable.
Quickstart
Drop geon.js into your page. Call Geon.render(source, container). That's it.
<!-- 1. Include the library --> <script src="geon.js"></script> <!-- 2. Create a container --> <div id="canvas"></div> <!-- 3. Render a scene --> <script> Geon.render(` scene 600x400 grid x -5 to 5 step 1 y -5 to 5 step 1 point A (0,0) circle C center A r 2 stroke blue label A "Origin" label C "Circle C" `, document.getElementById("canvas")); </script>
Installation
Geon is a single file with zero external dependencies. Download and include it directly.
# Via <script> tag (recommended) <script src="geon.js"></script> # Or inline the contents of geon.js directly into your HTML
Once included, the global Geon object is available on window.
Program Structure
Every Geon program follows this grammar. Both scene and grid are mandatory and must appear before any statements.
Program ::= SceneDecl GridDecl Statement* Statement ::= Point | Segment | Circle | Polygon | Label
Scene
Declares the SVG viewport dimensions in pixels. Must be the first statement.
scene <width>x<height>
scene 600x400 # 600px wide, 400px tall scene 800x800 # Square canvas
| Field | Type | Description |
|---|---|---|
width | integer | SVG width in pixels |
height | integer | SVG height in pixels |
Grid
Defines the logical coordinate system — the bounds and step interval for both axes. The grid is rendered as light lines in the SVG, with the x=0 and y=0 axes drawn darker.
grid x <xmin> to <xmax> step <dx> y <ymin> to <ymax> step <dy>
grid x -5 to 5 step 1 y -5 to 5 step 1 grid x 0 to 10 step 2 y 0 to 10 step 2
| Field | Constraint | Description |
|---|---|---|
xmin / xmax | xmin < xmax | Horizontal logical bounds |
ymin / ymax | ymin < ymax | Vertical logical bounds |
dx / dy | > 0 | Grid line interval |
Point
Declares a named point. Points render as small filled circles and serve as anchors for other shapes.
point <id> (<x>,<y>) point <id> <AnchorExpr>
point A (0,0) # Absolute coordinate point B A + (2,1) # Offset from another point point P C.center + (1,0) # Offset from circle center point Q T.p2 # Second vertex of polygon T
Segment
Draws a line between two anchor expressions. Renders as an SVG <line>.
segment <id> from <AnchorExpr> to <AnchorExpr> [style]
segment AB from A to B segment S from (-2,0) to (2,0) stroke red width 3 segment R from A to C.center stroke blue
| Anchor | Returns |
|---|---|
segId.from | Start point of the segment |
segId.to | End point of the segment |
Circle
Draws a circle. The radius is specified in logical (grid) units. Renders as SVG <circle>.
circle <id> center <AnchorExpr> r <number> [style]
circle C center A r 2 circle C center (0,0) r 3 stroke blue fill rgba(0,0,255,0.1) circle D center C.center r 0 # Renders as a dot
| Anchor | Returns |
|---|---|
circleId.center | Center point of the circle |
Polygon
Draws a closed polygon through a sequence of anchor expressions. Requires at least 3 points. Renders as SVG <polygon>.
polygon <id> points <AnchorExpr> <AnchorExpr> <AnchorExpr> ... [style]
polygon T points A B (1,2) polygon Q points (-1,-1) (1,-1) (1,1) (-1,1) fill rgba(255,0,0,0.2)
| Anchor | Returns |
|---|---|
polyId.p1, p2, p3, … | The Nth vertex (1-indexed) |
polyId.centroid (label only) | Geometric center of the polygon |
Anchor Expressions
An anchor expression resolves to a 2D coordinate. They are used wherever a position is needed.
AnchorExpr ::= (x,y) # Literal coordinate | pointId # Named point | shapeId.anchor # Named anchor on a shape | AnchorExpr + (dx,dy) # Vector offset
| Shape | Anchor | Description |
|---|---|---|
| point | pointId | The point itself |
| circle | circleId.center | Center of the circle |
| polygon | polyId.p1 … polyId.pN | Nth vertex |
| segment | segId.from, segId.to | Endpoints |
# ✓ Right-hand side must always be a literal (dx,dy) point P A + (1,0) point Q C.center + (-1,2) # ✗ Cannot add two anchor refs together point B A + A # Error: expected (dx,dy)
Styling
Style tokens are appended inline after the shape declaration. All tokens are optional; unspecified properties use their defaults.
circle C center (0,0) r 2 stroke blue fill rgba(0,100,255,0.15) width 3 segment S from A to B stroke #e07b54 width 2 polygon T points A B (1,2) fill rgba(255,0,0,0.2) stroke red
| Token | Default | Accepts |
|---|---|---|
stroke | black | Any CSS color: named, hex, rgb, rgba |
fill | none | Any CSS color, or none |
width | 2 | Number ≥ 0 (pixels) |
width is an error.
Labels
Attaches a text annotation to a declared shape or point. Labels are always rendered as the topmost layer, after all shapes.
label <target> "<text>"
label A "Origin" label C "Unit Circle" label T "Triangle" label AB "Hypotenuse" # Multiple labels on the same target are both rendered (stacked) label A "First" label A "Second"
| Target Type | Label Anchors At |
|---|---|
| point | Exact point location |
| circle | Center of the circle |
| segment | Midpoint of the segment |
| polygon | Centroid of the polygon |
Rendering Order
Geon renders in three layers, in this fixed sequence:
label appears in source
circle A center (0,0) r 2 # drawn first → underneath circle B center (1,0) r 2 # drawn second → on top of A
Coordinate System
Geon uses a standard mathematical coordinate system: Y increases upward. This is the opposite of SVG's default (where Y increases downward). The mapping is handled automatically.
# Logical space (Geon) → SVG pixel space (xmin, ymax) top-left → (0, 0) (xmax, ymin) bottom-right → (width, height) (0, 0) origin → center (if grid is symmetric)
JavaScript API
The global Geon object exposes a single function.
Geon.render(source: string, container: HTMLElement): Result Result ::= { success: true } | { success: false, error: string }
| Condition | Effect |
|---|---|
| Success | Clears container, appends the rendered <svg> |
| Error | Clears container, appends a styled error message div; returns { success: false, error } |
const result = Geon.render(source, document.getElementById('canvas')); if (!result.success) { console.error('Geon error:', result.error); }
Error Reference
All errors include a line number where possible. Errors stop execution immediately — no partial rendering occurs.
| Error | Trigger |
|---|---|
Missing scene declaration |
No scene statement in program |
Missing grid declaration |
No grid statement in program |
Undefined identifier 'X' |
Referencing a name that was never declared |
Duplicate identifier 'X' |
Declaring the same name twice |
Circular reference |
A point that depends on itself (directly or transitively) |
Invalid anchor 'X.prop' |
Accessing a property that does not exist on the shape (e.g. circle.radius) |
Polygon requires >= 3 points |
A polygon with fewer than 3 vertices |
Radius must be >= 0 |
A circle with a negative radius |
Width must be >= 0 |
A negative width style token |
Grid step must be > 0 |
A step value of zero or negative |
Grid x min must be < x max |
Inverted grid range |
Undefined label target 'X' |
label X "..." where X was never declared |
Unknown keyword 'X' |
Unrecognized keyword — also catches capitalized keywords like Point |
Malformed coordinate |
Coordinates like (1,) or (,2) |
Expected (dx,dy) after '+' |
Vector addition with non-literal right-hand side |
Edge Cases
A summary of how Geon handles boundary and degenerate inputs.
Full Example
A complete Geon program demonstrating all major features: anchor chaining, shape anchors, polygon fill, and labels.
scene 600x400 grid x -5 to 5 step 1 y -5 to 5 step 1 # Define anchor points point A (0,0) point B (3,0) # Draw a segment between them segment AB from A to B stroke #555 width 2 # Circle centered on A circle C center A r 2 stroke blue fill rgba(0,0,255,0.08) # Triangle using A, B, and a literal coordinate polygon T points A B (1,3) fill rgba(255,100,0,0.15) stroke orange # Point derived from circle center point P C.center + (1,0) # Labels label A "Origin" label C "Circle C" label T "Triangle" label AB "Base"