Craft beautiful geometric art using code.
Use the code basics like loops, control flow and specialized functions to generate your geometry artworks.
Examples of g2D Geometry Art
Installation
Go get
$ go get u github.com/lucasepe/g2d
ReadyToUse Releases
Here you can find g2d
already compiled for:
 MacOS
 Linux
 Windows
How to use
To execute a local g2d
script:
$ g2d /path/to/myscript.g2d
To execute a g2d
script stored somewhere on the web:
$ g2d http://mycoolsite.com/remote/path/to/myscript.g2d
Use the directory
(or the shorter d
) flag to specify a destination folder for the generated PNG images.
The g2D
Programming Language Syntax
Exampleprograms can be found beneath examples/ which demonstrate these things, as well as parts of the standardlibrary.
Types
g2D has the following data types: bool
, int
, float
, str
, array
, and fn
.
Type  Syntax  Notes 

bool  true false 

int  0 42 1234 5 
is a signed 64bit integer 
float  0.5 4.2 1.234 5.5 
is a 64bit doubleprecision floating point 
str  "" "foo" "\"quotes\" and a\nline break" 
are immutable arrays of bytes 
array  [] [1, 2] [1, 2, 3] 
growable arrays (use the append() builtin) 
fn  fn(a, b) { ... } 
defines a custom function 
Bindings
Variables are bounded using the :=
operator.
a := 3
b := 1.2
Variables may be integers, floats, strings, or arrays/hashes.
To update a variable you can simply specify the equals =
operator:
a := 3 // Binding
a = a + 5 // Updating
Arithmetic operations
g2D
supports all the basic arithmetic operation of int
and float
types.
a := 5
b := 3
c := a + b
d := c / 2
e := d * d
Builtin containers
g2d
has one builtin containers: array
.
Arrays
An array is a list which organizes items by linear sequence. Arrays can hold multiple types.
a := [1, 2.3, "hello!"]
b := [false, true, "Hello World", 3, 3.13]
Adding to an array is done via the push
builtin function:
a = append(a, "another")
You can iterate over the contents of an array like so:
i := 0
while( i < len(a) ) {
print( "Array index ", i, " contains ", a[i], "\n")
i = i + 1
}
With the definition we included that produces this output:
Array index 0 contains 1
Array index 1 contains 2.3
Array index 2 contains hello!
Array index 3 contains another
Functions
g2D
uses fn
to define a function which will be assigned to a variable for naming/invocation purposes:
sum := fn(a, b) { return a + b }
print(sum(5,3), "\n") // Outputs: 8
print(sum(2.5,7.5), "\n") // Outputs: 10
Functions can be passed as values to others functions:
addTwo := fn(a, b, f) {
return 2 + f(a, b)
}
tot := addTwo(68, 1, sum)
print(tot, "\n") // Outputs: 71
Functions inside functions
multiplier := fn(q) {
return fn(x) {
return x*q
}
}
multThree := multiplier(3)
print(multThree(2), "\n") // Outputs: 6
print(multThree(3), "\n") // Outputs: 9
print(multThree(4), "\n") // Outputs: 12
Ifelse statements
g2D
supports ifelse
statements.
max := fn(a, b) {
if (a > b) {
return a;
} else {
return b;
}
}
print( max(1, 2) ) // Outputs: 2
Switch Statements
g2D
supports the switch
and case
expressions:
switch n := randi(10) {
case n % 2 == 0 {
print(n, " is even", "\n")
}
default {
print(n, " is odd", "\n")
}
}
While Loops
g2D
supports only one looping construct, the while
loop:
i := 30
while (i > 0) {
print(i, " ")
i = i  10
}
// 30 20 10
Builtin functions
Core
Function  Description 

