npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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-script

Requires Node 18+.

Quick Start

Create a new project

castle-script init my-game
cd my-game

This 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 script

Start the web player

castle-script serve main.lua --open

Edit 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
end

Coordinate system

The canvas is 5:7 (450×630 px). In onDraw():

(-5, -7) ──────────────── (5, -7)   ← top
    │                          │
    │           (0, 0)          │    ← center
    │                          │
(-5,  7) ──────────────── (5,  7)   ← bottom

Drawing

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()
end

See 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 automatically

Mobile 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 screen

From 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 user

Sync 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 Castle

These 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 service

Images 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.