Observed since 20 Oct, 20:40 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
5velte-ph4ser
Svelte 5 components and hooks for building Phaser 4 games
Svelte 5 components and hooks for building Phaser 4 games.
A modern rewrite of the original svelte-phaser (Svelte 3 / Phaser 3) using runes, snippets and callback props — targeting Svelte ^5 and Phaser ^4.
| Layer | What | Where it works |
|---|---|---|
Core (svelte-phaser/core, JSR: @easierbycode/svelte-phaser) | Pure TypeScript: context getters, event hooks, prop appliers, and compiler-free hooks (useSprite, useArcadePhysics, createGame, …). Reactivity flows out through svelte/store and in through per-step prop syncing — no runes, no .svelte files. | Anywhere — including installed from JSR, which only accepts JS/TS modules. |
Components (svelte-phaser) | .svelte components (<Game>, <Scene>, <Sprite>, …) built on the core, with fine-grained $effect prop bindings. | npm / workspace installs, where your bundler's Svelte plugin compiles library source. |
Why the split? JSR's module graph only accepts JavaScript/TypeScript —
.sveltefiles (and rune code, which needs the Svelte compiler) cannot be published there (jsr-io/jsr#861). The core layer is designed to be fully usable without the compiler, so the JSR package is a real, working game-binding API — not a stub.
From JSR (core API):
npx jsr add @easierbycode/svelte-phaser
From a workspace / local checkout (components + core) — note the unscoped
svelte-phaser name on the npm registry belongs to the original Svelte 3
project, so install this package by path:
npm install phaser svelte
npm i 5velte-ph4ser
(see examples/dino, which consumes it via file:../..)
<script lang="ts">
import Phaser from 'phaser'
import { Game, Scene, Sprite, Text } from 'svelte-phaser'
function preload(scene: Phaser.Scene) {
scene.load.image('player', 'assets/player.png')
}
</script>
<Game width={800} height={600} physics={{ default: 'arcade' }}>
<Scene key="main" {preload}>
{#snippet loading(progress)}
<Text x={400} y={300} text={`Loading ${Math.round(progress * 100)}%`} />
{/snippet}
<Sprite texture="player" x={400} y={300} />
</Scene>
</Game>
<Game> — creates the Phaser.Game. Accepts game config as props, a
booting snippet, and bind:instance.<Scene key> — creates and registers a Phaser.Scene. Accepts preload /
create / init callbacks, a loading snippet (receives progress 0–1),
and bind:instance.<Sprite>, <Text>, <TileSprite>, <Rectangle>, <Container> — game
objects. Props apply reactively; omitted props keep Phaser defaults.
Phaser events surface as callback props (onpointerdown,
onanimationcomplete, …).<ArcadePhysics> — enables an arcade body on the parent game object
(velocityX, bounce, collideWorldBounds, circle, …).<ArcadeCollider with={...} overlapOnly oncollide={...}> — collides the
parent game object with other objects, or with names (string targets are
matched against gameObject.name, including objects spawned later).<Spawner> — provides getSpawner() context so gameplay code can
imperatively spawn(Component, props) (bullets, pickups, …). Spawned
components receive an onDestroy prop to remove themselves.import {
getGame, getScene, getSpawner, getGameObject, getContainer,
onGameEvent, onSceneEvent, onInputEvent, onArcadePhysicsEvent,
} from 'svelte-phaser'
const scene = getScene()
onGameEvent('step', () => { /* runs every game step */ })
onInputEvent('pointerdown', () => { /* ... */ })
The hooks create the same objects without any library .svelte files. Pass a
props getter — it is re-read every game step and only changed values are
re-applied to Phaser:
<script lang="ts">
import { createGame, createScene, useSprite, useArcadePhysics }
from '@easierbycode/svelte-phaser'
// inside your own components:
const sprite = useSprite(() => ({ texture: 'player', x, y }))
useArcadePhysics(() => ({ velocityX, collideWorldBounds: true }), sprite)
</script>
createGame(config) → { game, booted } (booted is a store)createScene({ key, preload, create }) → { scene, loading, progress } (stores)createSpawner() → { spawn } — mounts components imperatively with the
current context (uses Svelte's public mount/unmount)useSprite / useText / useTileSprite / useRectangle / useContainer(getProps)useArcadePhysics(getProps, gameObject?), useArcadeCollider(props, gameObject?)applyGameObjectProps(...) etc. — the underlying idempotent prop appliersAll hooks must be called during component initialisation (they use Svelte context and lifecycle under the hood).
<Container>/<Rectangle>/<Text>, keyed
{#each} obstacle spawning, onGameEvent/onInputEvent, and reactive
theme/color customization. cd examples/dino && npm install && npm run dev.
The deployable full-stack version (Deno Deploy + PostgreSQL leaderboard)
lives at dino-sp.npx jsr publish from this directory publishes the core layer as
@easierbycode/svelte-phaser (see jsr.json). Run npm install here first
so the bare svelte/phaser specifiers type-check, then validate with
npx jsr publish --dry-run..svelte/TS source, which
@sveltejs/vite-plugin-svelte compiles in the consuming app (the svelte
export condition points at the source). The unscoped svelte-phaser npm
name is taken by the original project, so publishing to npm requires a
scoped rename (e.g. @easierbycode/svelte-phaser) in package.json.@sveltejs/vite-plugin-svelte)npm · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-20 | 1 | 2026-10-20T21:34:24.4849505Z |
| Package / target | Requirement | Relationship |
|---|---|---|
phaserEnvironment{
"local_name": "phaser",
"alias": false,
"peer_metadata": null
} | ^4.0.0 | development |
svelteEnvironment{
"local_name": "svelte",
"alias": false,
"peer_metadata": null
} | ^5.0.0 | development |
phaserEnvironment{
"local_name": "phaser",
"alias": false,
"peer_metadata": null
} | ^4.0.0 | peer |
svelteEnvironment{
"local_name": "svelte",
"alias": false,
"peer_metadata": null
} | ^5.0.0 | peer |
Source distribution
{
"shasum": "9c4094c26dee1638d47a9db9e8edc195a4854d68",
"tarball": "https://registry.npmjs.org/5velte-ph4ser/-/5velte-ph4ser-1.0.0.tgz",
"fileCount": 25,
"integrity": "sha512-EktfL/F3HcNci+x/QH3JF9Lnvx8LMfA4rLTuerMJT4ZzF63uzPrZ1UGMJDToEsk5SYpFMVb30R2axcVgzR3STA==",
"signatures": [
{
"sig": "MEQCIFny5FjbpqkOkTCXSz8nMqnaZ86sV7zqXBjXsd4vxDD6AiB1KTL4Br2RJJpoRuCICwtu8CTMm9IQnQerynd/8ZJS0A==",
"keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
}
],
"unpackedSize": 62615
}Shared repository data · GitHub
Observed since 20 Oct, 20:40 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:670fd0e4d53520fa75c3f0a06a302cda06feef2c8d0e08b0b00515e4f05ed741