pi-extensions 0.1.9

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 (135) hide show
  1. package/.ralph/import-cc-codex.md +31 -0
  2. package/.ralph/import-cc-codex.state.json +14 -0
  3. package/.ralph/mario-not-impl.md +69 -0
  4. package/.ralph/mario-not-impl.state.json +14 -0
  5. package/.ralph/mario-not-spec.md +163 -0
  6. package/.ralph/mario-not-spec.state.json +14 -0
  7. package/LICENSE +21 -0
  8. package/README.md +65 -0
  9. package/RELEASING.md +34 -0
  10. package/agent-guidance/CHANGELOG.md +4 -0
  11. package/agent-guidance/README.md +102 -0
  12. package/agent-guidance/agent-guidance.ts +147 -0
  13. package/agent-guidance/package.json +22 -0
  14. package/agent-guidance/setup.sh +75 -0
  15. package/agent-guidance/templates/CLAUDE.md +5 -0
  16. package/agent-guidance/templates/CODEX.md +92 -0
  17. package/agent-guidance/templates/GEMINI.md +5 -0
  18. package/arcade/CHANGELOG.md +4 -0
  19. package/arcade/README.md +85 -0
  20. package/arcade/assets/picman.png +0 -0
  21. package/arcade/assets/ping.png +0 -0
  22. package/arcade/assets/spice-invaders.png +0 -0
  23. package/arcade/assets/tetris.png +0 -0
  24. package/arcade/mario-not/README.md +30 -0
  25. package/arcade/mario-not/boss.js +103 -0
  26. package/arcade/mario-not/camera.js +59 -0
  27. package/arcade/mario-not/collision.js +91 -0
  28. package/arcade/mario-not/colors.js +36 -0
  29. package/arcade/mario-not/constants.js +97 -0
  30. package/arcade/mario-not/core.js +39 -0
  31. package/arcade/mario-not/death.js +77 -0
  32. package/arcade/mario-not/effects.js +84 -0
  33. package/arcade/mario-not/enemies.js +31 -0
  34. package/arcade/mario-not/engine.js +171 -0
  35. package/arcade/mario-not/fireballs.js +98 -0
  36. package/arcade/mario-not/items.js +24 -0
  37. package/arcade/mario-not/levels.js +403 -0
  38. package/arcade/mario-not/logic.js +104 -0
  39. package/arcade/mario-not/mario-not.ts +297 -0
  40. package/arcade/mario-not/player.js +244 -0
  41. package/arcade/mario-not/render.js +257 -0
  42. package/arcade/mario-not/spec.md +548 -0
  43. package/arcade/mario-not/state.js +246 -0
  44. package/arcade/mario-not/tests/e2e.test.js +855 -0
  45. package/arcade/mario-not/tests/engine.test.js +888 -0
  46. package/arcade/mario-not/tests/fixtures/story0-frame.txt +4 -0
  47. package/arcade/mario-not/tests/fixtures/story1-camera.txt +4 -0
  48. package/arcade/mario-not/tests/fixtures/story1-glyphs.txt +4 -0
  49. package/arcade/mario-not/tests/fixtures/story10-item.txt +4 -0
  50. package/arcade/mario-not/tests/fixtures/story11-hazards.txt +4 -0
  51. package/arcade/mario-not/tests/fixtures/story12-used-block.txt +4 -0
  52. package/arcade/mario-not/tests/fixtures/story13-pipes.txt +4 -0
  53. package/arcade/mario-not/tests/fixtures/story14-goal.txt +4 -0
  54. package/arcade/mario-not/tests/fixtures/story15-hud-narrow.txt +2 -0
  55. package/arcade/mario-not/tests/fixtures/story16-unknown-tile.txt +4 -0
  56. package/arcade/mario-not/tests/fixtures/story17-mix.txt +4 -0
  57. package/arcade/mario-not/tests/fixtures/story18-hud-score.txt +2 -0
  58. package/arcade/mario-not/tests/fixtures/story19-cue.txt +4 -0
  59. package/arcade/mario-not/tests/fixtures/story2-enemy.txt +4 -0
  60. package/arcade/mario-not/tests/fixtures/story20-camera-offset.txt +4 -0
  61. package/arcade/mario-not/tests/fixtures/story21-hud-zero.txt +2 -0
  62. package/arcade/mario-not/tests/fixtures/story22-big-viewport.txt +4 -0
  63. package/arcade/mario-not/tests/fixtures/story23-camera-negative.txt +4 -0
  64. package/arcade/mario-not/tests/fixtures/story24-camera-width.txt +4 -0
  65. package/arcade/mario-not/tests/fixtures/story25-camera-positive.txt +4 -0
  66. package/arcade/mario-not/tests/fixtures/story26-hud-lives.txt +2 -0
  67. package/arcade/mario-not/tests/fixtures/story27-hud-coins.txt +2 -0
  68. package/arcade/mario-not/tests/fixtures/story28-item-viewport.txt +4 -0
  69. package/arcade/mario-not/tests/fixtures/story29-enemy-viewport.txt +4 -0
  70. package/arcade/mario-not/tests/fixtures/story3-hud.txt +2 -0
  71. package/arcade/mario-not/tests/fixtures/story30-hud-score.txt +2 -0
  72. package/arcade/mario-not/tests/fixtures/story31-particles-viewport.txt +4 -0
  73. package/arcade/mario-not/tests/fixtures/story32-paused-frame.txt +4 -0
  74. package/arcade/mario-not/tests/fixtures/story4-big.txt +4 -0
  75. package/arcade/mario-not/tests/fixtures/story5-resume-hud.txt +2 -0
  76. package/arcade/mario-not/tests/fixtures/story6-particles.txt +4 -0
  77. package/arcade/mario-not/tests/fixtures/story6-paused.txt +4 -0
  78. package/arcade/mario-not/tests/fixtures/story7-powerup.txt +4 -0
  79. package/arcade/mario-not/tests/fixtures/story8-hud-time.txt +2 -0
  80. package/arcade/mario-not/tests/fixtures/story9-hud-level.txt +2 -0
  81. package/arcade/mario-not/tiles.js +79 -0
  82. package/arcade/mario-not/tsconfig.json +14 -0
  83. package/arcade/mario-not/types.js +225 -0
  84. package/arcade/package.json +26 -0
  85. package/arcade/picman.ts +328 -0
  86. package/arcade/ping.ts +594 -0
  87. package/arcade/spice-invaders.ts +1104 -0
  88. package/arcade/tetris.ts +662 -0
  89. package/code-actions/CHANGELOG.md +4 -0
  90. package/code-actions/README.md +65 -0
  91. package/code-actions/actions.ts +107 -0
  92. package/code-actions/index.ts +148 -0
  93. package/code-actions/package.json +22 -0
  94. package/code-actions/search.ts +79 -0
  95. package/code-actions/snippets.ts +179 -0
  96. package/code-actions/ui.ts +120 -0
  97. package/files-widget/CHANGELOG.md +90 -0
  98. package/files-widget/DESIGN.md +452 -0
  99. package/files-widget/README.md +122 -0
  100. package/files-widget/TODO.md +141 -0
  101. package/files-widget/browser.ts +922 -0
  102. package/files-widget/comment.ts +5 -0
  103. package/files-widget/constants.ts +18 -0
  104. package/files-widget/demo.svg +1 -0
  105. package/files-widget/file-tree.ts +224 -0
  106. package/files-widget/file-viewer.ts +93 -0
  107. package/files-widget/git.ts +107 -0
  108. package/files-widget/index.ts +140 -0
  109. package/files-widget/input-utils.ts +3 -0
  110. package/files-widget/package.json +22 -0
  111. package/files-widget/types.ts +28 -0
  112. package/files-widget/utils.ts +26 -0
  113. package/files-widget/viewer.ts +424 -0
  114. package/import-cc-codex/research/import-chats-from-other-agents.md +135 -0
  115. package/import-cc-codex/spec.md +79 -0
  116. package/package.json +29 -0
  117. package/ralph-wiggum/CHANGELOG.md +7 -0
  118. package/ralph-wiggum/README.md +96 -0
  119. package/ralph-wiggum/SKILL.md +73 -0
  120. package/ralph-wiggum/index.ts +792 -0
  121. package/ralph-wiggum/package.json +25 -0
  122. package/raw-paste/CHANGELOG.md +7 -0
  123. package/raw-paste/README.md +52 -0
  124. package/raw-paste/index.ts +112 -0
  125. package/raw-paste/package.json +22 -0
  126. package/tab-status/CHANGELOG.md +4 -0
  127. package/tab-status/README.md +61 -0
  128. package/tab-status/assets/tab-status.png +0 -0
  129. package/tab-status/package.json +22 -0
  130. package/tab-status/tab-status.ts +179 -0
  131. package/usage-extension/CHANGELOG.md +17 -0
  132. package/usage-extension/README.md +120 -0
  133. package/usage-extension/index.ts +628 -0
  134. package/usage-extension/package.json +22 -0
  135. package/usage-extension/screenshot.png +0 -0