exit([status]) 
exits the program immediately with the optional status or 0 
input([prompt] 
reads a line from standard input optionally printing the specified prompt 
print(...) 
output a string to stdout 
printf(pattern, ...) 
output a string to stdout (formatted according the specified pattern) 
sprintf(pattern, ...) 
like printf(...) but returns a string

bool(val) 
converts value to a bool 
float(val) 
converts decimal value str to float  if val is invalid returns null 
int(val) 
converts decimal value str to int  if val is invalid returns null 
str(val) 
returns the string representation of val 
len(iterable) 
returns the length of the iterable (string or array) 
append(array, val) 
returns a new array with value pushed onto the end of array 
Calculation
Function  Description 

abs(x) 
returns the absolute value of x 
atan(x) 
returns the arc tangent, in radians, of x 
atan2(x, y) 
returns the arc tangent of y/x 
cos(x) 
returns the cosine of the radian argument x 
degrees(angle) 
converts radians into degrees 
hypot(p, q) 
returns sqrt(p*p + q*q)

lerp(start, stop, amt) 
calculates a number between two numbers at a specific increment 
map(v, b1, e1, b2, e2) 
remaps a number from one range to another 
max(v1....vn) 
returns the largest value in a sequence of numbers 
min(v1....vn) 
returns the smallest value in a sequence of numbers 
pow(x, y) 
returns x**y , the base x exponential of y

sin(x) 
returns the sine of the radian argument x 
sqrt(x) 
returns the square root of x 
radians(angle) 
converts a degree measurement to its corresponding value in radians 
randf([min], [max]) 
returns a random float between min and max  by default min=0.0 and max=1.0 
randi([min], [max]) 
returns a random int between min and max 
Basic graphic functions
Function  Description 

size(w,[h]) 
sets the size of the drawing; when both w and h are specified creates a rectangular image otherwise creates a squared one 
viewport(xMin, xMax, yMin, yMax, xOffset, yOffset) 
sets up userdefined coordinate system; performs a screen reset (drawings are cleared) 
clear() 
fills the entire image with the current color; clear all drawings 
fillColor(hexcolor) 
sets the fill color to the specified hexcolor; example fillColor("#ff0000") 
fillColor(r, g, b, [a]) 
sets the fill color to r,g,b,a values  should be between 0 and 255, inclusive 
strokeColor(hexcolor) 
sets the stroke color to the specified hexcolor; example strokeColor("#ff0000") 
strokeColor(r, g, b, [a]) 
sets the stroke color to r,g,b,a values  should be between 0 and 255, inclusive 
strokeWeight(weight) 
sets the stroke thickness to the specified width 
dashes([s1, s2, ...sn]) 
sets the current dash pattern to use (call with zero arguments to disable dashes) 
stroke() 
strokes the current path with the current stroek color and line width the path is cleared after this operation 
fill() 
fills the current path with the current fill color; open subpaths are implicity closed. The path is cleared after this operation 
fillAndStroke() 
fills the current path with the current fill color and strokes it with the current stroke color; the path is cleared after this operation 
push() 
saves the current state of the graphic context by pushing it onto a stack 
pop() 
restores the last saved graphic context state from the stack 
snapshot([filename]) 
creates a PNG image with the current drawings. If filename is omitted, it will be autogenerated with a progressive counter, that will be incremented on each snapshot() invocation; this is useful if you wants to generate an animation later (using all the generated PNG images). 
xpos() 
returns the current X position (if there is a current point) 
ypos() 
returns the current Y position (if there is a current point) 
Graphic primitives
Function  Description 

arc(x, y, r, sa, ea) 
draws a circular arc centered at (x, y) with a radius of r. The path starts at sa angle_, ends at ea angle, and travels in the direction given by anticlockwise 
circle(x, y, r) 
draws a circle centered at [x, y] coordinates and with the radius r 
ellipse(x, y, rx ,ry) 
draws an ellipse centered at [x, y] coordinates and with the radii rx and ry 
line(x1, y1, x2, y2) 
draws a line from point (x1, y1) to point (x2, y2) 
point(x, y) 
draws a point at specified coordinates (the size is equal to the stroke weight) 
quad(x1, y1, x2,y2, x3,y3, x4,y4) 
draws a a four sided polygon using the provided vertices 
rect(x, y, w, h, [tl, tr, br, bl]) 
draws a (w x h) rectangle with upper left corner located at (x, y). If only one radius is specified, all the corners have the same bending, if tl, tr, br, bl are specified, each corner can have a different curvature 
triangle(x1,y1, x2,y2, x3,y3) 
draws a triangle using the provided vertices 
star(cx, cy, n, or, ir) 
draws a star cx, cy is the center, n the number of spikes, or and ir the outer and inner radius 
Paths
Function  Description 

beginPath() 
starts a new path 
closePath() 
adds a line segment from the current point to the beginning of the current subpath 
moveTo(x, y) 
sets the begin of a new subpath starting at the specified x, y point 
lineTo(x, y) 
adds a line segment to the current path starting at the current point 
arcTo(x1, y1, x2, y2, r) 
adds a circular arc to the current subpath, using the given control points and radius 
quadraticCurveTo(x1, y1, x2, y2) 
adds a quadratic Bézier curve to the current subpath; x1, y1 is the control point and x2, y2 is the end point 
Transform
Function  Description 

rotate(angle, [x, y] ) 
updates the current matrix with a anticlockwise rotation; when x, y are specified, rotation occurs about this point, otherwise rotation occurs about the origin (angle is in radians) 
scale(sx, sy, [x, y]) 
updates the current matrix with sx, sy scaling factor; when x,y are specified, scaling occurs about this point, otherwise scaling occurs about origin. 
translate(x, y) 
updates the current matrix with a translation to x and y 
identity() 
resets the current transformation matrix to the identity matrix 
transform(x, y) 
multiplies the point x, y by the current matrix, returning a transformed position 
Text
Function  Description 

text(str, x, y, [ax, ay]) 
draws the specified text str at the specified anchor point x, y; the anchor point is x  w * ax, y  h * ay, where w, h is the size of the text (by default ax=0.5, ay=0.5 to center the text at the specified point) 
textWidth(str) 
returns the rendered width of the specified text str given the current font face 
fontSize(size) 
sets the font height 
Images
Function  Description 

imageGet(path/to/png) 
loads a PNG image from the local filesystem 
imageAt(im, x, y, [ax, ay]) 
draws the specified image im at the specified anchor point x, y; (ax and ay are the x and y offsets) use ax=0.5, ay=0.5 to center the image at the specified point 
Top comments (2)
Well, honestly, for the last four months I’ve been drawing around 30 hours per week. I’ve gone through various books and videos, learned a ton, and even completed a couple 11 x 17 comic book pages of original art. However, I began suffering from the problem any learner faces in the age of the internet, which is the sheer overabundance of learning material available. Oftentimes I’d spend hours sifting through lists of the best drawing books and creating playlists of YouTube videos. I became more focused on curating the best resources than actually going through those resources. I would start one book, then wonder if I should be working on a different book, and I’d start jumping back and forth. Jumping around so often, I started to lose the big picture, and I didn’t give each resource the full attention it deserves. I was always focused on getting through one book so I could get get to the next. I realized that I needed 1) more structure and 2) a different attitude.