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

create-excalibur

v2.0.0

Published

ExcaliburJS starter project

Downloads

306

Readme

create-excalibur

Scaffolding for ExcaliburJS projects

With NPM:

npx create-excalibur@latest

example running create excalibur

The ex CLI

Installing the package globally also gives you the ex command:

npm i -g create-excalibur   # installs `ex` (and an `excalibur` alias)
ex            # interactive menu (same as create-excalibur)
ex create     # scaffold a game from a template
ex sample     # scaffold a sample project
ex inspect    # download a showcase game
ex docs       # search the Excalibur docs & API
ex generate   # generate an actor, label, scene, resource, engine settings, material, spritesheet, or animation — or update an actor's options (alias: ex g)
ex doctor     # type-aware diagnostics: actors never added to a scene, unnamed actors
ex upgrade    # migrate your game to a newer Excalibur version, codemod-style (alias: ex up)
ex mcp        # MCP server over stdio (docs + codegen tools for AI agents)

ex docs — search the docs from your terminal

ex docs                         # type-as-you-search prompt
ex docs actor collision         # search, pick a result, read it in the terminal
ex docs Vector.distance -1      # open the top result immediately (no picker)
ex docs actor collision --list  # just print the matches + links (pipe friendly)
ex docs vector --json           # machine-readable results
ex docs --help                  # all options

Search is powered by the excaliburjs.com DocSearch (Algolia) index. Pages are rendered as markdown in the terminal with links back to the online docs; long pages open in $PAGER/less.

Version aware: when run inside a project, ex docs detects the installed excalibur version (from node_modules or package.json) and renders pages from that release's docs (--ref v0.32.0 to override; --ref main for the latest).

Offline:

ex docs offline            # download the docs for your Excalibur version (~1 MB) + plugin READMEs + build a local index
ex docs actor --offline    # search the downloaded docs only
ex docs offline --status   # what's cached and where (~/.excalibur/docs, or $EXCALIBUR_HOME)
ex docs offline --clear    # remove the cache

When the network is unavailable, ex docs falls back to the offline index automatically.

Plugins: ex docs offline also indexes the @excaliburjs/plugin-* READMEs (Tiled, Aseprite, LDtk, perlin, …) from npm, so plugin usage is searchable too — filter with --kind plugin.

ex doctor — check your game for common mistakes

ex doctor           # human-readable report, exits 1 when problems are found
ex doctor --json    # machine-readable findings (CI friendly)

Type-aware diagnostics powered by your project's own TypeScript and excalibur's type declarations (run npm install first). Twelve rules, each grounded in bugs found in shipped games:

  • actor-not-added — an Actor-derived new that never reaches .add/.addChild
  • unnamed-actor — an Actor constructed without a name, harder to spot in debugging tools
  • dont-shadow-excalibur-internals — a field like isActive on an Entity subclass shadows engine state and silently kills the entity (tip: set "noImplicitOverride": true)
  • leaked-subscription.on() to an engine-lifetime emitter with no cleanup; handlers compound across scene restarts
  • dead-collision-hooks — collision handlers while the Engine has physics: false
  • dont-mutate-shared-graphics — writes to cached getAnimation()/getSpriteSheet() results; .clone() first
  • unknown-scene-keygoToScene typos checked against the scenes: map
  • dont-call-lifecycle-hooks — calling an engine lifecycle hook directly instead of letting the engine invoke it
  • camera-pos-aliasingcamera.pos = actor.pos writes through to the live vector
  • no-reserved-tags — engine-owned ex.* tags added via addTag/removeTag
  • no-reserved-uniforms — a Material/ScreenShader source declares a built-in like u_time_ms or v_uv with a conflicting GLSL type; the engine sets it by name at draw time, so it silently reads as zeros or fails to link
  • prefer-seeded-randomMath.random(), unseeded new Random(), and duplicate seeds that correlate streams

Run ex doctor --help for the list. Only .ts files under src/ are checked.

Ignore a finding case-by-case with eslint-style comments — after a report, an interactive prompt offers to insert them for you:

// ex-doctor-ignore-next-line actor-not-added
new OffscreenHelper();
new Cursor(); // ex-doctor-ignore-line unnamed-actor

Omit the rule list to ignore every rule on that line.

ex upgrade — codemod-style version migrations

ex upgrade --dry-run       # preview the full migration plan, write nothing
ex upgrade                 # plan preview + one confirm, then apply + bump package.json
ex upgrade --to next       # target v1 (the `next` prerelease); default is latest
ex upgrade --migrate-only  # rewrite code but leave package.json alone

Chained migrations (v0.29.3 onward, ng-update style) rewrite your source with formatting-preserving splices, classified against your project's installed excalibur types — so run it before installing the new version. Every migration is one of three types:

