Skip to content
gifboy logo

Examples

Basic Examples

Clear

Just draw different colors to the background.

1local color=0 -- colors go from 0 to 15
2delay(500) -- every draw call will take 0.5 seconds
3
4function draw()
5 clear(color) -- clear the screen with current color
6 color=color+1 -- increment color every
7 if color==16 then stop() end -- stop after last color was reached
8end


Shapes

Example with all basic shapes.

1clear(7) -- white background
2line(16,12,48,36,0) -- line from (16,12) to (48,36) in black
3rect(60,12,24,24,9) -- rectangle outline at (60,12) with width and height of 24 in orange
4rectfill(96,12,48,24,12) -- filled rectangle at (96,12) with width 48 and height 24 in blue
5circle(80,80,24,8) -- circle outline at the center with radius 24 in red
6circlefill(80,80,18,2) -- filled circle at center with radius 18 in dark purple
7point(80,80,7) -- white point at center
8arc(30,80,18,0,270,12) -- arc outline at (30,80) with radius 18 going from 0 to 270 degress in blue
9arcfill(130,80,18,0,180,14) -- filled arc at (130,80) with radius 18 going from 0 to 180 degress in pink
10text('this is a text',16,130,0) -- text at (16,130) in black
11icon('a',118,124,9) -- a strange icon at (118,124) in orange
12
13--- note: only 1 frame is created, as there is no draw() loop


Scaled and rotated text

Play around with text.

1local angle=0 -- rotation angle
2local sf=1 -- scale factor
3local sf_dx=.02 -- change of scale factor
4local runs=0 -- number of runs
5
6function draw()
7 scale(sf,sf) -- scale the screen by scale factor
8 clear(1)
9 angle=angle+1 -- increment angle by 1 degree
10 translate(80/sf,80/sf) rotate(angle) -- rotate around center (scaled)
11 text("AWESOME!",-12*sf+1,-4*sf-1,9)
12 text("AWESOME!",-12*sf,-4*sf,7) -- white text and orange shadow, relative to center
13 transform(1,0,0,1,0,0,true) -- reset all scaling, rotating and moving
14 sf=sf+sf_dx -- change scale factor each frame
15 if sf>2 then sf_dx=-0.02 runs=runs+1 end -- if scale factor is >2 decrease from now on
16 if sf<1 then
17 if runs<3 then sf_dx=0.02 else sf_dx=0 end -- increase again, if factor <1, but only 3 times
18 if angle>360 then stop() end -- stop after full rotation
19 end
20end


Fun with Icons

Draw icons to screen.

1-- check out https://fontmeme.com/fonts/pixel-icons-compilation-font/
2-- for list of characters/icons.
3
4clear(15)
5color(1) -- change draw color to dark blue (unless other color is used)
6icon('abcdefg',6,24)
7icon('hijklmn',6,48)
8icon('opqrstu',6,72)
9icon('vwxyz',6,96)


Sprites

It's possible to draw sprites to the screen by defining strings with pixel data.

1-- Define heart pixel data
2heart={}
3
4heart[1] = [[
5 82 82
687828882
788888882
888888882
9 888882
10 8882
11 82
12]]
13
14heart[2] = [[
15 82 82
1688728882
1787888882
1888888882
19 888882
20 8882
21 82
22]]
23
24heart[3] = [[
25 82 82
2688828882
2788788882
2888888882
29 888882
30 8882
31 82
32]]
33
34-- setup
35delay(250)
36scale(8,8)
37clear(12)
38line(8,15,12,15,5)
39
40-- draw the sprites
41for i=1,len(heart) do
42 sprite(heart[i],8,6,6)
43 render()
44end


Text Positioning

Instead of using pixel coordinates you can also position (multiline-)text with some convenience functions.

1linedash(2,2)
2line(80,0,80,160,6)
3line(0,80,160,80,6)
4
5-- Position text conveniently
6text('left\ntop','left','top',7)
7text('center\ntop','center','top',7)
8text('right\ntop','right','top',7)
9
10textb('left\ncenter','left','center',7,9)
11textb('center\ncenter','center','center',7,8)
12textb('right\ncenter','right','center',7,9)
13
14text('left\nbottom','left','bottom',10)
15text('center\nbottom','center','bottom',10)
16text('right\nbottom','right','bottom',10)


