@waica/cli 0.7.0 → 0.9.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.
Files changed (114) hide show
  1. package/README.md +1 -1
  2. package/dist/editor/assets/{cssMode-eS4pAOyh.js → cssMode-DM5x3eXD.js} +1 -1
  3. package/dist/editor/assets/{freemarker2-FMQjZKQk.js → freemarker2-CmlzUOOI.js} +1 -1
  4. package/dist/editor/assets/{handlebars-dDYOnqat.js → handlebars-Dlz-T3Pu.js} +1 -1
  5. package/dist/editor/assets/{html-Ba6xZh4T.js → html-B-NfgvUd.js} +1 -1
  6. package/dist/editor/assets/{htmlMode-DC9qJr2p.js → htmlMode-K4hF3BAu.js} +1 -1
  7. package/dist/editor/assets/{index-CoyeInOT.js → index-Ca2oPxGt.js} +4626 -1104
  8. package/dist/editor/assets/{index-Cy5pmBhN.css → index-CzarIYLW.css} +1 -1
  9. package/dist/editor/assets/{javascript-DOwFvmvM.js → javascript-COj32tw-.js} +1 -1
  10. package/dist/editor/assets/{jsonMode-CcG7zlSf.js → jsonMode-DyL12Tvg.js} +1 -1
  11. package/dist/editor/assets/{liquid-Dfp71r7J.js → liquid-CGaRZ9Iu.js} +1 -1
  12. package/dist/editor/assets/{mdx-Ci7vVeht.js → mdx-L4fRd4xO.js} +1 -1
  13. package/dist/editor/assets/{python-Bluv3Y9Q.js → python-Z6FCrHUG.js} +1 -1
  14. package/dist/editor/assets/{razor-BtwTXMaK.js → razor-6XSfF-a3.js} +1 -1
  15. package/dist/editor/assets/{tsMode-D3_D-H85.js → tsMode-C24rNZgD.js} +1 -1
  16. package/dist/editor/assets/{typescript-Ch_PS5f7.js → typescript-BcFln1pD.js} +1 -1
  17. package/dist/editor/assets/waica-iso-hero-BsEdW0V7.png +0 -0
  18. package/dist/editor/assets/waica-iso-orc-DRK-SaXm.png +0 -0
  19. package/dist/editor/assets/waica-iso-villager-szDkD_Ag.png +0 -0
  20. package/dist/editor/assets/{xml-CI_bH_MX.js → xml-DJCue8rm.js} +1 -1
  21. package/dist/editor/assets/{yaml-LD9GTZyy.js → yaml-DiJf3V99.js} +1 -1
  22. package/dist/editor/index.html +2 -2
  23. package/dist/mcp/known-archetypes.js +5 -0
  24. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/ATTRIBUTION.md +93 -0
  25. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-crate.png +0 -0
  26. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-ground.png +0 -0
  27. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-hero.png +0 -0
  28. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-orc.png +0 -0
  29. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-rock.png +0 -0
  30. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-tree.png +0 -0
  31. package/dist/mcp/node_modules/@waica/archetype-isometric/assets/waica-iso-villager.png +0 -0
  32. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/animation.d.ts +7 -0
  33. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/animation.js +17 -0
  34. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/art.d.ts +3 -0
  35. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/art.js +10 -0
  36. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/bundle.d.ts +2 -0
  37. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/bundle.js +9 -0
  38. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/controls.d.ts +3 -0
  39. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/controls.js +16 -0
  40. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/index.d.ts +24 -0
  41. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/index.js +15 -0
  42. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/manifest.d.ts +16 -0
  43. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/manifest.js +30 -0
  44. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/prefabs.d.ts +22 -0
  45. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/prefabs.js +215 -0
  46. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/registry-data.d.ts +3 -0
  47. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/registry-data.js +47 -0
  48. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/registry.d.ts +4 -0
  49. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/registry.js +17 -0
  50. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/scene-default.d.ts +5 -0
  51. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/scene-default.js +59 -0
  52. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/ui.d.ts +1 -0
  53. package/dist/mcp/node_modules/@waica/archetype-isometric/dist/ui.js +30 -0
  54. package/dist/mcp/node_modules/@waica/archetype-isometric/package.json +30 -0
  55. package/dist/mcp/node_modules/@waica/archetype-platformer/package.json +3 -3
  56. package/dist/mcp/node_modules/@waica/archetype-topdown/dist/animation.d.ts +2 -1
  57. package/dist/mcp/node_modules/@waica/archetype-topdown/dist/animation.js +6 -2
  58. package/dist/mcp/node_modules/@waica/archetype-topdown/dist/registry-data.js +2 -1
  59. package/dist/mcp/node_modules/@waica/archetype-topdown/dist/ui.js +2 -19
  60. package/dist/mcp/node_modules/@waica/archetype-topdown/package.json +3 -3
  61. package/dist/mcp/node_modules/@waica/behaviors/dist/facing.d.ts +18 -0
  62. package/dist/mcp/node_modules/@waica/behaviors/dist/facing.js +56 -0
  63. package/dist/mcp/node_modules/@waica/behaviors/dist/grid-motor.d.ts +64 -0
  64. package/dist/mcp/node_modules/@waica/behaviors/dist/grid-motor.js +77 -0
  65. package/dist/mcp/node_modules/@waica/behaviors/dist/grid-player-role.d.ts +20 -0
  66. package/dist/mcp/node_modules/@waica/behaviors/dist/grid-player-role.js +133 -0
  67. package/dist/mcp/node_modules/@waica/behaviors/dist/health.d.ts +29 -0
  68. package/dist/mcp/node_modules/@waica/behaviors/dist/health.js +79 -3
  69. package/dist/mcp/node_modules/@waica/behaviors/dist/index.d.ts +4 -1
  70. package/dist/mcp/node_modules/@waica/behaviors/dist/index.js +4 -1
  71. package/dist/mcp/node_modules/@waica/behaviors/dist/interactable.d.ts +3 -0
  72. package/dist/mcp/node_modules/@waica/behaviors/dist/interactable.js +25 -2
  73. package/dist/mcp/node_modules/@waica/behaviors/dist/iso-motor.d.ts +21 -0
  74. package/dist/mcp/node_modules/@waica/behaviors/dist/iso-motor.js +24 -0
  75. package/dist/mcp/node_modules/@waica/behaviors/dist/iso-player-states.d.ts +5 -0
  76. package/dist/mcp/node_modules/@waica/behaviors/dist/iso-player-states.js +9 -0
  77. package/dist/mcp/node_modules/@waica/behaviors/dist/melee-attack.d.ts +48 -0
  78. package/dist/mcp/node_modules/@waica/behaviors/dist/melee-attack.js +83 -0
  79. package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.d.ts +11 -3
  80. package/dist/mcp/node_modules/@waica/behaviors/dist/patrol.js +49 -5
  81. package/dist/mcp/node_modules/@waica/behaviors/dist/topdown-motor.d.ts +7 -61
  82. package/dist/mcp/node_modules/@waica/behaviors/dist/topdown-motor.js +8 -79
  83. package/dist/mcp/node_modules/@waica/behaviors/dist/topdown-player-states.d.ts +4 -17
  84. package/dist/mcp/node_modules/@waica/behaviors/dist/topdown-player-states.js +10 -82
  85. package/dist/mcp/node_modules/@waica/behaviors/package.json +2 -2
  86. package/dist/mcp/node_modules/@waica/engine/dist/component.d.ts +2 -0
  87. package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.d.ts +19 -1
  88. package/dist/mcp/node_modules/@waica/engine/dist/components/animated-sprite.js +35 -7
  89. package/dist/mcp/node_modules/@waica/engine/dist/components/dynamic-body.js +2 -4
  90. package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.d.ts +19 -0
  91. package/dist/mcp/node_modules/@waica/engine/dist/components/sprite.js +44 -8
  92. package/dist/mcp/node_modules/@waica/engine/dist/components/tilemap.d.ts +113 -0
  93. package/dist/mcp/node_modules/@waica/engine/dist/components/tilemap.js +316 -0
  94. package/dist/mcp/node_modules/@waica/engine/dist/entity.d.ts +3 -0
  95. package/dist/mcp/node_modules/@waica/engine/dist/entity.js +13 -1
  96. package/dist/mcp/node_modules/@waica/engine/dist/game.d.ts +4 -0
  97. package/dist/mcp/node_modules/@waica/engine/dist/game.js +41 -9
  98. package/dist/mcp/node_modules/@waica/engine/dist/index.d.ts +9 -0
  99. package/dist/mcp/node_modules/@waica/engine/dist/index.js +5 -0
  100. package/dist/mcp/node_modules/@waica/engine/dist/projection.d.ts +14 -0
  101. package/dist/mcp/node_modules/@waica/engine/dist/projection.js +30 -0
  102. package/dist/mcp/node_modules/@waica/engine/dist/scene-solids.d.ts +16 -0
  103. package/dist/mcp/node_modules/@waica/engine/dist/scene-solids.js +28 -0
  104. package/dist/mcp/node_modules/@waica/engine/dist/scene.d.ts +3 -1
  105. package/dist/mcp/node_modules/@waica/engine/dist/solid-axis.js +2 -4
  106. package/dist/mcp/node_modules/@waica/engine/dist/sprite-placement.d.ts +22 -0
  107. package/dist/mcp/node_modules/@waica/engine/dist/sprite-placement.js +14 -0
  108. package/dist/mcp/node_modules/@waica/engine/dist/tilemap-grid.d.ts +26 -0
  109. package/dist/mcp/node_modules/@waica/engine/dist/tilemap-grid.js +41 -0
  110. package/dist/mcp/node_modules/@waica/engine/package.json +1 -1
  111. package/dist/mcp/package-resolver.js +4 -0
  112. package/dist/mcp/project-component-runner.js +1 -0
  113. package/dist/mcp/template/src/stats.json +2 -1
  114. package/package.json +1 -1
