diff --git a/preload/apps/joust/__init__.py b/preload/apps/joust/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..dbda3be8e5d7a9485999d502b431f5cfecde5a4c
--- /dev/null
+++ b/preload/apps/joust/__init__.py
@@ -0,0 +1,116 @@
+# card10 Joust
+# based on https://github.com/adangert/JoustMania
+
+import display
+import os
+import utime
+import buttons
+from color import Color
+import leds
+import vibra
+import bhi160
+
+COLOR_GREEN=(0,255,0)
+COLOR_RED=(255,0,0)
+COLOR_ORANGE=(255,125,0)
+COLOR_WHITE=(255,255,255)
+
+ACCELEROMETER = bhi160.BHI160Accelerometer()
+class JoustSensor:
+    NUM_READINGS = 1
+    def __init__(self):
+        self.sensor = ACCELEROMETER
+        self.last_accels = []
+        self.jerk = 0.0
+        self.threshold = 1.8
+    def get_jerk(self):
+        readings = list()
+        while not readings:
+            readings = self.sensor.read()
+            if len(readings) > 0:
+                self.last_accels = self.last_accels + readings
+                self.last_accels = self.last_accels[-JoustSensor.NUM_READINGS:]
+                jerk_x = sum([a.x for a in self.last_accels]) / JoustSensor.NUM_READINGS
+                jerk_y = sum([a.y for a in self.last_accels]) / JoustSensor.NUM_READINGS
+                jerk_z = sum([a.z for a in self.last_accels]) / JoustSensor.NUM_READINGS
+                self.jerk = (jerk_x**2 + jerk_y**2 + jerk_z**2)**0.5
+        return self.jerk
+    def too_fast(self):
+        return self.get_jerk() > self.threshold
+
+def wait_button():
+    utime.sleep_ms(1000)
+    while True:
+        pressed = buttons.read(
+            buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT
+        )
+        if pressed != 0:
+            break
+    if pressed & buttons.BOTTOM_LEFT != 0:
+        return "BL"
+    if pressed & buttons.BOTTOM_RIGHT != 0:
+        return "BR"
+    if pressed & buttons.UPPER_RIGHT != 0:
+        return "BR"
+    if pressed & buttons.UPPER_LEFT != 0:
+        return "UL"
+    return "??"
+
+def joining_game():
+    set_display("JOIN ?", COLOR_WHITE)
+    set_color(COLOR_WHITE)
+
+def status_in_game():
+    set_display("IN GAME", COLOR_GREEN)
+    set_color(COLOR_GREEN)
+
+def status_out_game():
+    set_display("DROPPED", COLOR_RED)
+    set_color(COLOR_RED)
+
+def set_display(text, colr):
+    with display.open() as disp:
+        disp.clear()
+        disp.print(text, fg=colr, bg=(0,0,0), posx=30, posy=30)
+        disp.update()
+
+def set_color(colr):
+    for i in range(15):
+        leds.prep(i, colr)
+    leds.update()
+
+def countdown(n):
+    colr = COLOR_WHITE
+    for i in range(n,0,-1):
+        if i == 3: colr = COLOR_RED
+        elif i == 2: colr = COLOR_ORANGE
+        elif i == 1: colr = COLOR_GREEN
+        set_display("START: %d" % i, colr)
+        leds.clear()
+        vibra.vibrate(300)
+        utime.sleep_ms(1000)
+    vibra.vibrate(1000)
+
+def change_status(status):
+    status()
+    vibra.vibrate(1000)
+
+def run():
+    print("Starting ...")
+    acc = JoustSensor()
+    i=0
+    states = [joining_game, status_in_game, status_out_game]
+    while True:
+        current_status = states[i%len(states)]
+        change_status(current_status)
+        i+=1
+        if current_status == joining_game:
+            wait_button()
+            countdown(5)
+        elif current_status == status_in_game:
+            while not acc.too_fast():
+                pass
+        elif current_status == status_out_game:
+            wait_button()
+
+run()
\ No newline at end of file
diff --git a/preload/apps/joust/metadata.json b/preload/apps/joust/metadata.json
new file mode 100644
index 0000000000000000000000000000000000000000..cfd7dc972ad524cafdf5f336d9c970f0b3a59419
--- /dev/null
+++ b/preload/apps/joust/metadata.json
@@ -0,0 +1 @@
+{"name":"Joust","description":"A very simple port of JSJoust to the Card10\r\n\r\nJoust is a multiplayer physical game. The core of the game is to be the last man standing you're knocked out when your controller (Card10 badge) moves too quickly. The aim is to attack your players by nudging their controllers, whilst defending yours.\r\n\r\nInstructions:\r\n- All players must have the app installed on their Card10 and wear it on their wrist.\r\n- Players must start with the 'JOIN' menu visible.\r\n- Simultaneously click a button to start the countdown.\r\n- Once the light goes green, the game is in play.\r\n- Defend your controller from pushing by other players, whilst trying to do the same to them.\r\n- If the light goes red, you're knocked out and should wait for the next round.\r\n- Keep playing until only 1 player has a green light, then claim victory (this doesn't happen automatically)\r\n- After the game, press any bottom button to get back to the 'JOIN' menu","category":"games","author":"Andy B-S","revision":1}
\ No newline at end of file