diff --git a/LICENSE b/LICENSE
index cd16d8e0ea72624118ad314b6e13fa054a87d1dc..d356020d6ac24b6018c1b54088a3299201d22210 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2013 M. Elizabeth Scott
+Copyright (c) 2013 Micah Elizabeth Scott
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index 97c2456a28dbe38e983ba9753f3a6ca9fa8f5f06..53b1237f630f208fe70c9622070445c645cae2dc 100644
--- a/README.md
+++ b/README.md
@@ -23,3 +23,9 @@ This is a work in progress! Things I don't know yet:
 * How many LEDs will be supported per Teensy board
 * Maximum frame rates
 * Specific documentation for the USB protocol
+
+Prerequisites
+-------------
+
+* The recommended ARM toolchain, from <https://code.launchpad.net/gcc-arm-embedded>
+* The Teensy Loader: <http://www.pjrc.com/teensy/loader.html>
diff --git a/fc_firmware/fc_firmware.ino b/fc_firmware/fc_firmware.ino
new file mode 100644
index 0000000000000000000000000000000000000000..f52b033628f761cebba962b822f84a228621e1c4
--- /dev/null
+++ b/fc_firmware/fc_firmware.ino
@@ -0,0 +1,33 @@
+/*
+ * Fadecandy Firmware
+ * For Arduino with Teensyduino and OctoWS2811.
+ *
+ * Copyright <c> 2013 Micah Elizabeth Scott. <micah@scanlime.org>
+ */
+
+#include <OctoWS2811.h>
+#include "hcolor.h"
+
+static const int ledsPerStrip = 64;
+static const int ledsTotal = ledsPerStrip * 8;
+
+DMAMEM int displayMemory[ledsPerStrip * 6];
+int drawingMemory[ledsPerStrip * 6];
+OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, WS2811_GRB | WS2811_800kHz);
+HPixelBuffer<ledsTotal> pixbuf;
+
+void setup()
+{
+    leds.begin();
+
+    for (unsigned i = 0; i < ledsTotal; ++i) {
+        pixbuf.pixels[i].color = HColor16(0x1080, 0x0080, 0x0080);
+    }
+}
+
+void loop()
+{
+    pixbuf.pixels[0].color.r = millis() & 0xffff;
+
+    pixbuf.show(leds);
+}
diff --git a/fc_firmware/hcolor.h b/fc_firmware/hcolor.h
new file mode 100644
index 0000000000000000000000000000000000000000..3534da4511d0139226dd267272890d5e9f56fef5
--- /dev/null
+++ b/fc_firmware/hcolor.h
@@ -0,0 +1,120 @@
+/*
+ * High dynamic range color library.
+ *
+ * Copyright <c> 2013 Micah Elizabeth Scott. <micah@scanlime.org>
+ *
+ * This is a high dynamic range (48-bit) color data type,
+ * and a temporal dithering implementation that's compatible
+ * with the OctoWS2811 LED driver.
+ */
+
+#pragma once
+#include <stdint.h>
+#include <algorithm>
+
+class OctoWS2811;
+
+/// Basic data type for a high-dynamic-range color.
+struct HColor {
+    uint16_t r, g, b;
+};
+
+/// Constructor for 16-bit colors
+static inline HColor HColor16(uint16_t r, uint16_t g, uint16_t b) {
+    HColor c = { r, g, b };
+    return c;
+}
+
+/// Constructor for 8-bit colors
+static inline HColor HColor8(uint8_t r, uint8_t g, uint8_t b) {
+    HColor c = {
+        r | (unsigned(r) << 8),
+        g | (unsigned(g) << 8),
+        b | (unsigned(b) << 8),
+    };
+    return c;
+}
+
+/// Constructor for 8-bit colors packed into a 24-bit word
+static inline HColor HColor8(uint32_t rgb) {
+    return HColor8( (rgb & 0xFF0000) >> 16, (rgb & 0x00FF00) >> 8, rgb & 0x0000FF );
+}
+
+/// Constructor for float colors, with clamping.
+static inline HColor HColorF(float r, float g, float b) {
+    HColor c = {
+        std::min<int>(0xffff, std::max<int>(0, r * 65535.0f + 0.5f)),
+        std::min<int>(0xffff, std::max<int>(0, g * 65535.0f + 0.5f)),
+        std::min<int>(0xffff, std::max<int>(0, b * 65535.0f + 0.5f)),
+    };
+    return c;
+}
+
+/// Add two colors, with saturation
+static inline HColor operator + (HColor a, HColor b) {
+    HColor c = {
+        std::min<int>(0xffff, unsigned(a.r) + unsigned(b.r)),
+        std::min<int>(0xffff, unsigned(a.g) + unsigned(b.g)),
+        std::min<int>(0xffff, unsigned(a.b) + unsigned(b.b)),
+    };
+    return c;
+}
+
+/**
+ * Linear interpolation between two colors. "Alpha" is in 8-bit fixed point.
+ * Returns c1 if alpha==0, or c2 if alpha==0x100. Values outside this range will extrapolate.
+ */
+static inline HColor lerp8(HColor c1, HColor c2, int alpha) {
+  int invA = 0x100 - alpha;
+  HColor c = {
+    (c1.r * invA + c2.r * alpha) >> 8,
+    (c1.g * invA + c2.g * alpha) >> 8,
+    (c1.b * invA + c2.b * alpha) >> 8,
+  };
+  return c;
+}
+
+/// Floating point linear interpolation, with clamping.
+static inline HColor lerp(HColor c1, HColor c2, float alpha) {
+  float invA = 1.0f - alpha;
+  HColor c = {
+    std::min<int>(0xffff, std::max<int>(0, c1.r * invA + c2.r * alpha)),
+    std::min<int>(0xffff, std::max<int>(0, c1.g * invA + c2.g * alpha)),
+    std::min<int>(0xffff, std::max<int>(0, c1.b * invA + c2.b * alpha)),
+  };
+  return c;
+}
+
+/// Data type for one display pixel
+struct HPixel {
+    HColor color;
+    int16_t residual[3];
+
+    /// Temporal dithering algorithm. Returns a 24-bit RGB color.
+    uint32_t dither() {
+        int r16 = color.r + residual[0];
+        int g16 = color.g + residual[1];
+        int b16 = color.b + residual[2];
+        int r8 = std::min<int>(0xff, std::max<int>(0, (r16 + 0x80) >> 8));
+        int g8 = std::min<int>(0xff, std::max<int>(0, (g16 + 0x80) >> 8));
+        int b8 = std::min<int>(0xff, std::max<int>(0, (b16 + 0x80) >> 8));
+        residual[0] = r16 - (r8 | (r8 << 8));
+        residual[1] = g16 - (g8 | (g8 << 8));
+        residual[2] = b16 - (b8 | (b8 << 8));
+        return (r8 << 16) | (g8 << 8) | b8;
+    }
+};
+
+/// Data type for a framebuffer of pixels
+template <unsigned tCount>
+struct HPixelBuffer {
+    HPixel pixels[tCount];
+
+    /// Update the entire frame
+    void show(OctoWS2811 &leds) {
+        for (unsigned i = 0; i < tCount; ++i) {
+            leds.setPixel(i, pixels[i].dither());
+        }
+        leds.show();
+    }
+};