HTML5 PORTFOLIO // C Applications

01 / PROJECT IDENTIFICATION

Project: C / SDL3 application compiled to WebAssembly

Project type: Static website (GitHub Pages)

Primary technologies: C, SDL3, SDL_ttf, FreeType, Emscripten

Build system: Makefile + GitHub Actions

Hosting platform: GitHub Pages (gh-pages branch)

Output: HTML, JavaScript, WASM and packaged data

Document type: Technical documentation

02 / PROJECT OVERVIEW

This project compiles a C application that uses SDL3 into WebAssembly with Emscripten, so it can run in a browser. The result is published as a static website on GitHub Pages.

Primary objectives

  • Compile C source code to WebAssembly with emcc.
  • Embed the application in a custom HTML page.
  • Package fonts, images and sounds with the build.
  • Automate the build and deployment with CI/CD.
  • Keep dependencies reproducible through Git submodules.

03 / REPOSITORY STRUCTURE

The repository separates source code, assets, libraries, the web template and generated output.

Recommended layout

my-project/
│
├── .github/
│   └── workflows/
│       └── build.yml          ← automatic CI/CD
│
├── src/                       ← C source code
│   ├── main.c
│   ├── game.c / game.h
│   ├── render.c / render.h
│   └── ...
│
├── assets/                    ← resources
│   ├── fonts/
│   │   └── font.ttf
│   ├── images/
│   └── sounds/
│
├── libs/                      ← libraries (gitignore or submodules)
│   ├── SDL3/
│   ├── SDL_ttf/
│   └── freetype/
│
├── web/                       ← website HTML template
│   ├── index.html             ← main page
│   ├── style.css
│   └── shell.html             ← Emscripten template
│
├── dist/                      ← generated by the build (gitignored)
│   ├── index.html
│   ├── index.js
│   ├── index.wasm
│   └── index.data             ← packaged assets
│
├── Makefile
└── README.md

04 / EMSCRIPTEN SHELL TEMPLATE

The shell.html file wraps the WASM application in a web page. Emscripten replaces the {{{ SCRIPT }}} placeholder with the generated loader script.