Automated — rewritten for you, no review needed:

  • ex.Input.* namespace flattened into ex.*
  • event .delta.elapsed
  • Engine.goto(...)goToScene(...)
  • GraphicsComponent.show(...)use(...)
  • Vector.sizemagnitude
  • getGlobalPos()/getGlobalRotation()/getGlobalScale() → the equivalent accessors
  • EventDispatcherEventEmitter
  • Engine.get/setAntialiasing()engine.screen.antialiasing
  • Particle/ParticleEmitter option renames (emitters gained a nested particle config)
  • easeTo/easeBy actions → moveTo/moveBy with easing
  • Timer now only takes the option-bag constructor
  • ScreenShader v_texcoordv_uv
  • BoundingBox.draw(...)debug(...)
  • TileMap's default compositeStrategy changed to 'separate' — pins the old default

Manual — needs human judgment, so // ex-upgrade(<id>): … breadcrumb comments are inserted at each site with a link and recipe:

  • ex.Physics.* statics were removed — configure physics in the Engine constructor
  • collision events now target Collider (was sometimes Entity)
  • System.priority is now static
  • Trigger API changed (action signature, target vs filter)
  • legacy EasingFunctions.* are deprecated — use the simple (t) => number forms
  • screen space is now rooted at the content area (v1's worldToScreenCoordinates/contentArea change)

Notification — no code changes, just a heads-up about a behavior change:

  • Vector.normalize() on a zero vector now returns (0,0) (was (0,1))
  • realistic physics bodies now sleep by default
  • Font/Text render slightly differently in v1

Requires a clean git tree (your undo) unless --allow-dirty; never runs npm install for you.

ex mcp — MCP server for AI agents

Exposes the CLI's capabilities as Model Context Protocol tools over stdio, so agents like Claude Code and OpenCode can search the Excalibur docs, scaffold projects, and generate code in your project.

Claude Code (add -s user to register it globally instead of per-project):

claude mcp add excalibur -- npx -y create-excalibur mcp

OpenCode — add to opencode.json in your project (or ~/.config/opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "excalibur": {
      "type": "local",
      "command": ["npx", "-y", "create-excalibur", "mcp"],
      "enabled": true
    }
  }
}
ex mcp                      # serve, tools operate on the current directory by default
ex mcp --project <dir>      # point the tools at a specific project
ex mcp --help

Docs — also cover the @excaliburjs/plugin-* READMEs (kind: "plugin", /plugins/<name> slugs):

  • docs_search — search guides, API reference, and plugin READMEs; live by default, falls back to the offline cache
  • docs_get_page — fetch a docs page or plugin README (or one section) as markdown
  • docs_sync — download docs + plugin READMEs into the local cache for offline/version-pinned search

Generate — scaffold new code into the project (accept dryRun to preview):

  • analyze_project — inspect scenes, actors, resources, spritesheets, installed version/plugins
  • generate_actor — new Actor class, optionally wired into a scene
  • generate_label — new Label (text) class, optionally wired into a scene
  • generate_scene — new Scene class, registered in the scenes map by default
  • generate_resource — register an image/sound/font/other asset in the resource loader
  • generate_material — new WebGL shader Material, optionally assigned to an actor
  • generate_spritesheet — slice a sheet image into an ex.SpriteSheet
  • generate_animation — build an ex.Animation from an existing spritesheet

Update — edit existing code in place, preserving untouched options and comments:

  • update_actor — change an Actor's super({ ... }) ActorArgs
  • update_engine — change the project's new Engine(...) options

Project lifecycle:

  • list_templates — list templates and sample projects usable with create_project
  • create_project — scaffold a new game from a template (skips npm install/git init unless asked)

Diagnostics:

  • doctor — type-aware lint for common Excalibur mistakes (12 rules)
  • upgrade — chained codemod migrations to a newer Excalibur version

Errors come back with actionable hints so agents can self-correct.

