diff --git a/repbuild/src/main.rs b/repbuild/src/main.rs
index c308774..af09c6d 100644
--- a/repbuild/src/main.rs
+++ b/repbuild/src/main.rs
@@ -336,8 +336,8 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
                 "-drive", "file=target/disk.img,format=raw",
                 "-m", "4G",
                 "-smp", "cores=4",
-                // "-enable-kvm",
-                "-cpu", "Broadwell-v4",
+                "-enable-kvm",
+                "-cpu", "host",
                 "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"
             ]);
         }
diff --git a/sysdata/libraries/stn/src/lib.hb b/sysdata/libraries/stn/src/lib.hb
index e8b9ef3..ff45c3b 100644
--- a/sysdata/libraries/stn/src/lib.hb
+++ b/sysdata/libraries/stn/src/lib.hb
@@ -1,4 +1,5 @@
 string := @use("rel:string.hb")
 log := @use("rel:log.hb")
 memory := @use("rel:memory.hb")
-buffer := @use("rel:buffer.hb")
\ No newline at end of file
+buffer := @use("rel:buffer.hb")
+math := @use("rel:math.hb")
\ No newline at end of file
diff --git a/sysdata/libraries/stn/src/math.hb b/sysdata/libraries/stn/src/math.hb
new file mode 100644
index 0000000..2fd1d02
--- /dev/null
+++ b/sysdata/libraries/stn/src/math.hb
@@ -0,0 +1,7 @@
+abs := fn(x: int): int {
+	mask := x >> 31
+	return (x ^ mask) - mask
+}
+min := fn(a: int, b: int): int {
+	return b + (a - b & a - b >> 31)
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/UNTESTED_FUNCTIONS b/sysdata/programs/fb_driver/UNTESTED_FUNCTIONS
new file mode 100644
index 0000000..7c7d0f5
--- /dev/null
+++ b/sysdata/programs/fb_driver/UNTESTED_FUNCTIONS
@@ -0,0 +1,7 @@
+color.blend
+
+lib.composite
+lib.screen2rect
+lib.rect2screen
+
+draw.tri_line
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/meta.toml b/sysdata/programs/fb_driver/meta.toml
index 9863f08..c2659bc 100644
--- a/sysdata/programs/fb_driver/meta.toml
+++ b/sysdata/programs/fb_driver/meta.toml
@@ -1,6 +1,6 @@
 [package]
 name = "fb_driver"
-authors = ["able"]
+authors = ["able", "aurlex"]
 
 [dependants.libraries]
 
diff --git a/sysdata/programs/fb_driver/src/color.hb b/sysdata/programs/fb_driver/src/color.hb
new file mode 100644
index 0000000..51bbf14
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/color.hb
@@ -0,0 +1,27 @@
+ColorBGRA := struct {b: u8, g: u8, r: u8, a: u8}
+
+/* ALL the colo(u)rs you will ever need.
+   they dont work though, cause hblang bug (reg id leaked, again) */
+WHITE := ColorBGRA.{b: 255, g: 255, r: 255, a: 255}
+BLACK := ColorBGRA.{b: 0, g: 0, r: 0, a: 255}
+GRAY := ColorBGRA.{b: 127, g: 127, r: 127, a: 255}
+RED := ColorBGRA.{b: 0, g: 0, r: 205, a: 255}
+GREEN := ColorBGRA.{b: 0, g: 205, r: 0, a: 255}
+YELLOW := ColorBGRA.{b: 0, g: 205, r: 205, a: 255}
+BLUE := ColorBGRA.{b: 205, g: 0, r: 0, a: 255}
+MAGENTA := ColorBGRA.{b: 205, g: 0, r: 205, a: 255}
+CYAN := ColorBGRA.{b: 205, g: 205, r: 0, a: 255}
+LIGHTGRAY := ColorBGRA.{b: 229, g: 229, r: 229, a: 255}
+LIGHTRED := ColorBGRA.{b: 0, g: 0, r: 255, a: 255}
+LIGHTGREEN := ColorBGRA.{b: 0, g: 255, r: 0, a: 255}
+LIGHTYELLOW := ColorBGRA.{b: 0, g: 255, r: 255, a: 255}
+LIGHTBLUE := ColorBGRA.{b: 255, g: 0, r: 0, a: 255}
+LIGHTMAGENTA := ColorBGRA.{b: 255, g: 0, r: 255, a: 255}
+LIGHTCYAN := ColorBGRA.{b: 255, g: 255, r: 0, a: 255}
+
+// i have no clue if this works. please don't me ask how it works. -aurlex
+blend := fn(fg: ColorBGRA, bg: ColorBGRA): ColorBGRA {
+	s := fg + bg
+	m := s - ((fg ^ bg) & 16843008) & 16843008
+	return (m >> 8 | 16777216 * (s < fg)) * 255 | s - m
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/draw.hb b/sysdata/programs/fb_driver/src/draw.hb
new file mode 100644
index 0000000..9faf24a
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/draw.hb
@@ -0,0 +1,113 @@
+.{draw_pixel, screenidx, Transform, Point, Rect, Buffer, FB_WIDTH} := @use("rel:lib.hb")
+ColorBGRA := @use("rel:color.hb").ColorBGRA
+math := @use("../../../libraries/stn/src/lib.hb").math
+
+/* draws a filled rectangle to the screen
+   will be optimised later */
+rect_fill := fn(buffer: Buffer, pos: Point, tr: Transform, color: ColorBGRA): void {
+	n := 0
+	loop if n == tr.height * tr.width break else {
+		*(buffer.write + screenidx(.(n % tr.width + pos.x, n / tr.width + pos.y))) = color
+		n += 1
+	}
+	return
+}
+/* draws a wireframe rectangle to the screen
+   will also be optimised later */
+rect_line := fn(buffer: Buffer, pos: Point, tr: Transform, color: ColorBGRA, thickness: int): void {
+	t := 0
+	y := 0
+	x := 0
+	loop if t == thickness break else {
+		y = pos.y
+		x = pos.x
+		loop if y == pos.y + tr.height break else {
+			*(buffer.write + pos.x + t + FB_WIDTH * y) = color;
+			*(buffer.write + pos.x + tr.width - t + FB_WIDTH * y) = color
+			y += 1
+		}
+		loop if x == pos.x + tr.width break else {
+			*(buffer.write + x + (pos.y + t) * FB_WIDTH) = color;
+			*(buffer.write + x + (pos.y + tr.height - t) * FB_WIDTH) = color
+			x += 1
+		}
+		t += 1
+	}
+	return
+}
+
+// do not use, use line() instead
+line_low := fn(buffer: Buffer, p0: Point, p1: Point, color: ColorBGRA): void {
+	dx := p1.x - p0.x
+	dy := p1.y - p0.y
+	yi := 1
+	if dy < 0 {
+		yi = 0 - 1
+		dy = 0 - dy
+	}
+	D := 2 * dy - dx
+	y := p0.y
+	x := p0.x
+	loop if x == p1.x break else {
+		*(buffer.write + x + y * FB_WIDTH) = color
+		if D > 0 {
+			y += yi
+			D += 2 * (dy - dx)
+		} else {
+			D += 2 * dy
+		}
+		x += 1
+	}
+	return
+}
+// do not use, use line() instead
+line_high := fn(buffer: Buffer, p0: Point, p1: Point, color: ColorBGRA): void {
+	dx := p1.x - p0.x
+	dy := p1.y - p0.y
+	xi := 1
+	if dy < 0 {
+		xi = 0 - 1
+		dx = 0 - dx
+	}
+	D := 2 * dx - dy
+	x := p0.x
+	y := p0.y
+	loop if y == p1.y break else {
+		*(buffer.write + x + y * FB_WIDTH) = color
+		if D > 0 {
+			x += xi
+			D += 2 * (dx - dy)
+		} else {
+			D += 2 * dx
+		}
+		y += 1
+	}
+	return
+}
+
+/* implementation of Bresenham's line algorithm
+   TODO: thickness, might need better math library */
+line := fn(buffer: Buffer, p0: Point, p1: Point, color: ColorBGRA, thickness: int): void {
+	if math.abs(p1.y - p0.y) < math.abs(p1.x - p0.x) {
+		if p0.x > p1.x {
+			line_low(buffer, p1, p0, color)
+		} else {
+			line_low(buffer, p0, p1, color)
+		}
+	} else {
+		if p0.y > p1.y {
+			line_high(buffer, p1, p0, color)
+		} else {
+			line_high(buffer, p0, p1, color)
+		}
+	}
+	return
+}
+
+// theoretically draws a wireframe polygon to the screen. untested.
+tri_line := fn(buffer: Buffer, p0: Point, p1: Point, p2: Point, color: ColorBGRA, thickness: int): void {
+	line(buffer, p0, p1, color, thickness)
+	line(buffer, p1, p2, color, thickness)
+	line(buffer, p2, p0, color, thickness)
+	return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/examples/amogus.hb b/sysdata/programs/fb_driver/src/examples/amogus.hb
new file mode 100644
index 0000000..b045f47
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/examples/amogus.hb
@@ -0,0 +1,26 @@
+.{rect_line} := @use("../draw.hb");
+.{present, create_buffer, clear} := @use("../lib.hb")
+
+/* expected result:
+   the impostor travels left and loops around the screen */
+
+example := fn(): void {
+	// Creates a back buffer, which we write to, to avoid screen flickering
+	buffer := create_buffer()
+	x := 0
+	loop {
+		// draw all our shapes to the back buffer
+		rect_line(buffer, .(200 - x, 80), .(430, 380), .(0, 0, 255, 0), 1)
+		rect_line(buffer, .(630 - x, 120), .(120, 300), .(0, 0, 255, 0), 1)
+		rect_line(buffer, .(200 - x, 460), .(160, 270), .(0, 0, 255, 0), 1)
+		rect_line(buffer, .(470 - x, 460), .(160, 270), .(0, 0, 255, 0), 1)
+		rect_line(buffer, .(140 - x, 140), .(340, 250), .(255, 255, 0, 0), 1)
+		/* push the back buffer to the front buffer
+		   this displays our image to the screen */
+		present(buffer)
+		// erase our old image
+		clear(buffer, .(0, 0, 0, 0))
+		x += 1
+	}
+	return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/examples/colors.hb b/sysdata/programs/fb_driver/src/examples/colors.hb
new file mode 100644
index 0000000..a20f5ff
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/examples/colors.hb
@@ -0,0 +1,27 @@
+.{clear, create_buffer, present} := @use("../lib.hb");
+.{ColorBGRA} := @use("../color.hb")
+
+/* expected result:
+   the screen fades from green to cyan
+   then wraps back to green
+   note that this may happen too fast for you to notice... */
+
+example := fn(): void {
+	// creates a back buffer, which we write to, to avoid screen flickering
+	buffer := create_buffer()
+	color := ColorBGRA.(0, 255, 0, 255)
+	/* have to explicitly say 0 is a u8, or we do something crazy to the colors.
+	   looks like a compiler bug */
+	n := @as(i8, @as(u8, 0)) - 1
+	loop {
+		clear(buffer, color)
+		present(buffer)
+		/* because for some reason just comparing doesnt work.
+		   also looks like a compiler bug */
+		if (color.b & 255) == 255 | (color.b & 255) == 0 {
+			n = 0 - n
+		}
+		color.b += n
+	}
+	return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/examples/front_buffer.hb b/sysdata/programs/fb_driver/src/examples/front_buffer.hb
new file mode 100644
index 0000000..8c1bf5a
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/examples/front_buffer.hb
@@ -0,0 +1,19 @@
+.{front_buffer_ptr, front_buffer_copy, get_front_buffer, Buffer} := @use("../lib.hb");
+
+example := fn(): void {
+    // you can get the raw frontbuffer pointer using
+    raw_buffer := front_buffer_ptr
+    // this buffer is the one that you write individual pixels to
+
+    // you can gete the copy frontbuffer pointer using
+    copy_buffer := copy_buffer_ptr
+    /* this buffer is used for massive writing
+       operations by taking advantage of
+       static copying */
+    
+    // you can construct a buffer like so
+    buffer := Buffer.{write: raw_buffer, copy: copy_buffer}
+    // this is the operation that get_front_buffer does
+    same_buffer := get_front_buffer()
+    return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/examples/lines.hb b/sysdata/programs/fb_driver/src/examples/lines.hb
new file mode 100644
index 0000000..11adde7
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/examples/lines.hb
@@ -0,0 +1,25 @@
+.{line} := @use("../draw.hb");
+.{clear, create_buffer, present, FB_WIDTH, FB_HEIGHT, Point} := @use("../lib.hb")
+
+/* expected result:
+   a 3d-looking blue set of lines
+   created on a blue background */
+
+example := fn(): void {
+	// creates a back buffer, which we write to, to avoid screen flickering
+	buffer := create_buffer()
+	// fill the screen in blue
+	clear(buffer, .(100, 50, 0, 255))
+	p0 := Point.(0, 0 - 1)
+	p1 := Point.(0, FB_HEIGHT - 1)
+	loop if p0.y >= FB_HEIGHT break else {
+		// draw a line between p0 and p1
+		line(buffer, p0, p1, .(255, 180, 100, 255), 3)
+		p0.y += FB_HEIGHT >> 6
+		p1.x += FB_WIDTH >> 6
+	}
+	/* push the back buffer to the front buffer
+	   this displays our image to the screen */
+	present(buffer)
+	return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/examples/square.hb b/sysdata/programs/fb_driver/src/examples/square.hb
new file mode 100644
index 0000000..84b3994
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/examples/square.hb
@@ -0,0 +1,32 @@
+.{rect_line} := @use("../draw.hb");
+.{clear, create_buffer, present, Point, FB_HEIGHT, FB_WIDTH} := @use("../lib.hb")
+
+/* expected result:
+   the white outline of a square bounces around the screen */
+
+example := fn(): void {
+	// creates a back buffer, which we write to, to avoid screen flickering
+	buffer := create_buffer()
+	vel := Point.{x: 1, y: 1}
+	pos := Point.{x: 100, y: 100}
+	loop {
+		// draw the square at our current position
+		rect_line(buffer, pos, .(100, 100), .(255, 255, 255, 255), 3)
+		/* push the back buffer to the front buffer
+		   this displays our image to the screen */
+		present(buffer)
+		// erase our old image
+		clear(buffer, .(0, 0, 0, 0))
+
+		// bounce the square if it touches the screen edges
+		if pos.x == 0 | pos.x == FB_WIDTH - 100 {
+			vel.x = 0 - vel.x
+		}
+		if pos.y == 0 | pos.y == FB_HEIGHT - 100 {
+			vel.y = 0 - vel.y
+		}
+
+		pos += vel
+	}
+	return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/examples/strobe.hb b/sysdata/programs/fb_driver/src/examples/strobe.hb
new file mode 100644
index 0000000..e46653c
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/examples/strobe.hb
@@ -0,0 +1,20 @@
+.{clear, create_buffer, present} := @use("../lib.hb")
+
+/* expected result: (EPILEPSY WARNING)
+   the screen rapidly flashes red then black */
+
+example := fn(): void {
+	// creates a back buffer, which we write to, to avoid screen flickering
+	buffer := create_buffer()
+	loop {
+		// screen go red
+		clear(buffer, .(0, 0, 255, 0))
+		// show the red
+		present(buffer)
+		// screen go black
+		clear(buffer, .(0, 255, 255, 0))
+		// show the black
+		present(buffer)
+	}
+	return
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/lib.hb b/sysdata/programs/fb_driver/src/lib.hb
new file mode 100644
index 0000000..ddfc3e4
--- /dev/null
+++ b/sysdata/programs/fb_driver/src/lib.hb
@@ -0,0 +1,100 @@
+.{memory, log, math} := @use("../../../libraries/stn/src/lib.hb");
+.{ColorBGRA, blend} := @use("rel:color.hb")
+
+FB_WIDTH := 1024
+FB_HEIGHT := 768
+FB_PIXELS := FB_WIDTH * FB_HEIGHT
+FB_BYTES := FB_PIXELS << 2
+// actual enforced max copy size is (1 << 16) - 1, but this was faster
+MAX_COPY_SIZE := 6144
+// see stn.math.min, cant use here due to compiler bug (reg id leaked)
+COPY_PIXELS := MAX_COPY_SIZE + (FB_BYTES - MAX_COPY_SIZE & FB_BYTES - MAX_COPY_SIZE >> 31) >> 2
+PARTITIONS := FB_PIXELS / COPY_PIXELS
+TOTAL_PAGES := 1 + FB_BYTES >> 12
+
+Buffer := struct {write: ^ColorBGRA, copy: ^[ColorBGRA; COPY_PIXELS]}
+Point := struct {x: int, y: int}
+Transform := struct {width: int, height: int}
+Rect := struct {p1: Point, p2: Point}
+
+front_buffer_ptr := @as(^ColorBGRA, @bitcast(18446603339442421760))
+front_buffer_copy := @as(^[ColorBGRA; COPY_PIXELS], @bitcast(front_buffer_ptr))
+
+get_front_buffer := fn(): Buffer {
+	// trying to return front_buffer_ptr or front_buffer_copy causes reg id leak
+	return Buffer.{write: @as(^ColorBGRA, @bitcast(18446603339442421760)), copy: @as(^[ColorBGRA; COPY_PIXELS], @bitcast(18446603339442421760))}
+}
+/* this is separate to create_raw_buffer because returning a Buffer from 
+   create_raw_buffer causes reg id leak */
+create_buffer := fn(): Buffer {
+	ptr := create_raw_buffer()
+	ptr_copy := @as(^[ColorBGRA; COPY_PIXELS], @bitcast(ptr))
+	// same here, bitcasting inside the struct literal causes reg id leak
+	buffer := Buffer.{write: ptr, copy: ptr_copy}
+	return buffer
+}
+create_raw_buffer := fn(): ^ColorBGRA {
+	// helps to trace allocation bugs
+	log.info("Creating buffer. This will allocate.\0")
+	if TOTAL_PAGES <= 255 {
+		return @bitcast(memory.request_page(TOTAL_PAGES))
+	}
+	ptr := memory.request_page(255)
+	remaining := TOTAL_PAGES - 255
+	loop if remaining <= 0 break else {
+		if remaining < 255 {
+			memory.request_page(remaining)
+		} else {
+			memory.request_page(255)
+		}
+		remaining -= 255
+	}
+	return @bitcast(ptr)
+}
+// sets the buffer to the color. very fast.
+clear := fn(buffer: Buffer, color: ColorBGRA): void {
+	n := 0
+	// write the first pixel chunk
+	loop if n >= COPY_PIXELS break else {
+		*(buffer.write + n) = color
+		n += 1
+	}
+	n = 1
+	// copy that pixel chunk through the buffer, taking advantage of memory copying
+	loop if n >= PARTITIONS break else {
+		*(buffer.copy + n) = *buffer.copy
+		n += 1
+	}
+	return
+}
+// only required to be called when using a back buffer. if using single-buffered rendering, do not call this.
+present := fn(buffer: Buffer): void {
+	offset := 0
+	// copy chunks of the read buffer to the front buffer
+	loop if offset >= PARTITIONS break else {
+		*(front_buffer_copy + offset) = *(buffer.copy + offset)
+		offset += 1
+	}
+	return
+}
+// composites the contents of buffer1 into buffer2, accounting for alpha transparency
+// i dont know if it works. i have not tested it. it probably doesnt work
+composite := fn(buffer1: Buffer, buffer2: Buffer): void {
+	n := 0
+	loop if n == FB_PIXELS break else {
+		bg := *(buffer2.write + n);
+		*(buffer2.write + n) = blend(*(buffer1.write + n), bg)
+		n += 1
+	}
+	return
+}
+// really need to be able to inline this please - aurlex
+screenidx := fn(pos: Point): int {
+	return pos.x + FB_WIDTH * pos.y
+}
+point2rect := fn(pos: Point, tr: Transform): Rect {
+	return .(pos, .(pos.x + tr.x, pos.y + tr.y))
+}
+rect2point := fn(rect: Rect): struct {point: Point, transform: Transform} {
+	return .(.(0, 0), .(0, 0))
+}
\ No newline at end of file
diff --git a/sysdata/programs/fb_driver/src/main.hb b/sysdata/programs/fb_driver/src/main.hb
index a6483dc..0068d1f 100644
--- a/sysdata/programs/fb_driver/src/main.hb
+++ b/sysdata/programs/fb_driver/src/main.hb
@@ -1,15 +1,7 @@
-frame_buffer := @as(^u8, @bitcast(18446603339442421760))
+// change "lines.hb" to another example to see it onscreen
+example := @use("examples/lines.hb").example
 
 main := fn(): int {
-	color := 17
-	loop {
-		len := 786432 * 4 + 1
-		loop if len == 0 break else {
-			fb := frame_buffer + len;
-			*fb = color
-			len -= 1
-			color += len
-		}
-	}
+	example()
 	return 0
 }
\ No newline at end of file