diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..af78532
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,40 @@
+# Build Workflow
+name: build
+
+# Run on Push
+on: [push]
+
+
+jobs:
+ build:
+ # Run this on a default linux machine
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@master
+
+ - uses: mymindstorm/setup-emsdk@v11
+
+ - name: Checkout ocen repo
+ uses: actions/checkout@v3
+ with:
+ repository: ocen-lang/ocen
+ path: ocen
+
+ - name: Build ocen
+ run: |
+ cd ocen
+ ./meta/bootstrap.sh
+ echo "OCEN_ROOT=${{ github.workspace }}/ocen" >> $GITHUB_ENV
+ echo "${{ github.workspace }}/ocen/bootstrap" >> $GITHUB_PATH
+
+ - name: Build Wasm
+ run: |
+ cd ${{ github.workspace }}
+ ./meta/build_wasm.sh
+ ./meta/multi_build_wasm.sh
+
+ - name: Deploy 🚀
+ uses: JamesIves/github-pages-deploy-action@4.1.0
+ with:
+ branch: gh-pages # The branch the action should deploy to.
+ folder: build
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..543141f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.dSYM
+*out
+*.c
+build
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4248dc8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,49 @@
+# Ocen WASM Template
+
+This is a template using the `std::og` library in [ocen](https://github.com/ocen-lang/ocen)
+to draw some graphics to the screen. `std::og` is a set of wrappers around `SDL` to make it
+a friendlier API for fast-protoyping (loosely inspired by `p5.js` / `raylib`).
+
+This repository demonstrates how to compile such an application to WebAssembly using `emscripten`,
+and has a sample github workflow to automatically build and deploy the application to github pages.
+
+## Customization
+
+- The `assets` folder is automatically bundled into the generated `wasm` (can be changed in `build_wasm.sh`).
+ Any files you want to be available to the application should be placed in this folder.
+
+- `assets/index.html` is the default HTML template for the application. It only works with the default emscriptem
+ build, and assumes the files generated are `index.js` and `index.wasm`.
+
+- `assets/multi-canvas.html` is a demonstration of how to load in different compiled WASM modules into the same
+ page. This requires building the WASM modules with different names (`-s MODULARIZE=1 -s EXPORT_NAME="FOO"` flags).
+ This is demonstrated in `./meta/multi_build_wasm.sh`.
+
+## Building
+
+### Native SDL build
+
+Need to have `SDL2` installed on your system, and should be able to compile C code with `-lSDL2 -lz`
+
+```shell
+$ ocen main.oc -o main
+$ ./main
+```
+
+### Emscripten build, Local toolchain
+
+Need to have `emscripten` installed locally, and activated so that `emcc` is in your path.
+
+```shell
+$ ./meta/build_wasm.sh
+$ python3 -m http.server build/
+```
+
+### Emscripten build, Docker
+
+Must have docker installed on your system, and running.
+
+```shell
+$ ./meta/build_wasm_docker.sh
+$ python3 -m http.server build/
+```
\ No newline at end of file
diff --git a/assets/index.html b/assets/index.html
new file mode 100644
index 0000000..febbdbd
--- /dev/null
+++ b/assets/index.html
@@ -0,0 +1,69 @@
+
+
+
This demo was written in the Ocen, and compiled to the web using Emscripten.
+
Use Up and Down keys to zoom in/out
+
+
+
+
+
+ Check out the single-canvas template
+
+
+
+
+
+
+
+
+
diff --git a/main.oc b/main.oc
new file mode 100644
index 0000000..b665cc4
--- /dev/null
+++ b/main.oc
@@ -0,0 +1,47 @@
+import std::og
+
+def main() {
+ let rows = 20i32
+ let cols = 20i32
+ let cell_size = 20i32
+
+ og::init((cols * cell_size) as u32, (rows * cell_size) as u32, "Demo")
+
+ let off = 0i32
+ let frames = 0
+ while og::is_running() {
+ if og::is_key_pressed(Escape) {
+ break
+ }
+
+ if og::is_key_pressed(Up) {
+ cell_size += 1
+ }
+ if og::is_key_pressed(Down) {
+ cell_size -= 1
+ }
+
+ for let i = -1; i < rows + 1; i++ {
+ for let j = -1; j < cols + 1; j++ {
+ og::draw_rect(
+ (j * cell_size + off) as i32,
+ (i * cell_size + off) as i32,
+ (cell_size) as i32,
+ (cell_size) as i32,
+ if (i + j) % 2 == 0 then og::colors::BLACK else og::colors::WHITE
+ )
+ }
+ }
+
+ frames++
+ if frames % 20 == 0 {
+ if (off == cell_size) {
+ off = 0
+ }
+ off++
+ }
+ }
+ og::quit()
+}
+
+
diff --git a/meta/build_wasm.sh b/meta/build_wasm.sh
new file mode 100755
index 0000000..b6e7081
--- /dev/null
+++ b/meta/build_wasm.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -xe
+
+mkdir -p build
+
+if [[ -z "$1" ]]; then
+ ocen main.oc -n -c build/main.c
+ FILE=build/main.c
+else
+ FILE=$1
+fi
+
+
+cp assets/index.html build/
+
+# GUIDE for flags:
+#------------------
+# -O3: Optimize the code.
+# -DOC_NO_BACKTRACE: Disable backtrace: Ocen specific, required, since WASM doesn't have execinfo.h
+# -s USE_SDL=2: Use SDL2 for graphics. (`std::og` is based on SDL2)
+# -s USE_ZLIB=1: Use zlib for compression. (`std::image::png` uses zlib)
+# -s ALLOW_MEMORY_GROWTH=1: Allow memory to grow dynamically.
+# --preload-file assets: Bundle the `assets` directory into generated WASM data
+# --use-preload-plugins: Use the plugins in the preload file.
+# -o build/index.js: Output file name (JS + corresponding WASM file)
+# -s ASYNCIFY=1: Enable asyncify (allows `while` loops in the code for main event loop)
+#
+# Optional flags (not used here, but needed for multi-wasm pages)
+# ----------------------------------------------------------------
+# -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0: Without this, SDL always assumes single canvas with ID `#canvas`.
+# -s MODULARIZE=1: Generate a module that can be loaded into the same HTML page.
+# -s EXPORT_NAME="'Module1'": Name of the module. This is used in the HTML file to load the module.
+# -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ENV"]': Export the ENV object to the module. This is needed so we can configure
+# the module to not capture keyboard events outside the canvas. Look at
+# `assets/multi-canvas.html` or `assets/index.html` for more details.
+
+
+emcc $FILE \
+ -O3 \
+ -DOC_NO_BACKTRACE \
+ -s USE_SDL=2 \
+ -s USE_ZLIB=1 \
+ -s ALLOW_MEMORY_GROWTH=1 \
+ --preload-file assets \
+ --use-preload-plugins \
+ -o build/index.js \
+ -s ASYNCIFY=1
\ No newline at end of file
diff --git a/meta/build_wasm_docker.sh b/meta/build_wasm_docker.sh
new file mode 100755
index 0000000..236563f
--- /dev/null
+++ b/meta/build_wasm_docker.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -xe
+
+ocen main.oc -n -c build/main.c
+docker run --rm -v $(PWD):/mnt/ -w /mnt/ emscripten/emsdk ./meta/build_wasm.sh build/main.c
diff --git a/meta/multi_build_wasm.sh b/meta/multi_build_wasm.sh
new file mode 100755
index 0000000..16834ea
--- /dev/null
+++ b/meta/multi_build_wasm.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+# NOTE: This is a demo on how to build separate files into modules which can be loaded
+# into the **same** HTML page. Note the usage of `-s MODULARIZE` and `-s EXPORT_NAME`
+# flags.
+# Look at `assets/multi-canvas.html` for how to load multiple modules into the same
+# HTML page.
+
+set -xe
+
+mkdir -p build
+
+cp assets/multi-canvas.html build/
+
+
+ocen main.oc -n -c build/main.c
+
+# NOTE: This is just to make the second file different from the first one.
+cat main.oc | sed 's/BLACK/RED/g' > build/main2.oc
+ocen build/main2.oc -n -c build/main2.c
+rm build/main2.oc
+
+# Optional flags (needed for multi-wasm pages)
+# ----------------------------------------------------------------
+# -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0: Without this, SDL always assumes single canvas with ID `#canvas`.
+# -s MODULARIZE=1: Generate a module that can be loaded into the same HTML page.
+# -s EXPORT_NAME="'Module1'": Name of the module. This is used in the HTML file to load the module.
+# -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ENV"]': Export the ENV object to the module. This is needed so we can configure
+# the module to not capture keyboard events outside the canvas. Look at
+# `assets/multi-canvas.html` or `assets/index.html` for more details.
+# NOTE: ENV is exported by default when NOT using MODULARIZE.
+
+emcc build/main.c \
+ -DOC_NO_BACKTRACE \
+ -s USE_SDL=2 \
+ -s USE_ZLIB=1 \
+ -s ALLOW_MEMORY_GROWTH=1 \
+ --preload-file assets \
+ --use-preload-plugins \
+ -s ASYNCIFY=1 \
+ -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \
+ -s MODULARIZE=1 \
+ -s EXPORT_NAME=Module1 \
+ -o build/mod1.js \
+ -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ENV"]'
+
+emcc build/main2.c \
+ -DOC_NO_BACKTRACE \
+ -s USE_SDL=2 \
+ -s USE_ZLIB=1 \
+ -s ALLOW_MEMORY_GROWTH=1 \
+ --preload-file assets \
+ --use-preload-plugins \
+ -s ASYNCIFY=1 \
+ -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \
+ -s MODULARIZE=1 \
+ -s EXPORT_NAME=Module2 \
+ -o build/mod2.js \
+ -s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ENV"]'
\ No newline at end of file