@@ -0,0 +1,16 @@
1
+ export const ISOMETRIC_BINDINGS = {
2
+ up: ['ArrowUp', 'KeyW'],
3
+ down: ['ArrowDown', 'KeyS'],
4
+ left: ['ArrowLeft', 'KeyA'],
5
+ right: ['ArrowRight', 'KeyD'],
6
+ interact: ['KeyE', 'Space'],
7
+ attack: ['KeyX', 'KeyJ'],
8
+ };
9
+ export const ISOMETRIC_ACTION_LABELS = {
10
+ up: 'Move up',
11
+ down: 'Move down',
12
+ left: 'Move left',
13
+ right: 'Move right',
14
+ interact: 'Interact',
15
+ attack: 'Attack',
16
+ };
@@ -0,0 +1,24 @@
1
+ export { ISOMETRIC_ANIMATION } from './animation.js';
2
+ export { ISOMETRIC_ART } from './art.js';
3
+ export { ISOMETRIC_BUNDLE } from './bundle.js';
4
+ export { ISOMETRIC_ACTION_LABELS, ISOMETRIC_BINDINGS } from './controls.js';
5
+ export { ISOMETRIC_PREFABS, ISOMETRIC_HERO_SPRITE } from './prefabs.js';
6
+ export { ISOMETRIC_ART_URLS, ISOMETRIC_PALETTE, ISOMETRIC_REGISTRY, } from './registry.js';
7
+ export { ISOMETRIC_BLANK_SCENE, ISOMETRIC_SCENE } from './scene-default.js';
8
+ export { ISOMETRIC_UI } from './ui.js';
9
+ export declare const ARCHETYPE: {
10
+ id: string;
11
+ label: string;
12
+ scene: import("@waica/engine").SceneJson;
13
+ blankScene: import("@waica/engine").SceneJson;
14
+ palette: import("@waica/engine").EntityTemplate[];
15
+ prefabs: Record<string, import("@waica/engine").PrefabJson>;
16
+ art: import("@waica/engine").ArchetypeArt[];
17
+ entityIcons: Readonly<Record<string, string>>;
18
+ bindings: Readonly<import("@waica/engine").InputBindings>;
19
+ actionLabels: Readonly<Record<string, string>>;
20
+ bundle: import("@waica/engine").ArchetypeBundle;
21
+ animation: import("@waica/engine").DirectionalAnimation<string>;
22
+ registry: import("@waica/engine").SceneRegistry;
23
+ artUrls: Record<string, string>;
24
+ };
@@ -0,0 +1,15 @@
1
+ import { ARCHETYPE as DATA_ARCHETYPE } from './manifest.js';
2
+ import { ISOMETRIC_ART_URLS, ISOMETRIC_REGISTRY } from './registry.js';
3
+ export { ISOMETRIC_ANIMATION } from './animation.js';
4
+ export { ISOMETRIC_ART } from './art.js';
5
+ export { ISOMETRIC_BUNDLE } from './bundle.js';
6
+ export { ISOMETRIC_ACTION_LABELS, ISOMETRIC_BINDINGS } from './controls.js';
7
+ export { ISOMETRIC_PREFABS, ISOMETRIC_HERO_SPRITE } from './prefabs.js';
8
+ export { ISOMETRIC_ART_URLS, ISOMETRIC_PALETTE, ISOMETRIC_REGISTRY, } from './registry.js';
9
+ export { ISOMETRIC_BLANK_SCENE, ISOMETRIC_SCENE } from './scene-default.js';
10
+ export { ISOMETRIC_UI } from './ui.js';
11
+ export const ARCHETYPE = {
12
+ ...DATA_ARCHETYPE,
13
+ registry: ISOMETRIC_REGISTRY,
14
+ artUrls: ISOMETRIC_ART_URLS,
15
+ };
@@ -0,0 +1,16 @@
1
+ export declare const ISOMETRIC_ENTITY_ICONS: Readonly<Record<string, string>>;
2
+ export declare const ARCHETYPE: {
3
+ id: string;
4
+ label: string;
5
+ scene: import("@waica/engine").SceneJson;
6
+ blankScene: import("@waica/engine").SceneJson;
7
+ registry: import("@waica/engine").SceneRegistry;
8
+ palette: import("@waica/engine").EntityTemplate[];
9
+ prefabs: Record<string, import("@waica/engine").PrefabJson>;
10
+ art: import("@waica/engine").ArchetypeArt[];
11
+ entityIcons: Readonly<Record<string, string>>;
12
+ bindings: Readonly<import("@waica/engine").InputBindings>;
13
+ actionLabels: Readonly<Record<string, string>>;
14
+ bundle: import("@waica/engine").ArchetypeBundle;
15
+ animation: import("@waica/engine").DirectionalAnimation<string>;
16
+ };
@@ -0,0 +1,30 @@
1
+ import { ISOMETRIC_ANIMATION } from './animation.js';
2
+ import { ISOMETRIC_ART } from './art.js';
3
+ import { ISOMETRIC_BUNDLE } from './bundle.js';
4
+ import { ISOMETRIC_ACTION_LABELS, ISOMETRIC_BINDINGS } from './controls.js';
5
+ import { ISOMETRIC_PREFABS } from './prefabs.js';
6
+ import { ISOMETRIC_PALETTE, ISOMETRIC_REGISTRY_DATA } from './registry-data.js';
7
+ import { ISOMETRIC_BLANK_SCENE, ISOMETRIC_SCENE } from './scene-default.js';
8
+ export const ISOMETRIC_ENTITY_ICONS = {
9
+ IsoMotor: '🧭',
10
+ Tilemap: '💎',
11
+ MeleeAttack: '⚔️',
12
+ Interactable: '💬',
13
+ Collectible: '📦',
14
+ Hazard: '👹',
15
+ };
16
+ export const ARCHETYPE = {
17
+ id: 'isometric',
18
+ label: 'Isometric',
19
+ scene: ISOMETRIC_SCENE,
20
+ blankScene: ISOMETRIC_BLANK_SCENE,
21
+ registry: ISOMETRIC_REGISTRY_DATA,
22
+ palette: ISOMETRIC_PALETTE,
23
+ prefabs: ISOMETRIC_PREFABS,
24
+ art: ISOMETRIC_ART,
25
+ entityIcons: ISOMETRIC_ENTITY_ICONS,
26
+ bindings: ISOMETRIC_BINDINGS,
27
+ actionLabels: ISOMETRIC_ACTION_LABELS,
28
+ bundle: ISOMETRIC_BUNDLE,
29
+ animation: ISOMETRIC_ANIMATION,
30
+ };
@@ -0,0 +1,22 @@
1
+ import type { PrefabJson } from '@waica/engine';
2
+ type ClipMap = Record<string, {
3
+ frames: number[];
4
+ fps: number;
5
+ loop?: boolean;
6
+ }>;
7
+ export declare const ISOMETRIC_HERO_SPRITE: {
8
+ texture: string;
9
+ cols: number;
10
+ rows: number;
11
+ spacingX: number;
12
+ spacingY: number;
13
+ pixelArt: boolean;
14
+ width: number;
15
+ height: number;
16
+ anchorY: number;
17
+ offsetY: number;
18
+ clips: ClipMap;
19
+ initialClip: string;
20
+ };
21
+ export declare const ISOMETRIC_PREFABS: Record<string, PrefabJson>;
22
+ export {};
@@ -0,0 +1,215 @@
1
+ import { ISO_PLAYER_STATE_GRAPH, NPC_STATE_GRAPH, PATROLLER_STATE_GRAPH, } from '@waica/behaviors';
2
+ const SHIPPED_DIRECTIONS = ['n', 'ne', 'e', 'se', 's'];
3
+ /** One row per shipped facing: idle · walk×3 · attack×3 · hurt×2 · death×2. */
4
+ const SHEET_COLUMNS = 11;
5
+ const SOUTH_ROW = SHIPPED_DIRECTIONS.indexOf('s') * SHEET_COLUMNS;
6
+ /** Transparent texels under the boots in every Puny cell, in render units (9 / 16). */
7
+ const BOOTS_OFFSET = -9 / 16;
8
+ function directionalClips({ plain = false, attacks = false }) {
9
+ const clips = {};
10
+ SHIPPED_DIRECTIONS.forEach((direction, row) => {
11
+ const first = row * SHEET_COLUMNS;
12
+ clips[`idle-${direction}`] = { frames: [first], fps: 2 };
13
+ clips[`walk-${direction}`] = {
14
+ frames: [first + 1, first + 2, first + 3, first + 2],
15
+ fps: 8,
16
+ };
17
+ if (attacks) {
18
+ clips[`attack-${direction}`] = { frames: [first + 4, first + 5, first + 6], fps: 12, loop: false };
19
+ }
20
+ clips[`hurt-${direction}`] = { frames: [first + 7, first + 8], fps: 8, loop: false };
21
+ clips[`death-${direction}`] = { frames: [first + 9, first + 10], fps: 4, loop: false };
22
+ });
23
+ if (plain) {
24
+ clips['idle'] = { frames: [SOUTH_ROW], fps: 2 };
25
+ clips['walk'] = { frames: [SOUTH_ROW + 1, SOUTH_ROW + 2, SOUTH_ROW + 3, SOUTH_ROW + 2], fps: 8 };
26
+ }
27
+ return clips;
28
+ }
29
+ function characterSprite(texture, options = {}) {
30
+ return {
31
+ texture,
32
+ cols: SHEET_COLUMNS,
33
+ rows: 5,
34
+ spacingX: 1,
35
+ spacingY: 1,
36
+ pixelArt: true,
37
+ width: 2,
38
+ height: 2,
39
+ anchorY: 0,
40
+ // The Puny bodies stand 9 texels above their cell's bottom edge; shift the
41
+ // quad down so the boots sit on the entity's position (its footprint),
42
+ // instead of floating half a unit up the screen — over a water diamond
43
+ // the body is actually stopped short of.
44
+ offsetY: BOOTS_OFFSET,
45
+ clips: directionalClips(options),
46
+ initialClip: options.plain ? 'idle' : 'idle-s',
47
+ };
48
+ }
49
+ export const ISOMETRIC_HERO_SPRITE = characterSprite('waica:iso-hero', { attacks: true });
50
+ const MAP_WIDTH = 16;
51
+ const MAP_HEIGHT = 16;
52
+ const GRASS = 0;
53
+ const DIRT = 1;
54
+ const PATH = 2;
55
+ const WATER = 3;
56
+ const BORDER = 4;
57
+ function tileAt(column, row) {
58
+ if (column === 0 || row === 0 || column === MAP_WIDTH - 1 || row === MAP_HEIGHT - 1) {
59
+ return BORDER;
60
+ }
61
+ if (column >= 11 && column <= 12 && row >= 5 && row <= 6)
62
+ return WATER;
63
+ if (column === 7 || row === 7)
64
+ return PATH;
65
+ if (column >= 2 && column <= 5 && row >= 2 && row <= 4)
66
+ return DIRT;
67
+ return GRASS;
68
+ }
69
+ const GROUND_CELLS = Array.from({ length: MAP_WIDTH * MAP_HEIGHT }, (_, index) => tileAt(index % MAP_WIDTH, Math.floor(index / MAP_WIDTH)));
70
+ export const ISOMETRIC_PREFABS = {
71
+ 'characters/player': {
72
+ waicaPrefab: 1,
73
+ type: 'character',
74
+ components: [
75
+ { type: 'AnimatedSprite', props: ISOMETRIC_HERO_SPRITE },
76
+ { type: 'IsoMotor' },
77
+ {
78
+ type: 'StateMachine',
79
+ props: {
80
+ role: 'player',
81
+ initial: ISO_PLAYER_STATE_GRAPH.initial,
82
+ states: ISO_PLAYER_STATE_GRAPH.states,
83
+ },
84
+ },
85
+ { type: 'Hitbox', props: { width: 0.8, height: 0.8 } },
86
+ { type: 'MeleeAttack' },
87
+ { type: 'Respawnable' },
88
+ { type: 'Health', props: { max: 3, invulnerability: 1, stat: 'health' } },
89
+ ],
90
+ },
91
+ 'characters/villager': {
92
+ waicaPrefab: 1,
93
+ type: 'character',
94
+ components: [
95
+ {
96
+ type: 'AnimatedSprite',
97
+ props: characterSprite('waica:iso-villager', { plain: true }),
98
+ },
99
+ {
100
+ type: 'StateMachine',
101
+ props: {
102
+ role: 'npc',
103
+ initial: NPC_STATE_GRAPH.initial,
104
+ states: NPC_STATE_GRAPH.states,
105
+ },
106
+ },
107
+ { type: 'Interactable', props: { line: 'Welcome to Diamond Meadow!', radius: 1.5 } },
108
+ { type: 'Solid', props: { width: 0.8, height: 0.6 } },
109
+ ],
110
+ },
111
+ 'characters/orc': {
112
+ waicaPrefab: 1,
113
+ type: 'character',
114
+ components: [
115
+ {
116
+ type: 'AnimatedSprite',
117
+ props: {
118
+ ...characterSprite('waica:iso-orc', { attacks: true }),
119
+ // Patrol reports facing, so the orc resolves directional clips
120
+ // from the first frame: it starts down its rail, screen south-east.
121
+ initialClip: 'walk-se',
122
+ },
123
+ },
124
+ { type: 'Patrol', props: { axis: 'horizontal', distance: 2, speed: 2 } },
125
+ {
126
+ type: 'StateMachine',
127
+ props: {
128
+ role: 'patroller',
129
+ initial: PATROLLER_STATE_GRAPH.initial,
130
+ states: PATROLLER_STATE_GRAPH.states,
131
+ },
132
+ },
133
+ { type: 'Hitbox', props: { width: 0.8, height: 0.7 } },
134
+ { type: 'Hazard', props: { stompable: false, contactDamage: 1 } },
135
+ { type: 'Health', props: { max: 2, invulnerability: 0.3 } },
136
+ ],
137
+ },
138
+ 'objects/crate': {
139
+ waicaPrefab: 1,
140
+ type: 'object',
141
+ components: [
142
+ {
143
+ type: 'Sprite',
144
+ props: {
145
+ texture: 'waica:iso-crate',
146
+ pixelArt: true,
147
+ width: 1,
148
+ height: 1,
149
+ anchorY: 0,
150
+ },
151
+ },
152
+ { type: 'Hitbox', props: { width: 0.6, height: 0.6 } },
153
+ { type: 'Collectible', props: { value: 1 } },
154
+ ],
155
+ },
156
+ 'objects/tree': {
157
+ waicaPrefab: 1,
158
+ type: 'object',
159
+ components: [
160
+ {
161
+ type: 'Sprite',
162
+ props: {
163
+ texture: 'waica:iso-tree',
164
+ pixelArt: true,
165
+ width: 2,
166
+ height: 47 / 16,
167
+ anchorY: 0,
168
+ },
169
+ },
170
+ { type: 'Solid', props: { width: 0.8, height: 0.6 } },
171
+ ],
172
+ },
173
+ 'objects/rock': {
174
+ waicaPrefab: 1,
175
+ type: 'object',
176
+ components: [
177
+ {
178
+ type: 'Sprite',
179
+ props: {
180
+ texture: 'waica:iso-rock',
181
+ pixelArt: true,
182
+ width: 1,
183
+ height: 1,
184
+ anchorY: 0,
185
+ },
186
+ },
187
+ { type: 'Solid', props: { width: 0.8, height: 0.6 } },
188
+ ],
189
+ },
190
+ 'tiles/ground': {
191
+ waicaPrefab: 1,
192
+ type: 'tile',
193
+ components: [
194
+ {
195
+ type: 'Tilemap',
196
+ props: {
197
+ texture: 'waica:iso-ground',
198
+ cols: 5,
199
+ rows: 1,
200
+ spacingX: 1,
201
+ spacingY: 1,
202
+ cellWidth: 64,
203
+ cellHeight: 32,
204
+ pixelArt: true,
205
+ mapWidth: MAP_WIDTH,
206
+ mapHeight: MAP_HEIGHT,
207
+ cellSize: 1,
208
+ cells: GROUND_CELLS,
209
+ solidTiles: [WATER, BORDER],
210
+ layer: -2,
211
+ },
212
+ },
213
+ ],
214
+ },
215
+ };
@@ -0,0 +1,3 @@
1
+ import { type EntityTemplate, type SceneRegistry } from '@waica/engine';
2
+ export declare const ISOMETRIC_REGISTRY_DATA: SceneRegistry;
3
+ export declare const ISOMETRIC_PALETTE: EntityTemplate[];
@@ -0,0 +1,47 @@
1
+ import { AnimatedSprite, Hitbox, Solid, Sprite, StateMachine, Tilemap, } from '@waica/engine';
2
+ import { Chaser, Collectible, Hazard, Health, Interactable, IsoMotor, Lifetime, MeleeAttack, Patrol, Respawnable, } from '@waica/behaviors';
3
+ import { ISOMETRIC_ART } from './art.js';
4
+ import { ISOMETRIC_PREFABS } from './prefabs.js';
5
+ import { ISOMETRIC_UI } from './ui.js';
6
+ const PACKAGE_ASSETS = Object.fromEntries(ISOMETRIC_ART.map((art) => [art.uri, `assets/${art.file}`]));
7
+ export const ISOMETRIC_REGISTRY_DATA = {
8
+ components: {
9
+ Sprite,
10
+ AnimatedSprite,
11
+ Tilemap,
12
+ Solid,
13
+ Hitbox,
14
+ StateMachine,
15
+ IsoMotor,
16
+ MeleeAttack,
17
+ Interactable,
18
+ Collectible,
19
+ Patrol,
20
+ Chaser,
21
+ Hazard,
22
+ Health,
23
+ Respawnable,
24
+ Lifetime,
25
+ },
26
+ resolveAsset: (uri) => PACKAGE_ASSETS[uri] ?? uri,
27
+ prefabs: ISOMETRIC_PREFABS,
28
+ ui: ISOMETRIC_UI,
29
+ };
30
+ const PALETTE_ICONS = {
31
+ player: '🧭',
32
+ villager: '🧑‍🌾',
33
+ orc: '👹',
34
+ crate: '📦',
35
+ tree: '🌳',
36
+ rock: '🪨',
37
+ ground: '💎',
38
+ };
39
+ export const ISOMETRIC_PALETTE = Object.entries(ISOMETRIC_PREFABS).map(([key, prefab]) => {
40
+ const base = key.slice(key.indexOf('/') + 1);
41
+ return {
42
+ label: base,
43
+ icon: PALETTE_ICONS[base] ?? '▣',
44
+ category: prefab.type,
45
+ make: () => ({ name: base.charAt(0).toUpperCase() + base.slice(1), prefab: key }),
46
+ };
47
+ });
@@ -0,0 +1,4 @@
1
+ import type { SceneRegistry } from '@waica/engine';
2
+ export { ISOMETRIC_PALETTE } from './registry-data.js';
3
+ export declare const ISOMETRIC_ART_URLS: Record<string, string>;
4
+ export declare const ISOMETRIC_REGISTRY: SceneRegistry;
@@ -0,0 +1,17 @@
1
+ import { ISOMETRIC_ART } from './art.js';
2
+ import { ISOMETRIC_REGISTRY_DATA } from './registry-data.js';
3
+ export { ISOMETRIC_PALETTE } from './registry-data.js';
4
+ export const ISOMETRIC_ART_URLS = {
5
+ 'waica-iso-hero.png': new URL('../assets/waica-iso-hero.png', import.meta.url).href,
6
+ 'waica-iso-villager.png': new URL('../assets/waica-iso-villager.png', import.meta.url).href,
7
+ 'waica-iso-orc.png': new URL('../assets/waica-iso-orc.png', import.meta.url).href,
8
+ 'waica-iso-ground.png': new URL('../assets/waica-iso-ground.png', import.meta.url).href,
9
+ 'waica-iso-tree.png': new URL('../assets/waica-iso-tree.png', import.meta.url).href,
10
+ 'waica-iso-rock.png': new URL('../assets/waica-iso-rock.png', import.meta.url).href,
11
+ 'waica-iso-crate.png': new URL('../assets/waica-iso-crate.png', import.meta.url).href,
12
+ };
13
+ const BUILTIN_ASSETS = Object.fromEntries(ISOMETRIC_ART.map((art) => [art.uri, ISOMETRIC_ART_URLS[art.file] ?? art.uri]));
14
+ export const ISOMETRIC_REGISTRY = {
15
+ ...ISOMETRIC_REGISTRY_DATA,
16
+ resolveAsset: (uri) => BUILTIN_ASSETS[uri] ?? uri,
17
+ };
@@ -0,0 +1,5 @@
1
+ import type { SceneJson } from '@waica/engine';
2
+ /** A logical 16x16 meadow projected into a 2:1 diamond at render time. */
3
+ export declare const ISOMETRIC_SCENE: SceneJson;
4
+ /** Blank projects retain the diamond grid and full-map framing. */
5
+ export declare const ISOMETRIC_BLANK_SCENE: SceneJson;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Full-map framing plus a follow feel tuned for the diamond: a tight dead
3
+ * zone and no horizontal lookahead (the engine's step kicks in every time
4
+ * the player crosses walking speed, which lurches on short runs), a little
5
+ * vertical lead, and softer smoothing than the platformer default.
6
+ */
7
+ function isometricCamera() {
8
+ return {
9
+ position: [0, -8],
10
+ zoom: 12,
11
+ limits: { minX: -16, maxX: 16, minY: -16, maxY: 0 },
12
+ deadzoneWidth: 0.5,
13
+ deadzoneHeight: 0.5,
14
+ lookahead: 0,
15
+ lookaheadY: 0.5,
16
+ smoothing: 4,
17
+ };
18
+ }
19
+ /** A logical 16x16 meadow projected into a 2:1 diamond at render time. */
20
+ export const ISOMETRIC_SCENE = {
21
+ waicaScene: 3,
22
+ render: { sort: 'y', projection: 'isometric' },
23
+ camera: {
24
+ ...isometricCamera(),
25
+ follow: 'Player',
26
+ },
27
+ entities: [
28
+ { name: 'Ground', prefab: 'tiles/ground', position: [0, 0] },
29
+ { name: 'Player', prefab: 'characters/player', position: [8, 8] },
30
+ {
31
+ name: 'Villager',
32
+ prefab: 'characters/villager',
33
+ position: [6, 9],
34
+ overrides: { Interactable: { line: 'The water sparkles, but it blocks the trail.' } },
35
+ },
36
+ {
37
+ name: 'Orc',
38
+ prefab: 'characters/orc',
39
+ position: [10, 10],
40
+ overrides: { Patrol: { axis: 'horizontal', distance: 2.5, speed: 1.5 } },
41
+ },
42
+ { name: 'Crate-1', prefab: 'objects/crate', position: [5, 6] },
43
+ { name: 'Crate-2', prefab: 'objects/crate', position: [10, 4] },
44
+ { name: 'Crate-3', prefab: 'objects/crate', position: [12, 10] },
45
+ { name: 'Tree-1', prefab: 'objects/tree', position: [4, 10] },
46
+ { name: 'Tree-2', prefab: 'objects/tree', position: [10, 12] },
47
+ { name: 'Tree-3', prefab: 'objects/tree', position: [12, 3] },
48
+ { name: 'Rock-1', prefab: 'objects/rock', position: [5, 11] },
49
+ { name: 'Rock-2', prefab: 'objects/rock', position: [9, 4] },
50
+ ],
51
+ ui: ['crate-counter', 'health'],
52
+ };
53
+ /** Blank projects retain the diamond grid and full-map framing. */
54
+ export const ISOMETRIC_BLANK_SCENE = {
55
+ waicaScene: 3,
56
+ render: { sort: 'y', projection: 'isometric' },
57
+ camera: isometricCamera(),
58
+ entities: [],
59
+ };
@@ -0,0 +1 @@
1
+ export declare const ISOMETRIC_UI: Record<string, string>;
@@ -0,0 +1,30 @@
1
+ import { INTERACTABLE_UI } from '@waica/behaviors';
2
+ export const ISOMETRIC_UI = {
3
+ 'crate-counter': `<style>
4
+ .crate-counter {
5
+ position: absolute;
6
+ top: 12px;
7
+ left: 12px;
8
+ font: 600 20px system-ui, sans-serif;
9
+ color: #ffd166;
10
+ text-shadow: 0 1px 3px #000a;
11
+ user-select: none;
12
+ }
13
+ </style>
14
+ <div class="crate-counter">📦 {{points}}</div>
15
+ `,
16
+ health: `<style>
17
+ .health {
18
+ position: absolute;
19
+ top: 12px;
20
+ right: 12px;
21
+ font: 600 20px system-ui, sans-serif;
22
+ color: #ef476f;
23
+ text-shadow: 0 1px 3px #000a;
24
+ user-select: none;
25
+ }
26
+ </style>
27
+ <div class="health">♥ {{health}}</div>
28
+ `,
29
+ ...INTERACTABLE_UI,
30
+ };
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@waica/archetype-isometric",
3
+ "version": "0.9.0",
4
+ "description": "Waica isometric archetype — logical-grid action adventures with screen-relative movement",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/chichex/waica",
10
+ "directory": "packages/archetype-isometric"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "assets"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./manifest": {
22
+ "types": "./dist/manifest.d.ts",
23
+ "default": "./dist/manifest.js"
24
+ }
25
+ },
26
+ "dependencies": {
27
+ "@waica/behaviors": "^0.9.0",
28
+ "@waica/engine": "^0.9.0"
29
+ }
30
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waica/archetype-platformer",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Waica platformer archetype — opinionated setup for side-scrolling platformers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@waica/behaviors": "^0.7.0",
28
- "@waica/engine": "^0.7.0"
27
+ "@waica/behaviors": "^0.9.0",
28
+ "@waica/engine": "^0.9.0"
29
29
  }