Simple Path

Draw a triangle by using path() functions.

1clear(12)
2path_begin() -- begin path
3 path_move(32,128) -- move pointer to bottom left
4 path_line(80,32) -- make line to top middle
5 path_line(128,128) -- make line to bottom right
6path_close() -- close path
7path_fill(14) -- fill pink
8path_stroke(7) -- draw white outline


Transparency

Draw transparent shapes by using the alpha.

1clear(15)
2rectfill(24,24,80,80,12) -- draw a blue rectangle
3alpha(0.5) -- set transparency to 50%
4rectfill(56,56,80,80,8) -- draw a red rectangle (using transparency now)


Line Effects

Use styling effects for all line draw operations.

1local offset=0 -- offset parameter
2
3function draw()
4 offset=offset-.5
5 clear(2)
6 linewidth(2) -- set line width to 2 pixels
7 linedash(4,4,offset) -- use linedash effect: 4px are drawn, 4px are not drawn, segments are offsetted each frame
8 rect(16,62,128,32,7) -- rectangle outline will use the effect
9 text("YOU WIN!","center","center")
10 if offset< -6 then stop() end
11end


Clipping

Clip the screen area to allow drawing only on certain areas.

1local x=0
2clip(0,0,80,160) -- clip the draw area to the left half of the screen
3
4function draw()
5 clear(6)
6 x=x+1
7 rectfill(x,72,16,16,5) -- draw a rectangle, will disappear in the right half of the screen
8 if x>144 then stop() end
9end


Palette Swapping

Need different colors? Just change them.

1-- Change first 5 colors
2palette(0,'cadca0')
3palette(1,'9bbb0e')
4palette(2,'8aac0f')
5palette(3,'30622f')
6palette(4,'0f380e')
7
8-- All draw operations will now use these colors
9rectfill(80,80,80,80,1)
10rectfill(0,80,80,80,2)
11rectfill(80,0,80,80,3)
12rectfill(0,0,80,80,4)
13circlefill(80,80,40,0)
14circle(80,80,40,2)


Advanced Examples

Heart

Using paths to draw complex shapes.

1local w=1
2local dw=.2
3translate(7, 7)
4
5function draw()
6 w=w+dw
7 if w>6 then dw=-.2 end
8 if w<1 then dw=.2 end
9 linewidth(w)
10 clear(12)
11 -- heart
12 path_begin()
13 path_move(75, 40)
14 path_bezier(75, 37, 70, 25, 50, 25)
15 path_bezier(20, 25, 20, 62.5, 20, 62.5)
16 path_bezier(20, 80, 40, 102, 75, 120)
17 path_bezier(110, 102, 130, 80, 130, 62.5)
18 path_bezier(130, 62.5, 130, 25, 100, 25)
19 path_bezier(85, 25, 75, 37, 75, 40)
20 path_fill(8)
21 path_stroke(7)
22 if frames()>50 then stop() end
23end


Falling Down

A non-looping example. Also pixel colors are read to detect if square is on the ground.

1loop(-1)
2local y = 0
3local dy = 1
4
5function draw()
6 clear(10)
7 line(0, 80, 160, 80, 0)
8 y = y + dy
9 if pixel(80, y + 8) == 0 then dy = 0 text("Boom!", 12, 12, 0) stop() end
10 rectfill(76, y, 8, 8, 8)
11end


Controlling Frame Speed

In this example the delay() command is heavily used to control the speed of individual frames.

1-- Helper functions
2-- Show rolling text, controlled by delay() and render()
3function text_roll(label, time)
4 delay(time)
5 for i=1,string.len(label) do
6 content=string.sub(label, 1, i)
7 clear(12)
8 textb(content,'center','center',7,0)
9 icon('t',128,128,7)
10 render()
11 end
12end
13
14-- Show text, controlled by delay() and render()
15function text_punch(label, time)
16 delay(time)
17 clear(12)
18 textb(label,'center','center',7,0)
19 icon('t',128,128,7)
20 render()
21end
22
23-- Wait = just render() a new frame with a certain delay
24function wait(time)
25 delay(time)
26 render()
27end
28
29-- Animation
30text_roll("Ooh, baby, do you know", 110)
31wait(80)
32text_punch("Ooh, baby, do you know\nwhat",400)
33text_punch("Ooh, baby, do you know\nwhat it's",400)
34text_punch("Ooh, baby, do you know\nwhat it's worth",400)
35
36wait(800)
37
38text_roll("Ooh, heaven is a",115)
39wait(80)
40text_punch("Ooh, heaven is a\nplace",400)
41text_punch("Ooh, heaven is a\nplace on",400)
42text_punch("Ooh, heaven is a\nplace on earth",400)
43wait(600)