@@ -0,0 +1,246 @@
1
+ // @ts-check
2
+ "use strict";
3
+
4
+ const { createRng, makeLevel } = require("./core.js");
5
+ const { DEFAULT_CONFIG, START_LIVES, START_TIME, GAME_MODES } = require("./constants.js");
6
+ const { isSolidAt } = require("./tiles.js");
7
+
8
+ /** @typedef {import("./types").GameState} GameState */
9
+ /** @typedef {import("./types").SaveState} SaveState */
10
+ /** @typedef {import("./types").SnapshotState} SnapshotState */
11
+
12
+ /** @param {GameState} state @returns {SaveState} */
13
+ function saveState(state) {
14
+ return {
15
+ version: 1,
16
+ level: {
17
+ lines: state.level.tiles.map((row) => row.join("")),
18
+ },
19
+ player: {
20
+ x: round(state.player.x),
21
+ y: round(state.player.y),
22
+ vx: round(state.player.vx),
23
+ vy: round(state.player.vy),
24
+ facing: state.player.facing,
25
+ size: state.player.size,
26
+ invuln: round(state.player.invuln),
27
+ },
28
+ enemies: state.enemies.map((enemy) => ({
29
+ x: round(enemy.x),
30
+ y: round(enemy.y),
31
+ vx: round(enemy.vx),
32
+ vy: round(enemy.vy),
33
+ alive: enemy.alive,
34
+ })),
35
+ items: state.items.map((item) => ({
36
+ x: round(item.x),
37
+ y: round(item.y),
38
+ vx: round(item.vx),
39
+ vy: round(item.vy),
40
+ alive: item.alive,
41
+ })),
42
+ fireballs: state.fireballs.map((fb) => ({
43
+ x: round(fb.x),
44
+ y: round(fb.y),
45
+ vx: round(fb.vx),
46
+ vy: round(fb.vy),
47
+ alive: fb.alive,
48
+ pattern: fb.pattern,
49
+ startY: round(fb.startY),
50
+ })),
51
+ fireballSpawners: state.fireballSpawners.map((sp) => ({
52
+ x: sp.x,
53
+ y: sp.y,
54
+ timer: round(sp.timer),
55
+ interval: sp.interval,
56
+ direction: sp.direction,
57
+ })),
58
+ boss: state.boss ? {
59
+ x: round(state.boss.x),
60
+ y: round(state.boss.y),
61
+ vx: round(state.boss.vx),
62
+ vy: round(state.boss.vy),
63
+ alive: state.boss.alive,
64
+ health: state.boss.health,
65
+ maxHealth: state.boss.maxHealth,
66
+ invuln: round(state.boss.invuln),
67
+ onGround: state.boss.onGround,
68
+ } : null,
69
+ score: state.score,
70
+ coins: state.coins,
71
+ lives: state.lives,
72
+ time: round(state.time),
73
+ levelIndex: state.levelIndex,
74
+ mushroomSpawned: state.mushroomSpawned,
75
+ spawnX: round(state.spawnX),
76
+ spawnY: round(state.spawnY),
77
+ mode: state.mode,
78
+ };
79
+ }
80
+
81
+ /**
82
+ * @param {SaveState} save
83
+ * @param {{ config?: Partial<import("./types").Config> }} [options]
84
+ * @returns {GameState | null}
85
+ */
86
+ function loadState(save, options) {
87
+ if (!save || save.version !== 1 || !save.level || !Array.isArray(save.level.lines)) {
88
+ return null;
89
+ }
90
+ const config = { ...DEFAULT_CONFIG, ...(options && options.config ? options.config : {}) };
91
+ const level = makeLevel(save.level.lines);
92
+ const spawnX = typeof save.spawnX === "number" ? save.spawnX : save.player.x;
93
+ const spawnY = typeof save.spawnY === "number" ? save.spawnY : save.player.y;
94
+ const mode = normalizeMode(save);
95
+ /** @type {GameState} */
96
+ const state = {
97
+ level,
98
+ rng: createRng(1),
99
+ config,
100
+ tick: 0,
101
+ score: save.score || 0,
102
+ coins: save.coins || 0,
103
+ lives: save.lives || START_LIVES,
104
+ time: typeof save.time === "number" ? save.time : START_TIME,
105
+ levelIndex: save.levelIndex || 1,
106
+ mushroomSpawned: !!save.mushroomSpawned,
107
+ mode,
108
+ cameraX: 0,
109
+ particles: [],
110
+ cue: null,
111
+ spawnX,
112
+ spawnY,
113
+ deathTimer: 0,
114
+ deathJumped: false,
115
+ player: {
116
+ x: save.player.x,
117
+ y: save.player.y,
118
+ vx: save.player.vx,
119
+ vy: save.player.vy,
120
+ facing: save.player.facing,
121
+ onGround: false,
122
+ size: save.player.size,
123
+ invuln: save.player.invuln,
124
+ },
125
+ enemies: save.enemies.map((enemy) => ({
126
+ x: enemy.x,
127
+ y: enemy.y,
128
+ vx: enemy.vx,
129
+ vy: enemy.vy,
130
+ alive: enemy.alive,
131
+ onGround: false,
132
+ })),
133
+ items: save.items.map((item) => ({
134
+ x: item.x,
135
+ y: item.y,
136
+ vx: item.vx,
137
+ vy: item.vy,
138
+ alive: item.alive,
139
+ onGround: false,
140
+ })),
141
+ fireballs: (save.fireballs || []).map((fb) => ({
142
+ x: fb.x,
143
+ y: fb.y,
144
+ vx: fb.vx,
145
+ vy: fb.vy,
146
+ alive: fb.alive,
147
+ pattern: fb.pattern,
148
+ startY: fb.startY,
149
+ })),
150
+ fireballSpawners: (save.fireballSpawners || []).map((sp) => ({
151
+ x: sp.x,
152
+ y: sp.y,
153
+ timer: sp.timer,
154
+ interval: sp.interval,
155
+ direction: sp.direction,
156
+ })),
157
+ boss: save.boss ? {
158
+ x: save.boss.x,
159
+ y: save.boss.y,
160
+ vx: save.boss.vx,
161
+ vy: save.boss.vy,
162
+ alive: save.boss.alive,
163
+ health: save.boss.health,
164
+ maxHealth: save.boss.maxHealth,
165
+ invuln: save.boss.invuln,
166
+ onGround: save.boss.onGround,
167
+ } : null,
168
+ };
169
+ state.player.onGround = isSolidAt(level, state.player.x, state.player.y + 1);
170
+ if (state.mode === GAME_MODES.gameOver) {
171
+ state.cue = { text: "GAME OVER", ttl: 0, persist: true };
172
+ } else if (state.mode === GAME_MODES.paused) {
173
+ state.cue = { text: "PAUSED", ttl: 0, persist: true };
174
+ } else if (state.mode === GAME_MODES.levelClear) {
175
+ state.cue = { text: "LEVEL CLEAR", ttl: 0, persist: true };
176
+ }
177
+ for (const enemy of state.enemies) {
178
+ enemy.onGround = isSolidAt(level, enemy.x, enemy.y + 1);
179
+ }
180
+ for (const item of state.items) {
181
+ item.onGround = isSolidAt(level, item.x, item.y + 1);
182
+ }
183
+ return state;
184
+ }
185
+
186
+ /** @param {GameState} state @returns {SnapshotState} */
187
+ function snapshotState(state) {
188
+ return {
189
+ tick: state.tick,
190
+ score: state.score,
191
+ coins: state.coins,
192
+ lives: state.lives,
193
+ time: round(state.time),
194
+ levelIndex: state.levelIndex,
195
+ mushroomSpawned: state.mushroomSpawned,
196
+ mode: state.mode,
197
+ player: {
198
+ x: round(state.player.x),
199
+ y: round(state.player.y),
200
+ vx: round(state.player.vx),
201
+ vy: round(state.player.vy),
202
+ onGround: state.player.onGround,
203
+ facing: state.player.facing,
204
+ size: state.player.size,
205
+ invuln: round(state.player.invuln),
206
+ },
207
+ enemies: state.enemies.map((enemy) => ({
208
+ x: round(enemy.x),
209
+ y: round(enemy.y),
210
+ vx: round(enemy.vx),
211
+ vy: round(enemy.vy),
212
+ alive: enemy.alive,
213
+ })),
214
+ items: state.items.map((item) => ({
215
+ x: round(item.x),
216
+ y: round(item.y),
217
+ vx: round(item.vx),
218
+ vy: round(item.vy),
219
+ alive: item.alive,
220
+ onGround: item.onGround,
221
+ })),
222
+ };
223
+ }
224
+
225
+ /** @param {SaveState} save @returns {"playing" | "paused" | "dead" | "level_clear" | "game_over" | "level_intro"} */
226
+ function normalizeMode(save) {
227
+ const mode = save.mode;
228
+ if (mode === GAME_MODES.playing || mode === GAME_MODES.paused || mode === GAME_MODES.dead || mode === GAME_MODES.levelClear || mode === GAME_MODES.gameOver || mode === GAME_MODES.levelIntro) {
229
+ return mode;
230
+ }
231
+ if (save.gameOver) return GAME_MODES.gameOver;
232
+ if (save.paused) return GAME_MODES.paused;
233
+ if (save.player && save.player.dead) return GAME_MODES.dead;
234
+ return GAME_MODES.playing;
235
+ }
236
+
237
+ /** @param {number} value @returns {number} */
238
+ function round(value) {
239
+ return Math.round(value * 1000) / 1000;
240
+ }
241
+
242
+ module.exports = {
243
+ saveState,
244
+ loadState,
245
+ snapshotState,
246
+ };