30
30
  }
@@ -2,6 +2,7 @@ import type { DirectionalAnimation } from '@waica/engine';
2
2
  /**
3
3
  * The archetype's directional animation contract: four facings with west
4
4
  * mirrored from east art (the stock sheets only draw s/n/e), clips named
5
- * `<state>-<dir>`, and walk falling back to idle when a sheet lacks it.
5
+ * `<state>-<dir>`, and every pose the shared player graph can enter (walk,
6
+ * attack, hurt, death) falling back to idle when a sheet lacks it.
6
7
  */
7
8
  export declare const TOPDOWN_ANIMATION: DirectionalAnimation;
@@ -1,10 +1,14 @@
1
1
  /**
2
2
  * The archetype's directional animation contract: four facings with west
3
3
  * mirrored from east art (the stock sheets only draw s/n/e), clips named
4
- * `<state>-<dir>`, and walk falling back to idle when a sheet lacks it.
4
+ * `<state>-<dir>`, and every pose the shared player graph can enter (walk,
5
+ * attack, hurt, death) falling back to idle when a sheet lacks it.
5
6
  */
6
7
  export const TOPDOWN_ANIMATION = {
7
8
  directions: ['n', 's', 'e', 'w'],
8
9
  fallbacks: { w: { dir: 'e', flip: true } },
9
- contract: { required: ['idle'], fallbacks: { walk: 'idle' } },
10
+ contract: {
11
+ required: ['idle'],
12
+ fallbacks: { walk: 'idle', attack: 'idle', hurt: 'idle', death: 'idle' },
13
+ },
10
14
  };