Jumping Fellas

An advanced example using cosinus to draw a skipping rope. The "fellas" are drawn as ascii art. (^_^)

1guy="웃"
2j=0
3
4function draw()
5 clear(12)
6 k=j
7 j=math.cos(frames()*.15)*12
8 y=j+44
9 rectfill(16,51,127,92,1)
10 rectfill(50,45,60,99,12)
11 rectfill(70,64,20,80,7)
12 rectfill(0,142,180,28,9)
13 c=6
14 if k>=j then text(guy,73,y,8) c=10 end
15 for i=48,112 do
16 point(i,math.cos(math.rad (i*2.2))*j+44,c)
17 end
18 if k<j then text(guy,73,y,8) end
19 if y<44 then text("hop",73,y-16,7) end
20 o=j*-.1
21 text(guy,38+o,42,1)
22 text(guy,111-o,42,1)
23 if frames()>40 then stop() end
24end


Generative Art

An example how #genart can be created using gifboy.

1rand=math.random
2local count=0
3delay(500)
4
5function draw()
6 -- generate points
7 q={} -- points to draw
8 for x=0,30 do
9 for y=0,30 do
10 p={} -- temporary table
11 p.u=x/18
12 p.v=y/18
13 p.r=math.floor(rand(2))*rand(4)
14 p.c=rand(6)+7
15 if rand()>.5 then table.insert(q,p) end
16 end
17 end
18
19 -- draw the work
20 clear(7)
21 count=count+1
22 for i=1,len(q),1 do
23 p=q[i]
24 x=spread(12,96,p.u)
25 y=spread(12,96,p.v)
26 circlefill(x,y,p.r,p.c)
27 end
28 if count>9 then stop() end
29end
30
31-- spread points helper
32function spread(x,y,pos)
33 return y*pos+x*(1-pos)
34end


Reflections

Achieving a water reflection effect by using pixelcpy().

1guy="웃"
2j=0
3
4function draw()
5 clear(10)
6 draw_scene()
7 --mirror bottom 50%
8 for i=80,1,-1 do
9 pixelcpy((160-i)*160,i*160,160)
10 end
11 -- blue overlay
12 alpha(.5)
13 rectfill(0,81,160,80,12)
14 alpha(1)
15 line(0,81,160,81,0)
16 if frames()>40 then stop() end
17end
18
19function draw_scene()
20 k=j
21 j=math.cos(frames()*.15)*12
22 y=j+44
23 rectfill(16,51,127,92,1)
24 rectfill(50,45,60,99,10)
25 rectfill(70,64,20,80,7)
26 rectfill(0,142,180,28,9)
27 c=6
28 if k>=j then text(guy,73,y,8) c=8 end
29 for i=48,112 do
30 point(i,math.cos(math.rad (i*2.2))*j+44,c)
31 end
32 if k<j then text(guy,73,y,8) end
33 if y<44 then text("hop",73,y-16,7) end
34 o=j*-.1
35 text(guy,38+o,42,1)
36 text(guy,111-o,42,1)
37end


Complex Clipping

You can use path_clip() to set an existing path as the clipping area. This can be used to achieve some complex effects while drawing.