Note: ex shadows the rarely-used system ex (vi's line-editor mode) while the npm global bin dir is first on your PATH. Use the excalibur alias if that bothers you.

Architecture

How the pieces fit together. Everything is TypeScript ESM; each command is a "flow" registered in src/constants.ts and dispatched from index.ts. Development runs the sources directly (Node's type stripping — no build step in the dev loop); publishing compiles to dist/ via tsc, which is what the bins run on end-user machines.

Command dispatch

Both bins point at the compiled dist/index.js. Dispatch is persona-aware: the create persona treats a bare positional as a project name, while ex/excalibur stay strict so a typo never scaffolds.

flowchart LR
    A["npm create excalibur my-game"] --> D
    B["create-excalibur bin"] --> D
    C["ex / excalibur bins"] --> D
    D["resolveInvocation<br/>src/dispatch.ts"]
    D -->|"no args"| MENU["interactive menu<br/>FLOW_CHOICES"]
    D -->|"known command"| FLOWS["FLOWS lookup<br/>src/constants.ts"]
    D -->|"create persona + positional"| CREATE["create flow<br/>name pre-filled"]
    D -->|"ex persona + unknown"| ERR["error: unknown command"]
    MENU --> FLOWS
    FLOWS --> F1["create / sample / inspect"]
    FLOWS --> F2["docs"]
    FLOWS --> F3["generate"]
    FLOWS --> F4["doctor"]
    FLOWS --> F5["mcp<br/>dynamic import, stdout = protocol only"]
    F5 -.->|"16 tools reuse the same cores:<br/>search, apply, doctor, scaffold"| F2

ex docs — search and the offline index

Searches hit the site's Algolia index first and fall back to a locally built index; ex docs offline builds that index straight from the Excalibur repo's docs source, pinned to your installed version.

flowchart TD
    Q["ex docs query"] --> RS["runDocsSearch<br/>src/docs/search.ts"]
    RS -->|"online"| ALG["Algolia DocSearch<br/>public search-only key"]
    RS -->|"--offline"| LOCAL["MiniSearch index<br/>one doc per page section"]
    ALG -->|"network error"| LOCAL
    ALG --> MERGE["merge plugin README hits<br/>up to 3 tail slots"]
    LOCAL --> MERGE
    MERGE --> RENDER["markdown to ANSI renderer<br/>pager for long pages"]

    subgraph SYNC["ex docs offline — sync and indexing"]
        V["detect installed excalibur<br/>node_modules or package.json"] --> REF["pick ref: release tag v0.32.0<br/>or main for old/no version"]
        REF --> TREE["GitHub trees API, one call<br/>list site/docs/**"]
        TREE --> RAW["fetch raw files by commit sha<br/>raw.githubusercontent.com"]
        RAW --> MDX["mdx.ts: frontmatter slugs, admonitions,<br/>playground embeds, wiki links"]
        MDX --> IDX["cache ~/.excalibur/docs/ref:<br/>index.json + slugs.json + manifest"]
        NPM["npm registry:<br/>@excaliburjs/plugin-* readmes"] --> PIDX["plugin index<br/>sibling plugins/ cache"]
        ALG2["Algolia symbol sweep"] --> SYM["api-symbols.json<br/>resolves wiki links"]
    end
    IDX --> LOCAL
    PIDX --> MERGE

ex generate — what it looks for in your TypeScript

Generation is a wizard/apply split: the wizard only builds an option model, and apply*() does the edits. Edits are minimal text splices validated by re-parsing — never a full AST reprint, so your formatting and comments survive. It uses your project's own TypeScript (never bundled; TypeScript 7 removed the compiler API, so it asks for 5.x/6.x).

flowchart TD
    G["ex generate actor / label / scene / resource /<br/>engine / material / update-actor / spritesheet / animation"] --> AP["analyzeProject"]
    AP --> TSL["load the project's TypeScript<br/>from its node_modules"]
    AP --> SCAN
    subgraph SCAN["syntactic AST scan of src/**/*.ts"]
        S1["new Engine and its<br/>scenes map keys"]
        S2["Resources literal:<br/>keys + asset paths"]
        S3["classes extending Scene"]
        S4["classes extending<br/>Actor / Label / ScreenElement"]
        S5["SpriteSheet consts:<br/>grid, spacing, image key"]
        S6["package.json:<br/>@excaliburjs/* plugins"]
    end
    SCAN --> W["wizard prompts<br/>build an option model"]
    W --> APPLY["apply: minimal text splices<br/>insert option property, add import,<br/>add to a scene's onInitialize"]
    APPLY --> VAL["re-parse: zero syntax errors<br/>or the edit is abandoned"]
    VAL -->|"ok"| WRITE["write files"]
    VAL -->|"seam not found"| MANUAL["print a manual snippet<br/>instead of guessing"]

ex doctor — type-aware diagnostics

Doctor is the one place a full ts.Program + TypeChecker is used (generate stays syntactic): the checker is what catches class Boss extends Monster extends Actor. Rules are kind-keyed listeners over a single AST walk per file, the same shape typescript-eslint uses.

flowchart LR
    D["ex doctor --json"] --> AP["analyzeProject"]
    AP --> PROG["ts.createProgram + TypeChecker<br/>tsconfig.json or vite-flavored defaults"]
    PROG --> PROBE["probe: excalibur .d.ts resolvable?<br/>no: run npm install"]
    PROBE --> WALK["one AST walk per src file<br/>dispatch to rule listeners"]
    WALK --> R1["actor-not-added:<br/>Actor-derived new never traced<br/>to add or addChild"]
    WALK --> R2["unnamed-actor:<br/>super options or new Actor<br/>without a name"]
    R1 --> OUT["findings: rule, file:line, message, hint<br/>exit 1 when any are found"]
    R2 --> OUT

Running this project locally

Run npm run dev, or node index.ts docs <query> (Node 22.18+/24 — the dev loop runs the TypeScript sources directly via type stripping; end users only ever run compiled JS).

Tests: npm test · Typecheck: npm run typecheck · Build: npm run build · Publish smoke test: npm run smoke:pack