@@ -1,4 +1,4 @@
1
- import { AnimatedSprite, Hitbox, Solid, Sprite, StateMachine, } from '@waica/engine';
1
+ import { AnimatedSprite, Hitbox, Solid, Sprite, StateMachine, Tilemap, } from '@waica/engine';
2
2
  import { Chaser, Collectible, Hazard, Health, Interactable, Lifetime, Patrol, Respawnable, TopDownMotor, } from '@waica/behaviors';
3
3
  import { TOPDOWN_ART } from './art.js';
4
4
  import { TOPDOWN_PREFABS } from './prefabs.js';
@@ -13,6 +13,7 @@ export const TOPDOWN_REGISTRY_DATA = {
13
13
  components: {
14
14
  Sprite,
15
15
  AnimatedSprite,
16
+ Tilemap,
16
17
  Solid,
17
18
  Hitbox,
18
19
  StateMachine,
@@ -1,3 +1,4 @@
1
+ import { INTERACTABLE_UI } from '@waica/behaviors';
1
2
  /**
2
3
  * The archetype's default UI pieces: self-contained HTML fragments
3
4
  * (markup + <style>, {{stat}} bindings) keyed by piece name. Projects
@@ -21,23 +22,5 @@ export const TOPDOWN_UI = {
21
22
  </style>
22
23
  <div class="potion-counter">🧪 {{points}}</div>
23
24
  `,
24
- 'npc-line': `<style>
25
- .npc-line {
26
- position: absolute;
27
- left: 50%;
28
- bottom: 24px;
29
- transform: translateX(-50%);
30
- max-width: 70%;
31
- padding: 10px 18px;
32
- border-radius: 8px;
33
- background: #1a1a2ecc;
34
- border: 1px solid #ffffff2e;
35
- font: 500 18px system-ui, sans-serif;
36
- color: #f5f5f5;
37
- text-shadow: 0 1px 2px #000a;
38
- user-select: none;
39
- }
40
- </style>
41
- <div class="npc-line">{{npcLine}}</div>
42
- `,
25
+ ...INTERACTABLE_UI,
43
26
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waica/archetype-topdown",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Waica top-down archetype — opinionated setup for Zelda-like overhead adventures",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,7 +24,7 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@waica/behaviors": "^0.7.0",
28
- "@waica/engine": "^0.7.0"
27
+ "@waica/behaviors": "^0.9.0",
28
+ "@waica/engine": "^0.9.0"
29
29
  }
30
30
  }