.agents/skills/developing-with-crisp-game-lib/SKILL.md
Creates browser-based mini-games using crisp-game-lib. Use when asked to make a game, create a mini-game, or build an arcade game with crisp-game-lib.
npx skillsauth add abagames/claude-one-button-game-creation developing-with-crisp-game-libInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Creates browser-based mini-games using crisp-game-lib, a JavaScript library for rapid arcade game development.
Use this skill when asked to create a mini-game with crisp-game-lib.
This guide separates:
Choose the appropriate setup based on the project context.
Create a project directory with index.html and main.js:
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>My Game</title>
<meta
name="viewport"
content="width=device-width, height=device-height, user-scalable=no, initial-scale=1, maximum-scale=1"
/>
<script src="https://unpkg.com/[email protected]/packages/core/dist/algo-chip.umd.js"></script>
<script src="https://unpkg.com/[email protected]/packages/util/dist/algo-chip-util.umd.js"></script>
<script src="https://unpkg.com/crisp-game-lib@latest/docs/bundle.js"></script>
<script src="./main.js"></script>
<script>
window.addEventListener("load", onLoad);
</script>
</head>
<body style="background: #ddd"></body>
</html>
Optional script tags (add before bundle.js if needed):
<!-- GIF capture: add if options.isCapturing is true -->
<script src="https://unpkg.com/[email protected]/build/index.js"></script>
<!-- WebGL themes (pixel, shape, shapeDark, crt): add if using these themes -->
<script src="https://unpkg.com/[email protected]/dist/pixi.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/pixi-filters.js"></script>
npm install crisp-game-lib
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>My Game</title>
<meta
name="viewport"
content="width=device-width, height=device-height, user-scalable=no, initial-scale=1, maximum-scale=1"
/>
<script src="https://unpkg.com/[email protected]/packages/core/dist/algo-chip.umd.js"></script>
<script src="https://unpkg.com/[email protected]/packages/util/dist/algo-chip-util.umd.js"></script>
<script type="module" src="./main.js"></script>
</head>
<body style="background: #ddd"></body>
</html>
main.js (bundler version uses const, import, and init()):
import "crisp-game-lib";
const title = "MY GAME";
const description = `[Control instructions]`;
const characters = [];
const options = {};
function update() {
if (!ticks) {
/* init */
}
}
init({ update, title, description, characters, options });
main.jsWrite main.js following the structure below.
Before and during implementation:
reference/api.md to confirm exact function behavior, arguments, and constraints.reference/examples.md to copy proven patterns and unblock design decisions quickly.title = "GAME NAME";
description = `
[Control instructions]
`;
characters = []; // Optional pixel art (6x6 grid, use letters a-z)
options = {
viewSize: { x: 100, y: 100 }, // Default screen size
theme: "simple", // simple | dark | shape | shapeDark | pixel | crt
};
// Game state variables
let player, enemies;
function update() {
if (!ticks) {
// Initialize on first frame
player = { pos: vec(50, 50) };
enemies = [];
}
// Input → Physics → Spawn → Draw (with collision) → Score → Game Over
}
Fill update() with a clear per-frame order:
Use if (!ticks) { ... } for one-time initialization.
Before finalizing logic, check all rules in section 4:
particle() argumentsTreat section 4 as required validation criteria, not optional advice.
Run the checklist in section 6 and confirm the game behaves correctly on the target input mode (desktop and/or mobile).
Follow these rules strictly. Violations cause silent bugs.
Drawing order determines collision detection. Objects can ONLY detect collision with shapes drawn BEFORE them in the same frame:
// ✅ CORRECT: Draw targets first, then detectors
color("red");
enemies.forEach((e) => box(e.pos, 10)); // Draw enemies FIRST
color("blue");
if (box(player.pos, 8).isColliding.rect.red) {
end();
} // Player detects enemies
// ❌ WRONG: Checking collision with something not yet drawn
color("blue");
if (box(player.pos, 8).isColliding.rect.red) {
end();
} // red not drawn yet!
color("red");
enemies.forEach((e) => box(e.pos, 10));
Do NOT manually draw the score. The library automatically displays it. Never call text() for score display.
White color is invisible on all themes (matches background). Use light_ variants or other colors instead.
Use particle() with object format:
particle(pos, { count: 5, speed: 2, angle: PI }); // ✅ Preferred
particle(pos, 5, 2, PI, PI); // ❌ Legacy format
if (input.isJustPressed) {
/* jump, shoot, or change direction */
}
player.pos.x = input.pos.x;
player.pos.clamp(5, 95, 5, 95);
// Declare at game state level
let nextEnemyTicks;
// In update(), initialize on first frame
if (!ticks) {
nextEnemyTicks = 0;
}
// Countdown and spawn
nextEnemyTicks--;
if (nextEnemyTicks < 0) {
enemies.push({ pos: vec(110, rnd(90) + 5) });
nextEnemyTicks = rnd(60, 120) / difficulty;
}
remove(enemies, (e) => {
e.pos.x -= difficulty * 0.5;
color("red");
box(e.pos, 8);
return e.pos.x < -10; // Remove when off-screen
});
player.vy += 0.15; // Gravity
player.pos.y += player.vy;
if (player.pos.y >= ground) {
// Ground collision
player.pos.y = ground;
player.vy = 0;
player.onGround = true;
}
if (input.isJustPressed && player.onGround) {
player.vy = -4;
play("jump");
}
Open the game in a browser and check:
end() triggers game over correctly| Category | Functions |
| -------- | ----------------------------------------------------------------------------------------------- |
| Drawing | rect(x,y,w,h) box(pos,w,h) line(p1,p2,t) bar(pos,len,t,angle) arc(pos,r,t,start,end) |
| Text | text(str,x,y) char(ch,x,y) addWithCharCode(ch,offset) |
| Color | color("red") — red, green, blue, yellow, purple, cyan, black, light_* variants, transparent |
| Input | input.pos input.isPressed input.isJustPressed keyboard.code["Space"].isJustPressed |
| Audio | play("coin") — coin, powerUp, hit, jump, select, lucky |
| Vector | vec(x,y) .add() .sub() .mul() .clamp() .wrap() .addWithAngle() .distanceTo() |
| Utility | times(n,fn) range(n) remove(arr,fn) rnd(max) rndi(max) clamp() wrap() |
| State | ticks score difficulty addScore(pts,pos) end() |
| Effects | particle(pos, {count, speed, angle, angleWidth}) |
Keep these open while implementing:
reference/api.md (spec-level API behavior)reference/examples.md (complete working examples and patterns)development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.