castle-cli-script
v0.7.0
Published
Build Castle games from a single Lua file
Readme
castle-cli-script
Build Castle games from a single Lua file.
Install
npm install -g castle-cli-scriptRequires Node 18+.
Quick Start
Create a new project
castle-script init my-game
cd my-gameThis creates:
my-game/
├── main.lua — your game script
├── castle-script.json — project config
├── CLAUDE.md — workflow guide for Claude Code
├── API.md — full API reference for Claude Code
└── test.mjs — visual test scriptStart the web player
castle-script serve main.lua --openEdit main.lua and the browser hot-reloads on every save.
Writing scripts
Your Lua file has three lifecycle callbacks:
function onCreate()
-- runs once at scene start
end
function onUpdate(dt)
-- runs every frame; dt = delta time in seconds
end
function onDraw()
-- runs every frame for drawing
-- castle.draw.* only works here
endCoordinate system
The canvas is 5:7 (450×630 px). In onDraw():
(-5, -7) ──────────────── (5, -7) ← top
│ │
│ (0, 0) │ ← center
│ │
(-5, 7) ──────────────── (5, 7) ← bottomDrawing
function onDraw()
-- shapes
castle.draw.setColor(1, 0.4, 0.1)
castle.draw.circle("fill", 0, 0, 0.2)
castle.draw.rectangle("fill", -0.3, -0.3, 0.6, 0.6)
castle.draw.line(-0.5, 0, 0.5, 0)
-- text
castle.draw.setColor(1, 1, 1)
castle.draw.text("Hello!", 0, 0, 12, "center", "middle")
-- transforms
castle.draw.push()
castle.draw.translate(0.2, 0.1)
castle.draw.rotate(math.pi / 4)
castle.draw.rectangle("fill", -0.05, -0.05, 0.1, 0.1)
castle.draw.pop()
endSee API.md in your project for the full API reference.
Commands
Local development
castle-script init [name] Create a new project (default: castle-game)
castle-script serve [file] Start the web player (default: main.lua)
-p, --port <n> port to listen on (default: auto from 5000)
--open open browser automaticallyMobile preview
When you are logged in, serve streams your game live to the Castle app. Run castle-script login once, then castle-script serve — the terminal will show a mobile preview link.
While the CLI Preview screen is open on your device, you can run these commands from a separate terminal:
castle-script screenshot <outputPath> Save a screenshot of the running game locally
castle-script restart Restart the game in the CLI Preview screenFrom your Lua script, you can also capture screenshots at specific moments using castle.screenshot(filename). The file is saved relative to your project directory by the running serve process. This only works from the top-level script (not actor behaviors) and only in the CLI Preview screen — it has no effect in the web player or the published game.
castle.co.start(function()
castle.co.wait(3)
castle.screenshot("state-after-3s.png")
end)Castle account
castle-script login Log in to Castle (opens browser)
castle-script logout Log out
castle-script whoami Show current userSync with Castle
castle-script clone <deckIdOrUrl> [outputDir] Copy a Castle deck locally
castle-script pull [file] Overwrite local files from Castle
castle-script push [file] Publish local files to CastleThese commands require login.
AI images
castle-script imagine <prompt> [file] Generate an image into images/
--name <stem> output filename (default: image)
--service replicate|openai AI backend (default: replicate)
--draft faster/cheaper model
--style fantasy|pixel|watercolor|noir|anime
--set-key <apiKey> save API key for selected serviceImages are auto hot-reloaded by serve. API keys are read from REPLICATE_API_TOKEN / OPENAI_API_KEY environment variables, or saved via --set-key.
With Claude Code
CLAUDE.md, API.md, and test.mjs are auto-generated in your project. CLAUDE.md gives Claude Code workflow context; API.md is the full draw API reference; test.mjs is a Playwright visual test script it can run to verify output. Open the project folder in Claude Code and ask it to build your game — it can read and edit main.lua directly.