1-- draw all 16 colors to the screen
2-- starting color is defined by c
3function draw_colors(c)
4 c=c-1
5 for y=0,160,10 do
6 c=c+1
7 rectfill(0,y,160,10,c)
8 end
9end
10
11-- set a star-shaped clipping area
12function clip_star(cx, cy, spikes, outer_radius, inner_radius)
13 rot = math.pi / 2 * 3
14 x = cx
15 y = cy
16 step = math.pi / spikes
17 path_begin()
18 path_move(cx, cy - outer_radius)
19 for i=0,spikes-1 do
20 x=cx+math.cos(rot)*outer_radius
21 y=cy+math.sin(rot)*outer_radius
22 path_line(x, y)
23 rot=rot+step
24 x=cx+math.cos(rot) * inner_radius
25 y=cy+math.sin(rot) * inner_radius
26 path_line(x, y)
27 rot=rot+step
28 end
29 path_line(cx, cy - outer_radius)
30 path_close()
31 path_clip()
32end
33
34col=-1 -- starting color for draw_colors
35size=-16 -- additional size for star
36dsize=1 -- direction of size effect
37function draw()
38 if frames()%8==0 then col=col+1 end -- change starting_color every 8 frames
39 if frames()>64 then dsize=-1 end -- grow star in size ...
40 if size<-16 then stop() end -- ... then shrink back to original value
41 size=size+dsize -- change size for start
42 clear(2) -- background color
43 clip_star(80,80,5,32+size,16+size) -- apply star clip
44 draw_colors(col) -- draw colors (only in clipped area)
45end


Infinite Space

A starfield example, using lua tables and simple 3D projections.

1flr=math.floor
2rnd=math.random
3stars={}
4stars.points={}
5stars.count=130
6stars.distance=180
7
8function init()
9 local range=2500
10 for i=1,stars.count do
11 xp=flr(range-rnd(range*2))
12 yp=flr(range-rnd(range*2))
13 zp=rnd(stars.distance)
14 table.insert(stars.points,{x=xp,y=yp,z=zp})
15 end
16end
17
18init()
19
20function draw()
21 clear(0)
22 update()
23 if frames()>300 then stop() end
24end
25
26function update()
27 for i=1,len(stars.points) do
28 stars.points[i].z=stars.points[i].z-1
29 if stars.points[i].z<=0 then
30 stars.points[i].z=stars.distance
31 end
32 end
33
34 for i=1,len(stars.points) do
35 local cz=stars.points[i].z
36 local cx=stars.points[i].x/cz
37 local cy=stars.points[i].y/cz
38 if cx< -80 or cx>80 then
39 stars.points[i].z=stars.distance
40 end
41 if cy< -80 or cy>80 then
42 stars.points[i].z=stars.distance
43 end
44 local cols={7,6,5}
45 local ci=1+flr(cz/stars.distance * len(cols))
46 if ci>3 then ci=3 end
47 rectfill(80+cx,80+cy,2,2,cols[ci])
48 end
49end


3D Cube

A simple 3D cube wireframe, using screen projections.

1pts={}
2for z=-1,1,2 do
3 for y=-1,1,2 do
4 for x=-1,1,2 do
5 table.insert(pts,{x,y,z})
6 end
7 end
8end
9lines={{1,2},{2,4},{1,3},{3,4},{5,6},{5,7},{6,8},{7,8},{1,5},{2,6},{3,7},{4,8}}
10cam={0,0,-3}
11fov=80
12linewidth(6)
13linedash(2,2)
14
15function draw_cube()
16 for k,v in pairs(lines) do
17 draw_line(pts[v[1]],pts[v[2]],10)
18 end
19end
20
21function draw_line(p1,p2,c)
22 x1 = (p1[1]-cam[1])*fov/(p1[3]-cam[3]) + 80
23 y1 = -(p1[2]-cam[2])*fov/(p1[3]-cam[3]) + 80
24 x2 = (p2[1]-cam[1])*fov/(p2[3]-cam[3]) + 80
25 y2 = -(p2[2]-cam[2])*fov/(p2[3]-cam[3]) + 80
26 line(x1,y1,x2,y2,c)
27end
28
29function rotate_shape(shape,a,r)
30 new_shape = {}
31 for k,v in pairs(pts) do
32 table.insert(new_shape, rotate_point(v,a,r)) -- Rotate the point and add it to the new shape
33 end
34 return new_shape
35end
36
37function rotate_point(p,a,r)
38 if a==1 then
39 x,y,z = 3,2,1
40 elseif a==2 then
41 x,y,z = 1,3,2
42 elseif a==3 then
43 x,y,z = 1,2,3
44 end
45 _x = math.cos(r)*(p[x]) - math.sin(r) * (p[y])
46 _y = math.sin(r)*(p[x]) + math.cos(r) * (p[y])
47 np = {}
48 np[x] = _x
49 np[y] = _y
50 np[z] = p[z]
51 return np
52end
53
54function draw()
55 axis=1
56 if frames()<60 then axis=2 end
57 if frames()>120 then axis=3 end
58 if frames()>180 then stop() end
59 clear()
60 pts = rotate_shape(pts,axis,.0532)
61 draw_cube()
62end