web/shell.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>My SDL3 App</title>
  <style>
    body { margin: 0; background: #1a1a2e; display: flex;
           justify-content: center; align-items: center; height: 100vh; }
    canvas { border: 2px solid #444; }
    #loading { color: white; font-family: monospace; }
  </style>
</head>
<body>
  <div id="loading">Loading...</div>
  <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>

  <script>
    var Module = {
      canvas: document.getElementById('canvas'),
      onRuntimeInitialized: function() {
        document.getElementById('loading').style.display = 'none';
      }
    };
  </script>
  {{{ SCRIPT }}}  <!-- Emscripten injects here -->
</body>
</html>

05 / MAKEFILE

The Makefile compiles the sources with emcc, links the WASM builds of the libraries, preloads the assets and outputs everything into dist/. The libs target builds the dependencies with CMake.

Makefile

CC = emcc
SRC = src/main.c src/game.c src/render.c
OUT = dist/index.html

INCLUDES = \
  -I./libs/SDL3/include \
  -I./libs/SDL_ttf \
  -I./libs/freetype/include

LIBS = \
  -L./libs/SDL3/build-wasm \
  -L./libs/SDL_ttf/build-wasm \
  -L./libs/freetype/build-wasm \
  -lSDL3 -lSDL3_ttf -lfreetype

FLAGS = \
  -s USE_WEBGL2=1 \
  -s ASYNCIFY=1 \
  -s ALLOW_MEMORY_GROWTH=1 \
  -O2

all: $(OUT)

$(OUT): $(SRC)
	mkdir -p dist
	$(CC) $(SRC) $(INCLUDES) $(LIBS) $(FLAGS) \
	  --shell-file web/shell.html \
	  --preload-file assets/ \
	  -o $(OUT)

libs:
	cd libs/freetype && mkdir -p build-wasm && cd build-wasm && \
	  emcmake cmake .. -DBUILD_SHARED_LIBS=OFF && emmake make -j4
	cd libs/SDL3 && mkdir -p build-wasm && cd build-wasm && \
	  emcmake cmake .. -DBUILD_SHARED_LIBS=OFF -DSDL_STATIC=ON && emmake make -j4
	cd libs/SDL_ttf && mkdir -p build-wasm && cd build-wasm && \
	  emcmake cmake .. -DBUILD_SHARED_LIBS=OFF && emmake make -j4

clean:
	rm -rf dist/

.PHONY: all libs clean

Makefile recipe lines must be indented with a tab character, not spaces.

06 / GIT IGNORE RULES

Generated output and compiled library builds are excluded from version control.

.gitignore

# Build
dist/
libs/SDL3/build-wasm/
libs/SDL_ttf/build-wasm/
libs/freetype/build-wasm/

# If libs are submodules, otherwise ignore everything
# libs/

*.o
*.a

07 / LIBRARY MANAGEMENT

Git submodules are the recommended way to track SDL3, SDL_ttf and FreeType at a fixed revision.

Adding the submodules

git submodule add https://github.com/libsdl-org/SDL.git libs/SDL3
git submodule add https://github.com/libsdl-org/SDL_ttf.git libs/SDL_ttf
git submodule add https://gitlab.freedesktop.org/freetype/freetype.git libs/freetype

CI configuration

In the workflow, the checkout step must also clone the libraries:

- uses: actions/checkout@v3
  with:
    submodules: recursive   # also clones the libs

Local clone (alternative)

cd C:\Users\killu
mkdir my-project
cd my-project
mkdir libs
cd libs

git clone https://github.com/libsdl-org/SDL.git SDL3
git clone https://github.com/libsdl-org/SDL_ttf.git SDL_ttf
git clone https://gitlab.freedesktop.org/freetype/freetype.git freetype

08 / BUILD AND DEPLOYMENT FLOW

Every push triggers GitHub Actions, which builds the dependencies and the application, then publishes the result.

Pipeline

push code
    ↓
GitHub Actions
    ↓
compile FreeType → SDL3 → SDL3_ttf → app
    ↓
generate dist/ (html + js + wasm + data)
    ↓
deploy to gh-pages
    ↓
https://youruser.github.io/my-project/

09 / WINDOWS SETUP (EMSDK)

On Windows, Emscripten is installed through emsdk. Using cmd.exe or Git Bash is recommended instead of PowerShell for Emscripten tasks.

Activating the SDK

cd C:\Users\killu\emsdk
emsdk activate latest --permanent

Verifying the installation

emcc --version
git --version
cmake --version

Expected output for the first command is an emcc version banner (Emscripten gcc/clang-like replacement + linker).

10 / TROUBLESHOOTING

PowerShell PATH parse error

Running emsdk activate latest in PowerShell can fail with an "unexpected token" error in emsdk_set_env.ps1, caused by malformed quotes in the PATH. Use cmd.exe instead, or run the environment script through it:

cmd /k "C:\Users\killu\emsdk\emsdk_env.bat"

Truncated PATH after --permanent

The permanent activation can overwrite the PATH and drop existing entries. If Git or CMake are no longer found, add the missing entries back in the system environment variables (Path):

C:\Windows\system32
C:\Windows
C:\Program Files\Git\cmd
C:\Program Files\CMake\bin

Best practices

  • Back up the PATH variable before running --permanent.
  • Open a new terminal after changing environment variables.
  • Run all Emscripten commands from the same shell.
  • Check emcc --version before building the libraries.

11 / SOURCE CODE AND RESOURCES

SDL3: github.com/libsdl-org/SDL

SDL_ttf: github.com/libsdl-org/SDL_ttf

FreeType: gitlab.freedesktop.org/freetype/freetype

Source management: Git (submodules)

Hosting model: Static web hosting (GitHub Pages)

Documentation format: HTML

This document describes the project's general architecture and build process. Implementation-specific details should be verified against the actual source code.