Appearance
Getting started
Run Gap Run, a portrait game where you hold either side of the screen to steer through gaps. It uses the same SDK lifecycle and host messages as a game embedded in a feed.
Prerequisites
- Node.js 20.19 or newer and npm 10.8.2. CI uses Node.js 20.20.2.
- Git and access to the
projportal/fah-sdkrepository. - A browser with WebGL 2 and Web Audio support. Chromium and WebKit are exercised in CI.
Run the example
The following immutable SDK snapshot includes the complete runtime, playable example and documentation toolchain:
sh
git clone https://github.com/projportal/fah-sdk.git
cd fah-sdk
git checkout 449dddaad6fa95e178f81b85187597057c2fdb75
npm ci --ignore-scripts
npm run build
npm run exampleOpen http://127.0.0.1:4173/g/template/?pptest=1. You should see a neon track and a ball. Tap to start, then hold the left or right side to steer. The pptest parameter enables the inspection hook used in Testing; omit it for ordinary play. Stop the server with Ctrl+C.
The build creates dist/example/, including the game, the SDK bundle and Three.js. The game runs without a CDN or backend. npm run example serves the last build; after source edits, rerun npm run build and reload. Open it through HTTP; loading index.html directly from disk will not provide the module and origin behavior the SDK expects.
Make your first change
The source is in examples/template/. Edit main.js, run npm run build again and reload the page. For a visible first change, adjust the COLORS constant; keep game.json.colors in sync.
| File | Purpose |
|---|---|
main.js | Game rules, scene, callbacks and deterministic preview player |
index.html | Canvas page, module entry and relative import map |
game.json | Identity, input hint, scoring, previews and compatibility metadata |
PROVENANCE.md | Sources and attribution for shipped content |
Follow the callbacks in this order: load builds the scene, arm draws the waiting frame, start resets a run, update advances play, render draws it, and dispose releases game-owned references. Game lifecycle explains the order and SDK API describes the callback arguments. Use Input to choose controls and HUD and visual feedback to show progress and impacts. Use Audio to add effects and music that follow the game's lifecycle. Use Graphics to size a Three.js renderer, fit cameras and prepare GPU resources. Adapt the example explains its rules, source structure, build output and inspection tools.
Create your own game
Copy the template into your game's source directory and adapt its rules and assets. Set ID, BUILD and COLORS in main.js, and update the corresponding manifest fields. The manifest id must match the game folder name. Keep the existing author's attribution for retained material; use your own identity and accurate source/license information for new material.
The example build script stages examples/template/ specifically. For a separate project, use the package installation instructions and your own build tool. A static distribution follows this layout:
text
site/
kit/portal-kit.js
lib/three/three.module.min.js
lib/three/three.core.min.js
lib/three-addons/
g/my-game/
index.html
main.js
game.jsonFrom g/my-game/index.html, an import map can resolve the shared files with relative URLs:
html
<script type="importmap">
{
"imports": {
"portal-kit": "../../kit/portal-kit.js",
"three": "../../lib/three/three.module.min.js",
"three/addons/": "../../lib/three-addons/"
}
}
</script>
<script type="module" src="./main.js"></script>Copy the SDK bundle from portal-kit/dist/portal-kit.js. If using Three.js, include its complete required build files and license; it is supplied by the game, not bundled into the SDK. Keep all runtime assets on the same origin and use relative URLs so the game can be mounted at another base path.
Before embedding
Validate game.json, test pause/restart/disposal in a host, and supply real preview media. The example's preview paths are placeholders; the SDK build does not generate captures. The testing guide covers the checks you can run locally and the device checks still needed before shipping.