Raycasting

No graphics engine is complete without showing a DOOM-like demo. Here we go: a raytracer demo similar to the graphical style of Wolfenstein 3D.

1--gifboy-wolfenstein
2--based on lodev's and yonaba's raycasting tutorial
3
4map={
5width=10,
6height=10,
7{1,0,0,0,1,1,1,1,1,1},
8{1,0,0,0,0,0,0,0,0,1},
9{1,0,0,0,0,0,0,0,0,1},
10{1,0,0,0,0,0,0,0,0,1},
11{1,0,0,0,0,0,0,0,0,1},
12{1,0,0,0,1,0,0,0,0,1},
13{1,1,0,0,1,1,0,0,0,1},
14{1,0,0,0,1,0,0,0,0,1},
15{1,1,0,0,1,1,0,0,0,1},
16{1,1,1,1,1,1,1,2,2,1}
17}
18
19posx=1
20posy=3
21dirx=1
22diry=0
23planex=0
24planey=0.66
25rotation=math.pi/2
26direction=1
27screenx=160
28screeny=160
29colorRoof=6
30colorSky=5
31colorStripes=10
32
33--3D loop
34delay(150)
35for i=1,24 do
36clear()
37x=0
38for x=0,screenx do
39camx=2*x/screenx-1
40rayposx=posx
41rayposy=posy
42raydirx=dirx+planex*camx
43raydiry=diry+planey*camx
44mapx=rayposx
45mapy=rayposy
46sidedistx=0
47sidedisty=0
48deltadistx=math.sqrt(1+(raydiry*raydiry)/(raydirx*raydirx))
49deltadisty=math.sqrt(1+(raydirx*raydirx)/(raydiry*raydiry))
50perp=0
51stepx=0
52stepy=0
53hit=0
54side=0
55if raydirx<0 then
56stepx=-1
57sidedistx=(rayposx-mapx)*deltadistx
58else stepx=1
59sidedistx=(mapx+1-rayposx)*deltadistx
60end
61if raydiry<0 then
62stepy=-1
63sidedisty=(rayposy-mapy)*deltadisty
64else stepy=1
65sidedisty=(mapy+1-rayposy)*deltadisty
66end
67while hit==0 do
68if sidedistx<sidedisty then
69sidedistx=sidedistx+deltadistx
70mapx=mapx+stepx
71side=0
72else
73sidedisty=sidedisty+deltadisty
74mapy=mapy+stepy
75side=1
76end
77if map[math.floor(mapx)][math.floor(mapy)]>0 then hit=1 end
78end
79if side==0 then
80perp=math.abs((mapx-rayposx+(1-stepx)/2)/raydirx)
81else
82perp=math.abs((mapy-rayposy+(1-stepy)/2)/raydiry)
83end
84lineheight=math.abs(screeny/perp)
85draw=-lineheight/2+screeny/2
86if draw<0 then draw=0 end
87drawE=lineheight/2+screeny/2
88if drawE>=screenx then drawE=screenx-1 end
89a=65
90b=58
91c=63
92if side==1 then
93a=a-30
94b=b-30
95c=c-30
96end
97if map[math.floor(mapx)][math.floor(mapy)]==2 then a,b,c=255,199,101 end
98palette(14,a,b,c)
99bandUp=screeny/2+drawE
100bandDown=screeny/2+draw
101rectfill(x,draw,1,drawE,14);
102rectfill(x,drawE,1,272,colorRoof);
103rectfill(x,0,1,draw,colorSky);
104rectfill(x,bandUp/2,1,1,colorStripes)
105rectfill(x,bandDown/2,1,1,colorStripes)
106rectfill(x,screeny/2,1,1,colorStripes)
107end
108render()
109if frames()<5 then posx=posx+1 end
110if frames()>=5 and frames()<11 then posy=posy+1 end
111if frames()>=15 and frames()<20 then posx=posx+1 end
112end
113
114-- scene end
115delay(2000)
116clear()
117scale(2,2)
118textb('Level Won','center','center',7,1)
119render()
120stop()

Where to go next

Do you want to deepen your understanding of the available gifboy commands?

Check out the Documentation.