incanto 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/bin/incanto-check.mjs +27 -0
- package/bin/incanto-multiplay.mjs +170 -0
- package/bin/incanto-new.mjs +29 -7
- package/bin/incanto-playtest.mjs +28 -2
- package/bin/incanto-verify.mjs +155 -19
- package/bin/incanto.mjs +107 -0
- package/dist/2d.d.ts +8 -2
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +9 -3
- package/dist/3d.js +4 -4
- package/dist/{behavior-l08AEbq9.d.ts → behavior-DWKTUzKI.d.ts} +10 -0
- package/dist/{create-game-C5jQYPah.js → create-game-BiW8Men_.js} +61 -13
- package/dist/{create-game-DpbUrMOQ.js → create-game-CHDLDQsQ.js} +6 -6
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +2 -2
- package/dist/{duplicate-BPLZDZpd.js → duplicate-DJQd44CD.js} +1 -1
- package/dist/{environment-presets-CvvQr_bJ.js → environment-presets-DRAz5EV9.js} +12 -10
- package/dist/{gameplay-BVphcxmE.js → gameplay-BBEjPFsR.js} +62 -34
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +36 -8
- package/dist/index.js +8 -8
- package/dist/{json-BLk7H2Qa.js → json-CwwhxQgb.js} +7 -1
- package/dist/{loader-BcrRSjxB.js → loader-D8n7TU8W.js} +142 -5
- package/dist/{loader-BbEMTuWg.d.ts → loader-TvkRFbyL.d.ts} +1 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{pathfinding-mEN4V1CU.d.ts → pathfinding-BqWBb0kh.d.ts} +1 -1
- package/dist/{physics-2d-BLcvEFDR.js → physics-2d-BaRSRrrZ.js} +14 -3
- package/dist/{physics-3d-QBrfIT2Y.js → physics-3d-CYxjh-HW.js} +15 -4
- package/dist/quiet-rapier-BAJ4K94N.js +46 -0
- package/dist/react.d.ts +1 -1
- package/dist/react.js +2 -2
- package/dist/{register-C6ZBFRjd.js → register-BpFcgdcL.js} +57 -27
- package/dist/{register-Ch70uByv.js → register-CDrAQqPp.js} +90 -41
- package/dist/{registry-C7u42TID.js → registry-WWcQcfMr.js} +1 -1
- package/dist/{replay-s7I2GstT.js → replay-CEPyQtF_.js} +31 -7
- package/dist/{replay-Dw6gMlYA.d.ts → replay-O-yAGM76.d.ts} +1 -1
- package/dist/{split-screen-B0baBwxI.d.ts → split-screen-BQ3tAsf-.d.ts} +38 -1
- package/dist/{split-screen-DLsUrleX.js → split-screen-DDMZutQ6.js} +56 -13
- package/dist/{sprite-animation-C0wXLBZJ.js → sprite-animation-CY-mrr1L.js} +1 -1
- package/dist/{src-CGjmPw65.js → src-CY21B462.js} +1 -1
- package/dist/{teardown-Cs113S9F.js → teardown-RApWnM1G.js} +1 -1
- package/dist/{test-it1VekWs.js → test-DHYuFyAu.js} +292 -31
- package/dist/test.d.ts +104 -6
- package/dist/test.js +3 -3
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-CGT7r3Mb.js → agent8-BoRGtVxK.js} +1 -1
- package/editor/assets/{debug-BxWSIHG3.js → debug-CzdyCg75.js} +1 -1
- package/editor/assets/{index-CV1m-aX5.js → index-VesuVEhe.js} +91 -91
- package/editor/index.html +1 -1
- package/package.json +3 -1
- package/schemas/scene.schema.json +1174 -70
- package/skills/incanto-building-2d-games.md +13 -0
- package/skills/incanto-building-3d-games.md +3 -3
- package/skills/incanto-localization.md +40 -8
- package/skills/incanto-multiplayer.md +57 -4
- package/skills/incanto-node-reference.md +18 -0
- package/skills/incanto-physics-and-input.md +26 -0
- package/skills/incanto-playtesting.md +19 -5
- package/skills/incanto-verifying-your-game.md +33 -4
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +7 -6
- package/templates-app/platformer-2d/PROJECT/Context.md +70 -0
- package/templates-app/platformer-2d/PROJECT/Requirements.md +63 -0
- package/templates-app/platformer-2d/PROJECT/Status.md +60 -0
- package/templates-app/platformer-2d/PROJECT/Structure.md +77 -0
- package/templates-app/platformer-2d/docs/project-2d-rules.md +61 -0
- package/templates-app/platformer-2d/index.html +99 -0
- package/templates-app/platformer-2d/package.json +23 -0
- package/templates-app/platformer-2d/src/behaviors.ts +541 -0
- package/templates-app/platformer-2d/src/game.scene.json +2061 -0
- package/templates-app/platformer-2d/src/main.ts +68 -0
- package/templates-app/platformer-2d/tsconfig.json +13 -0
- package/templates-app/platformer-2d/verify.ts +275 -0
- package/templates-app/platformer-2d/vite.config.ts +12 -0
- package/templates-app/star-survivor/PROJECT/Context.md +55 -0
- package/templates-app/star-survivor/PROJECT/Requirements.md +47 -0
- package/templates-app/star-survivor/PROJECT/Status.md +44 -0
- package/templates-app/star-survivor/PROJECT/Structure.md +63 -0
- package/templates-app/star-survivor/docs/project-2d-rules.md +53 -0
- package/templates-app/star-survivor/index.html +232 -0
- package/templates-app/star-survivor/package.json +23 -0
- package/templates-app/star-survivor/src/behaviors.ts +624 -0
- package/templates-app/star-survivor/src/game.scene.json +464 -0
- package/templates-app/star-survivor/src/main.ts +49 -0
- package/templates-app/star-survivor/tsconfig.json +13 -0
- package/templates-app/star-survivor/verify.ts +193 -0
- package/templates-app/star-survivor/vite.config.ts +12 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/game.scene.json +6 -3
- package/templates-app/tps-3d/verify.ts +17 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/grove.scene.json +14 -13
- package/templates-app/village-quest-3d/src/village.scene.json +5 -5
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Status — platformer-2d (Incanto)
|
|
2
|
+
|
|
3
|
+
## Implemented
|
|
4
|
+
|
|
5
|
+
- Full-window single-canvas page with loading overlay, an on-screen JUMP button,
|
|
6
|
+
and the iframe GAME_SIZE harness.
|
|
7
|
+
- `game.scene.json` — **Castle Run**: viewport (`design [960,540]`, `fit:
|
|
8
|
+
expand`), `physics.gravity [0,1800]`, `move` (A/D + arrows) / `jump`
|
|
9
|
+
(Space/W/Up) input, `knight`/`goblin` sheets + `coin`/`gem` textures, and the
|
|
10
|
+
level —
|
|
11
|
+
- `Game` root: `ScoreKeeper` (`scoreToWin 100000`, `lives 3`).
|
|
12
|
+
- Parallax castle backdrop (sky, sun, clouds, far castle band + towers, near
|
|
13
|
+
castle band + battlements) via `ParallaxLayer`.
|
|
14
|
+
- `GroundA–D` stone with green moss caps and gaps; `Plat1–4` floating
|
|
15
|
+
platforms; `MovePlat` (`Patrol` horizontal) + `Lift` (`Oscillate` vertical),
|
|
16
|
+
both group `platform` (rideable).
|
|
17
|
+
- `Spikes1/2` (`hazard`), `DeathPlane` (`pit`), `Checkpoint`, `Goal`.
|
|
18
|
+
- `Gob1–3` goblins (`Patrol` + `GoblinSkin`, group `enemy`).
|
|
19
|
+
- 12 coins + 2 gems (`Pickup` + bobbing `Oscillate` sprite).
|
|
20
|
+
- `Player` (`CharacterBody2D` + `PlayerController`) with `Skin` (knight) +
|
|
21
|
+
`Feet` sensor; `Camera` (`FollowCam`); SFX players; HUD + banner UILayers.
|
|
22
|
+
- Custom code in `src/behaviors.ts`: `PlayerController` (coyote/buffer/double-
|
|
23
|
+
jump/variable height/stomp/knockback/hearts+lives/checkpoint respawn/platform
|
|
24
|
+
carry/anim), `GoblinSkin`, `FollowCam` (follow + shake), `ParallaxLayer`,
|
|
25
|
+
`HudUpdater`. Particle puffs on double-jump/stomp/land/checkpoint via
|
|
26
|
+
`Particles2D`.
|
|
27
|
+
- `connections`: each coin/gem `collected → addScore` (+ SFX); root `won/lost →
|
|
28
|
+
SfxWin/SfxLose`.
|
|
29
|
+
- `main.ts`: inject the four asset urls, `createGame2D`, optional music, JUMP
|
|
30
|
+
button, remove loader, expose `window.game`. Node uids omitted (loader-
|
|
31
|
+
generated).
|
|
32
|
+
|
|
33
|
+
## Works (verified)
|
|
34
|
+
|
|
35
|
+
- `bun run check` → 1/1 scene valid. `bun run typecheck` → clean. `bun run lint`
|
|
36
|
+
→ clean.
|
|
37
|
+
- `bun run verify` (headless `runScript`): 13/13 assertions pass — run right,
|
|
38
|
+
jump off the ground and settle, a coin raises the score (Pickup → addScore), a
|
|
39
|
+
STOMP removes a goblin and scores, a side hit costs a heart, dying respawns the
|
|
40
|
+
knight at the checkpoint, the goal emits `won` once, and a pit fall with the
|
|
41
|
+
last life emits `lost`.
|
|
42
|
+
- Played in a real browser (`bun run dev`, Playwright-driven): the knight + the
|
|
43
|
+
goblins render as their real animated sheets; coins/gems render as sprites;
|
|
44
|
+
ground has moss caps; the parallax castle bands scroll; HUD shows ◆ coins,
|
|
45
|
+
♥♥♥ hearts and lives. A tap jump is a short hop (~41px), a held jump is full
|
|
46
|
+
(~156px), and a mid-air press double-jumps — variable height + double-jump
|
|
47
|
+
confirmed. FollowCam tracks + clamps to the level bounds. ZERO console errors.
|
|
48
|
+
|
|
49
|
+
## Not Included (on purpose — and the next polish passes)
|
|
50
|
+
|
|
51
|
+
- Background castle is styled `ColorRect2D` (no tilemap node in v0): two parallax
|
|
52
|
+
layers (`CastleFarLayer` 0.82 / `CastleNearLayer` 0.6), each a Node2D with ONE
|
|
53
|
+
`ParallaxLayer` whose children (wall band + towers + crenellation merlons + warm
|
|
54
|
+
glowing windows + a gate + a pennant) inherit the scroll. Reads clearly as a
|
|
55
|
+
castle skyline; swap for tile/sprite art later.
|
|
56
|
+
- No wall-jump/dash, no enemy variety beyond the goblin, no melee (the knight
|
|
57
|
+
has an attack sheet 12–17 if you want it), no bundled music (SFX presets only).
|
|
58
|
+
- One hand-authored level — extend by copying nodes into the right GROUP
|
|
59
|
+
(`enemy`/`hazard`/`pit`/`checkpoint`/`platform`); `PlayerController` picks them
|
|
60
|
+
up with no extra wiring.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Structure — platformer-2d (Incanto)
|
|
2
|
+
|
|
3
|
+
## `index.html`
|
|
4
|
+
|
|
5
|
+
Full-window page: inline favicon, loading overlay (removed once the game boots),
|
|
6
|
+
one `#game` canvas, an on-screen `#btn-jump` button (mobile parity), the
|
|
7
|
+
iframe-embed GAME_SIZE script, and the module entry.
|
|
8
|
+
|
|
9
|
+
## `src/game.scene.json`
|
|
10
|
+
|
|
11
|
+
THE whole level (open it with `npx incanto-editor`):
|
|
12
|
+
|
|
13
|
+
- scene header — `environment.background`, `viewport` (`design [960,540]`, `fit:
|
|
14
|
+
expand`), `physics.gravity [0,1800]`, `move`/`jump` input, and the
|
|
15
|
+
`knight`/`goblin` spritesheets + `coin`/`gem` texture `assets` (urls injected
|
|
16
|
+
in `main.ts`).
|
|
17
|
+
- `Game` root — `ScoreKeeper` (`scoreToWin 100000`, `lives 3`).
|
|
18
|
+
- Parallax castle backdrop — `Sky`/`Sun`/`Cloud1–3` (far), `CastleFar` band +
|
|
19
|
+
`TowerFarA–C`, `CastleNear` band + `BattlementA/B` — `ColorRect2D` +
|
|
20
|
+
`ParallaxLayer` (factor 0.6–0.96, higher = farther).
|
|
21
|
+
- `GroundA–D` — `StaticBody2D` stone (brown body + green `Moss` cap) with GAPS
|
|
22
|
+
(pits) between them.
|
|
23
|
+
- `Plat1–4` — static floating platforms; `MovePlat` (`Patrol` pingpong, group
|
|
24
|
+
`platform`) ferries the first pit; `Lift` (`Oscillate` vertical, group
|
|
25
|
+
`platform`) crosses the spike pit.
|
|
26
|
+
- `Spikes1/2` (group `hazard`) and `DeathPlane` (group `pit`, far below).
|
|
27
|
+
- `Checkpoint` (group `checkpoint`, blue flag) and `Goal` (group `goal`, gold
|
|
28
|
+
flag + gate).
|
|
29
|
+
- `Gob1–3` — Node2D (group `enemy`) + `Patrol`; children `Skin`
|
|
30
|
+
(`AnimatedSprite2D` goblin) + `AI` (`GoblinSkin`).
|
|
31
|
+
- `Coins/Coin1–12` — Area2D `Pickup` (value 10) with a bobbing `coin` sprite
|
|
32
|
+
child; `Gem1/2` — Area2D `Pickup` (value 50) with a bobbing `gem` sprite.
|
|
33
|
+
- `Player` — `CharacterBody2D` (group `player`, capsule) + `PlayerController`;
|
|
34
|
+
children `Skin` (`AnimatedSprite2D` knight idle/run/jump) + `Feet` (Area2D
|
|
35
|
+
sensor for moving-platform carry).
|
|
36
|
+
- `Camera` — `Camera2D` (`current`) + `FollowCam` (look-ahead, clamped `limits`,
|
|
37
|
+
screen-shake).
|
|
38
|
+
- `SfxJump/Coin/Stomp/Hurt/Checkpoint/Win/Lose` — `AudioPlayer` SFX presets
|
|
39
|
+
(PlayerController plays jump/stomp/hurt/checkpoint directly; coins/win/lose via
|
|
40
|
+
`connections`).
|
|
41
|
+
- `HUD` — UILayer (top-left, `HudUpdater`): Coin / Hearts / Lives / Hint Labels.
|
|
42
|
+
`BannerLayer` — UILayer (center) win/lose `Banner`.
|
|
43
|
+
- `connections` — each coin/gem `collected → ScoreKeeper.addScore` (+ SFX); root
|
|
44
|
+
`won/lost → SfxWin/SfxLose`. (Stomp/hit/checkpoint/respawn/win-trigger are
|
|
45
|
+
resolved by `PlayerController`, not connections.)
|
|
46
|
+
|
|
47
|
+
## `src/behaviors.ts`
|
|
48
|
+
|
|
49
|
+
- `PlayerController` — the heart: run/gravity/coyote/buffer/double-jump/variable
|
|
50
|
+
height, stomp + bounce, side-hit knockback, hearts+lives, checkpoint respawn,
|
|
51
|
+
moving-platform carry (via the `Feet` sensor), sprite clip + facing + i-frame
|
|
52
|
+
blink. All enemy/hazard/pit/checkpoint/goal contact is AABB against groups in
|
|
53
|
+
`resolveContacts()`.
|
|
54
|
+
- `GoblinSkin` — face the patrol heading + play the goblin walk clip.
|
|
55
|
+
- `FollowCam` — follow (look-ahead + smoothing + world clamp) + `shake()`.
|
|
56
|
+
- `ParallaxLayer` — re-anchor a backdrop to `cameraX · factor` for depth.
|
|
57
|
+
- `HudUpdater` — score/hearts/lives Labels + win/lose banner.
|
|
58
|
+
|
|
59
|
+
## `src/main.ts`
|
|
60
|
+
|
|
61
|
+
Boot: inject the four built-in asset urls, `createGame2D({ canvas, scene,
|
|
62
|
+
behaviors })`, optional `engine.music`, the JUMP button, remove the loader,
|
|
63
|
+
expose `window.game`.
|
|
64
|
+
|
|
65
|
+
## `verify.ts`
|
|
66
|
+
|
|
67
|
+
Browserless proof via `incanto/test` `runScript`: run+jump (off the ground and
|
|
68
|
+
back), coin scoring, STOMP (goblin removed + scored), side-hit costs a heart,
|
|
69
|
+
checkpoint respawn (die → back at the flag), WIN (goal → `won`), LOSE (pit with
|
|
70
|
+
the last life → `lost`). Run with `bun run verify`.
|
|
71
|
+
|
|
72
|
+
## `docs/project-2d-rules.md`
|
|
73
|
+
|
|
74
|
+
The vibe-coding rules: read the skills, JSON structure, built-ins first, omit
|
|
75
|
+
uids, declared assets, y-down space, collider props, GROUP-DRIVEN centralised
|
|
76
|
+
damage (§8), deferred engine access (§11), debug draw, delta discipline, verify
|
|
77
|
+
like a user.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<userRequest>
|
|
2
|
+
YOU MUST follow these rules EXACTLY when vibe-coding on this Incanto template
|
|
3
|
+
(Castle Run — a 2D adventure platformer):
|
|
4
|
+
|
|
5
|
+
1. 📖 READ THE SKILLS FIRST: `node_modules/incanto/skills/` is the engine
|
|
6
|
+
manual, version-pinned to what is installed. Start with
|
|
7
|
+
`incanto-building-2d-games.md` and `incanto-scene-json-authoring.md`, then
|
|
8
|
+
`incanto-gameplay-behaviors.md` (Pickup/Patrol/Oscillate/ScoreKeeper) and
|
|
9
|
+
`incanto-physics-and-input.md` (2D bodies, the input map, units).
|
|
10
|
+
2. 🧱 STRUCTURE IS JSON: scenes, nodes, props, assets, input maps and
|
|
11
|
+
connections all live in `src/game.scene.json`. Add level geometry there (or
|
|
12
|
+
with `npx incanto-editor`), NOT by constructing nodes ad-hoc in code.
|
|
13
|
+
3. 🧠 LOGIC IS BEHAVIORS: prefer a BUILT-IN behavior over custom code (Pickup
|
|
14
|
+
coins/gems, Patrol goblins + the moving platform, Oscillate the lift +
|
|
15
|
+
bobbing pickups, ScoreKeeper score/lives/win-lose, AudioPlayer SFX — all
|
|
16
|
+
wired in JSON). Custom code = small TypeScript Behavior classes registered via
|
|
17
|
+
`createGame2D({ behaviors })` and attached with `"script": { "name": "Name" }`.
|
|
18
|
+
This game's custom behaviors are the platformer GAME FEEL the library leaves
|
|
19
|
+
open: `PlayerController` (coyote-time, jump-buffer, double-jump, variable jump
|
|
20
|
+
height, stomp, knockback, hearts+lives, checkpoint respawn, moving-platform
|
|
21
|
+
carry), `GoblinSkin`, `FollowCam` (follow + screen-shake), `ParallaxLayer`,
|
|
22
|
+
`HudUpdater`.
|
|
23
|
+
4. 🔑 UIDS ARE GENERATED: omit `uid` and the loader assigns one (via the engine's
|
|
24
|
+
`newUid`). NEVER hand-invent readable uid strings.
|
|
25
|
+
5. 📦 ASSETS ARE DECLARED: `assets` entries need `type` + `url`; reference them as
|
|
26
|
+
`"$key"`. The knight + goblin sheets and the coin + gem textures are BUILT-INS
|
|
27
|
+
(`incanto/assets/...`) imported in `main.ts` and injected into the asset url
|
|
28
|
+
placeholders before boot. Free extra key-values are preserved — use them for
|
|
29
|
+
notes (frame ranges, license, source).
|
|
30
|
+
6. ⬇️ Y IS DOWN: 2D space is y-down pixels, (0,0) top-left, clockwise degrees.
|
|
31
|
+
Positive gravity falls (`physics.gravity` is `[0, 1800]`). Up is NEGATIVE
|
|
32
|
+
velocity; a jump subtracts y.
|
|
33
|
+
7. 🧲 COLLIDERS ARE PROPS: `"collider": { "shape": "rect"|"circle"|"capsule", … }`
|
|
34
|
+
on a body node — never child shape nodes. Wrong shapes hard-fail at load.
|
|
35
|
+
7b. 🦶 STAND THE FEET ON THE GROUND: a sprite-sheet `anchor` is the artist's pivot
|
|
36
|
+
(hip/centre), NOT the feet, and the frame has transparent padding below the art —
|
|
37
|
+
so a character will FLOAT unless you align it. MEASURE the feet (bottom opaque row
|
|
38
|
+
÷ frame height) and set `anchor.y` so the visible feet sit at the collider bottom
|
|
39
|
+
(here the knight is `0.464`, goblins `0.348`, not the sheet's ~0.61). See
|
|
40
|
+
`incanto-building-2d-games.md` → AnimatedSprite2D "stand the feet on the ground".
|
|
41
|
+
8. 🎯 DAMAGE IS CENTRALISED + GROUP-DRIVEN: the player takes NO built-in Health —
|
|
42
|
+
`PlayerController` owns hearts/lives and resolves ALL contact by AABB against
|
|
43
|
+
GROUPS each frame, so there's one authority and never a stomp-vs-damage
|
|
44
|
+
double-trigger. Tag content with groups: `enemy` (stompable from above, hurts
|
|
45
|
+
on the side), `hazard` (spikes → lose a heart), `pit` (death plane → instant
|
|
46
|
+
life loss), `checkpoint` (sets respawn), `goal` (win), `platform` (a moving
|
|
47
|
+
body the Feet sensor rides). Add an enemy/hazard = add the node in the right
|
|
48
|
+
group; no wiring needed.
|
|
49
|
+
9. 🐛 DEBUG WHEN UNSURE: `createGame2D({ debug: true })` (or `VITE_INCANTO_DEBUG=1`)
|
|
50
|
+
shows the Explorer/Inspector/Stats; `physics.debugDraw = true` draws colliders.
|
|
51
|
+
10. 🎬 DELTA DISCIPLINE: only write props that differ from defaults — the loader
|
|
52
|
+
treats unknown/garbage props as hard errors, which is your friend.
|
|
53
|
+
11. 🧭 ENGINE ACCESS IS DEFERRED: `this.engine` is NOT available in `onReady`
|
|
54
|
+
during `loadScene` (the scene isn't attached yet) — read scene config
|
|
55
|
+
(gravity, etc.) lazily on the first `fixedUpdate`. `getNode`/signals are fine
|
|
56
|
+
in `onReady`.
|
|
57
|
+
12. ✅ VERIFY LIKE A USER: `bun run check` (scene valid) → `bun run verify`
|
|
58
|
+
(headless run/jump/coin/stomp/checkpoint/win/lose proof) → `bun run dev`,
|
|
59
|
+
open the browser, and actually PLAY what you changed (run, double-jump, stomp
|
|
60
|
+
a goblin, ride the lift, die and respawn at the flag) before declaring done.
|
|
61
|
+
</userRequest>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><rect width=%22100%22 height=%22100%22 rx=%2220%22 fill=%22%236ee7dc%22/><text x=%2250%22 y=%2268%22 font-size=%2255%22 text-anchor=%22middle%22 font-family=%22Arial%22 font-weight=%22bold%22 fill=%22%230b0d14%22>in</text></svg>" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
7
|
+
<title>Castle Run — Incanto platformer</title>
|
|
8
|
+
<style>
|
|
9
|
+
html,
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
height: 100%;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
font-family: Arial, sans-serif;
|
|
16
|
+
background: #6aa9cf;
|
|
17
|
+
}
|
|
18
|
+
canvas {
|
|
19
|
+
display: block;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
.loading-container {
|
|
24
|
+
position: fixed;
|
|
25
|
+
inset: 0;
|
|
26
|
+
z-index: 50;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
background: #6aa9cf;
|
|
32
|
+
color: white;
|
|
33
|
+
}
|
|
34
|
+
.loading-title {
|
|
35
|
+
font-size: 1.5rem;
|
|
36
|
+
font-weight: bold;
|
|
37
|
+
margin-bottom: 1rem;
|
|
38
|
+
}
|
|
39
|
+
.spinner {
|
|
40
|
+
width: 30px;
|
|
41
|
+
height: 30px;
|
|
42
|
+
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
border-top-color: white;
|
|
45
|
+
animation: spin 1s ease-in-out infinite;
|
|
46
|
+
}
|
|
47
|
+
@keyframes spin {
|
|
48
|
+
to {
|
|
49
|
+
transform: rotate(360deg);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
.round-btn {
|
|
53
|
+
position: fixed;
|
|
54
|
+
bottom: 2rem;
|
|
55
|
+
right: 2rem;
|
|
56
|
+
z-index: 1001;
|
|
57
|
+
width: 88px;
|
|
58
|
+
height: 88px;
|
|
59
|
+
border: none;
|
|
60
|
+
border-radius: 9999px;
|
|
61
|
+
background: rgba(255, 209, 102, 0.45);
|
|
62
|
+
color: #1d2a44;
|
|
63
|
+
font-weight: bold;
|
|
64
|
+
font-size: 0.9rem;
|
|
65
|
+
cursor: pointer;
|
|
66
|
+
user-select: none;
|
|
67
|
+
-webkit-user-select: none;
|
|
68
|
+
touch-action: none;
|
|
69
|
+
transition: transform 0.1s;
|
|
70
|
+
}
|
|
71
|
+
.round-btn:active {
|
|
72
|
+
transform: scale(0.9);
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
75
|
+
</head>
|
|
76
|
+
<body>
|
|
77
|
+
<div class="loading-container" id="loading">
|
|
78
|
+
<h2 class="loading-title">Castle Run</h2>
|
|
79
|
+
<div class="spinner"></div>
|
|
80
|
+
</div>
|
|
81
|
+
<canvas id="game"></canvas>
|
|
82
|
+
<button type="button" id="btn-jump" class="round-btn">JUMP</button>
|
|
83
|
+
<script>
|
|
84
|
+
// agent8 embed harness: report the game size to a hosting iframe parent.
|
|
85
|
+
function postGameSize() {
|
|
86
|
+
window.parent.postMessage(
|
|
87
|
+
{ type: 'GAME_SIZE_RESPONSE', width: document.body.scrollWidth, height: document.body.scrollHeight },
|
|
88
|
+
'*',
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
window.addEventListener('load', postGameSize);
|
|
92
|
+
window.addEventListener('resize', postGameSize);
|
|
93
|
+
window.addEventListener('message', (e) => {
|
|
94
|
+
if (e.data && e.data.type === 'REQUEST_GAME_SIZE') postGameSize();
|
|
95
|
+
});
|
|
96
|
+
</script>
|
|
97
|
+
<script type="module" src="/src/main.ts"></script>
|
|
98
|
+
</body>
|
|
99
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "platformer-2d",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"typecheck": "tsc --noEmit",
|
|
9
|
+
"check": "incanto-check src",
|
|
10
|
+
"verify": "bun verify.ts"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@dimforge/rapier2d-compat": "0.19.3",
|
|
14
|
+
"incanto": "^0.59.0",
|
|
15
|
+
"three": "^0.184.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^24.0.0",
|
|
19
|
+
"@types/three": "^0.184.1",
|
|
20
|
+
"typescript": "^6.0.3",
|
|
21
|
+
"vite": "^8.0.16"
|
|
22
|
+
}
|
|
23
|
+
}
|