Add Mario 1-1 classic remake experience - #23
naoto714714 wants to merge 1 commit into
Conversation
WalkthroughルートディレクトリのREADME.mdとindex.htmlに新しいゲームカードエントリを追加し、新しく Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (4)
super-mario-bros-1-1-classic/main.js (3)
24-44: アセットのホスティングについて検討してください。imgurからのアセット読み込みは動作しますが、imgurはゲームアセットのホスティングを想定していないため、リンク切れやレート制限のリスクがあります。長期的な安定性のために、リポジトリ内にアセットを配置するか、専用のCDNを使用することを検討してください。
46-48: DOM要素取得時のnullチェックを検討してください。
getElementByIdは要素が見つからない場合にnullを返します。updateScoreDisplay()でこれらの要素にアクセスする前に、存在確認を行うとより堅牢になります。const scoreLabel = document.getElementById('score'); const coinLabel = document.getElementById('coins'); const timeLabel = document.getElementById('time'); + +if (!scoreLabel || !coinLabel || !timeLabel) { + console.warn('HUD elements not found'); +}
425-431: ゲームオーバー時のlocation.reload()について。
location.reload()でページ全体をリロードするのは機能しますが、Kaboom.jsのシーン機能を使用してゲーム状態をリセットする方が、よりスムーズなユーザー体験を提供できます。現状でも動作するため、将来の改善として検討してください。super-mario-bros-1-1-classic/index.html (1)
33-34: キャンバスアクセシビリティの改善を検討してください。
<canvas>要素にはスクリーンリーダーユーザーへのフォールバックテキストがありません。JavaScriptが無効な場合やKaboom.jsの読み込みに失敗した場合に備えて、フォールバック内容を追加することをお勧めします。- <canvas id="game"></canvas> + <canvas id="game"> + お使いのブラウザはcanvas要素に対応していません。最新のブラウザでお試しください。 + </canvas>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
README.md(1 hunks)index.html(1 hunks)super-mario-bros-1-1-classic/README.md(1 hunks)super-mario-bros-1-1-classic/index.html(1 hunks)super-mario-bros-1-1-classic/main.js(1 hunks)super-mario-bros-1-1-classic/style.css(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
*/index.html
📄 CodeRabbit inference engine (.cursor/rules/about-this-project.mdc)
*/index.html: 動的コードが必要な場合も、入口は index.html に集約 (モジュール分割は js/ 内)
外部ライブラリは CDN 参照を推奨 (ローカル配置も可)
index.html にゲームロジックを実装 (必要に応じて js/・css/ を参照)各ゲームは
index.htmlから開始する(エントリーポイント)
Files:
super-mario-bros-1-1-classic/index.html
**/*.html
📄 CodeRabbit inference engine (CLAUDE.md)
外部ライブラリはCDN参照を推奨する
Files:
super-mario-bros-1-1-classic/index.htmlindex.html
README*
📄 CodeRabbit inference engine (.cursor/rules/coding-rule.mdc)
README に成果物の概要を記載
Files:
README.md
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: naoto714714/browser-games PR: 0
File: .cursor/rules/about-this-project.mdc:0-0
Timestamp: 2025-07-20T03:15:07.280Z
Learning: 新規ゲーム追加時は <ゲーム名>/ ディレクトリを作成し、index.html とREADME.mdを配置
Learnt from: CR
Repo: naoto714714/browser-games PR: 0
File: .cursor/rules/about-this-project.mdc:0-0
Timestamp: 2025-07-20T03:15:07.280Z
Learning: Applies to */index.html : index.html にゲームロジックを実装 (必要に応じて js/・css/ を参照)
Learnt from: CR
Repo: naoto714714/browser-games PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-27T03:49:03.596Z
Learning: Applies to */index.html : 各ゲームは `index.html` から開始する(エントリーポイント)
📚 Learning: 2025-07-20T03:15:07.280Z
Learnt from: CR
Repo: naoto714714/browser-games PR: 0
File: .cursor/rules/about-this-project.mdc:0-0
Timestamp: 2025-07-20T03:15:07.280Z
Learning: Applies to */index.html : index.html にゲームロジックを実装 (必要に応じて js/・css/ を参照)
Applied to files:
super-mario-bros-1-1-classic/README.mdsuper-mario-bros-1-1-classic/index.htmlsuper-mario-bros-1-1-classic/style.css
📚 Learning: 2025-07-27T03:49:03.596Z
Learnt from: CR
Repo: naoto714714/browser-games PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-07-27T03:49:03.596Z
Learning: Applies to */index.html : 各ゲームは `index.html` から開始する(エントリーポイント)
Applied to files:
super-mario-bros-1-1-classic/index.htmlsuper-mario-bros-1-1-classic/style.css
📚 Learning: 2025-07-20T03:15:07.280Z
Learnt from: CR
Repo: naoto714714/browser-games PR: 0
File: .cursor/rules/about-this-project.mdc:0-0
Timestamp: 2025-07-20T03:15:07.280Z
Learning: 新規ゲーム追加時は <ゲーム名>/ ディレクトリを作成し、index.html とREADME.mdを配置
Applied to files:
super-mario-bros-1-1-classic/index.html
🔇 Additional comments (10)
index.html (1)
97-102: LGTM!既存のゲームカードと一貫したフォーマットで、新しいゲームエントリが正しく追加されています。リンクパスも適切です。
README.md (1)
7-9: LGTM!コーディングガイドラインに従い、新しいゲームの概要が適切に記載されています。既存のエントリと一貫したフォーマットです。
super-mario-bros-1-1-classic/README.md (1)
1-12: LGTM!学習データに基づき、新規ゲームディレクトリに適切なREADME.mdが配置されています。操作方法と開発メモが明確に記載されており、メンテナンス性が高いです。
super-mario-bros-1-1-classic/style.css (1)
64-74: LGTM!HUDのグリッドレイアウトは適切に実装されており、レスポンシブ対応も考慮されています。
super-mario-bros-1-1-classic/main.js (2)
254-262: プレイヤーの衝突エリア設定を確認してください。
k.area({ shape: new k.Rect(k.vec2(0, 2), 12, 14) })の構文がKaboom.jsのバージョンによって異なる可能性があります。また、Line 259のk.origin('bot')は新しいバージョンではk.anchor('bot')に変更されています。
1-8: Kaboom.js初期化は適切です。
global: falseを設定することで名前空間の汚染を防いでおり、良い実践です。キャンバス要素の指定も正しく行われています。super-mario-bros-1-1-classic/index.html (4)
7-9: フォント読み込み最適化を検討してください。Google Fonts のプリコネクト設定は良好ですが、
font-display: swapパラメータが既に URL に含まれており、フォント読み込み中のテキスト表示が最適化されています。現在の実装は良好ですが、今後のメンテナンス時にfont-displayプロパティの確認をお勧めします。
13-30: HUD デザイン構造は適切です。スコア、コイン、ワールド、時間の表示が classic Mario スタイルで実装されており、Japanese UI(MARIO、COIN、WORLD、TIME)のラベルが適切に配置されています。動的コンテンツ用の ID 属性(score、coins、time)も正しく設定されており、JavaScript から更新可能な構造になっています。
1-46: 全体的な HTML 構造は適切で、エントリーポイントとしての要件を満たしています。
- DOCTYPE、言語属性(lang="ja")、メタタグの設定が正しい
- スクリプトはボディ末尾に配置されており、DOM 解析後に実行される良好なプラクティス
- 外部 CDN(Kaboom.js)と本地モジュール(main.js)の読み込み順序が適切
- 学習内容に基づいて、index.html がゲームのエントリーポイントとして機能する設計
学習内容に基づく確認: 新規ゲーム追加時の
<ゲーム名>/ディレクトリ構造、index.html とREADME.md 配置の要件を満たしています。
10-10: style.css と main.js は正常に存在し、正しく読み込まれています。
- style.css: ✓ 存在確認
- main.js: ✓ 存在確認、type="module" で正しく読み込まれている
- Kaboom.js: ✓ CDN から正常に読み込まれた後、main.js が読み込まれている
- main.js の初期化: ✓ const k = kaboom({...}) で適切に初期化され、グローバル変数を使用せずにモジュールスコープ内で Kaboom へアクセスしている
| </section> | ||
| </main> | ||
|
|
||
| <script src="https://unpkg.com/kaboom@3001.0.0-beta.3/dist/kaboom.js"></script> |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Kaboom.js latest stable version 2024 2025
💡 Result:
As of Nov 30, 2025: Kaboom.js is archived/unmaintained. The latest published (stable) npm release is 3000.1.17; the original GitHub repo was archived on Nov 12, 2024. [1][2]
Sources:
- GitHub repo (archived Nov 12, 2024). [1]
- npm package page (latest published version 3000.1.17). [2]
🏁 Script executed:
# Check if main.js and style.css exist in the project directory
fd -t f "main\.js|style\.css" super-mario-bros-1-1-classic/Repository: naoto714714/browser-games
Length of output: 144
🏁 Script executed:
# Check the project directory structure
ls -la super-mario-bros-1-1-classic/ | head -20Repository: naoto714714/browser-games
Length of output: 427
Use the latest stable version of Kaboom.js instead of the beta version.
The current code loads Kaboom.js version 3001.0.0-beta.3, but Kaboom.js is archived and no longer maintained (archived Nov 12, 2024). The latest published stable version is 3000.1.17. Beta versions of unmaintained libraries pose significant long-term maintenance and stability risks. Update line 43 to: <script src="https://unpkg.com/kaboom@3000.1.17/dist/kaboom.js"></script>
🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/index.html around line 43, the page is loading a
beta, archived Kaboom.js release (3001.0.0-beta.3); update the script tag to
reference the latest stable published version by replacing the beta URL with the
stable CDN URL (use https://unpkg.com/kaboom@3000.1.17/dist/kaboom.js) so the
app uses the maintained stable release.
| function patrol(speed = 30, dir = -1) { | ||
| return { | ||
| id: 'patrol', | ||
| require: ['pos', 'area'], | ||
| add() { | ||
| this.on('collider', (other) => { | ||
| if (other.is('solid') && !other.is('player')) { | ||
| dir = -dir; | ||
| } | ||
| }); | ||
| }, | ||
| update() { | ||
| this.move(speed * dir, 0); | ||
| }, | ||
| }; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Kaboom.js collision event API documentation collide collider
💡 Result:
Summary of Kaboom.js collision API (key functions/components)
- area() — add collider to an object (enables collisions; accepts options like shape, scale, offset). [1]
- onCollide(t1, t2, fn) / onCollide(tag, fn) / obj.onCollide(tag, fn) — register a callback when two tagged objects collide (single-frame trigger or per-object variants). [1]
- onCollideUpdate(t1, t2, fn) / onCollideUpdate(...) — run every frame while the two objects are colliding. [1]
- onCollideEnd(t1, t2, fn) / onCollideEnd(...) — run once when collision ends. [1]
- isColliding(obj) / isOverlapping(obj) / getCollisions() / checkCollision(other) — query current collisions. [1]
- resolveCollision(obj) — push objects apart to resolve overlap; physics/body options available (BodyComp: isStatic, mass, etc.). [1]
- onBeforePhysicsResolve(col) / onPhysicsResolve(col) — hooks called before/when a physics collision is resolved. [1]
- area comps expose localArea(), worldArea(), screenArea(), collisionIgnore, and other helpers for advanced checks. [1]
Examples:
- Add area and listen for collision:
const p = add([ sprite("bean"), area(), "player" ]);
p.onCollide("tree", (t, col) => destroy(p));
(See docs for full signatures.) [1][2]
Sources:
[1] Kaboom.js API docs — area, onCollide, collision helpers. (kaboomjs.com).
[2] Kaboom/Kaplay guides — usage examples for onCollide and area().
🏁 Script executed:
# Check the structure and imports in main.js
head -100 super-mario-bros-1-1-classic/main.js | cat -nRepository: naoto714714/browser-games
Length of output: 3130
🏁 Script executed:
# Look for package.json or version info
find super-mario-bros-1-1-classic -name "package.json" -o -name "*.html" | head -20Repository: naoto714714/browser-games
Length of output: 108
🏁 Script executed:
# Check the HTML file for Kaboom.js version info
cat super-mario-bros-1-1-classic/index.htmlRepository: naoto714714/browser-games
Length of output: 1491
🌐 Web query:
Kaboom.js 3001.0.0-beta component this.on collider event
💡 Result:
Short answer: use the area() component and inside your component's add() handler call this.on("collide", ...) (or this.on("collideUpdate"/"collideEnd") for continuous/end events). The callback gets (otherObj, collision) and runs on the host object when a collision happens.
Example (v3000+/3001 style):
function myComp() {
return {
require: ["area"], // ensure area() exists
add() {
this.on("collide", (other, col) => {
// `this` = host obj, `other` = collided obj, `col` = Collision info
if (other.is("enemy")) {
this.trigger("hit-by-enemy", other, col)
}
})
}
}
}
Or register by tag globally:
onCollide("player", "enemy", (p, e, col) => { /* ... */ })
Notes:
- area() (or area component) is required for collision events. [1]
- Event names available on GameObj: "collide", "collideUpdate", "collideEnd" and signatures are (other: GameObj, col?: Collision). [1][2]
Sources:
- Kaboom.js API (area, onCollide, game object events). [1]
- Kaplay / GameObj event map showing "collide"/"collideUpdate"/"collideEnd" on objects. [2]
Change 'collider' to 'collide'
The collision event in Kaboom.js 3001.0.0-beta.3 is "collide", not "collider". Update line 94 to:
this.on('collide', (other) => {The available collision events are "collide", "collideUpdate", and "collideEnd".
🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/main.js around lines 89 to 104, the event name
used in the patrol component is incorrect — it's registering 'collider' instead
of Kaboom's correct 'collide' event; change the this.on call to listen for
'collide' (i.e., replace the 'collider' string with 'collide') so the collision
handler fires correctly, leaving the rest of the handler and logic unchanged.
| '=': () => [k.sprite('block'), k.area(), k.solid(), 'solid', 'brick'], | ||
| 'Q': () => [k.sprite('surprise'), k.area(), k.solid(), 'solid', 'question', { content: 'coin' }], | ||
| 'M': () => [k.sprite('surprise'), k.area(), k.solid(), 'solid', 'question', { content: 'mushroom' }], | ||
| 'c': () => [k.sprite('coin'), k.area({ scale: 0.8 }), 'coin', { floating: true }], | ||
| 'g': () => [k.sprite('goomba'), k.area(), k.body(), patrol(ENEMY_SPEED), k.origin('bot'), 'danger'], | ||
| 'k': () => [k.sprite('goomba'), k.area(), k.body(), patrol(ENEMY_SPEED), k.origin('bot'), 'danger'], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "index.html" | head -5Repository: naoto714714/browser-games
Length of output: 215
🏁 Script executed:
find . -path "*/super-mario-bros-1-1-classic/index.html"Repository: naoto714714/browser-games
Length of output: 110
🏁 Script executed:
cat -n ./super-mario-bros-1-1-classic/index.html | grep -i kaboomRepository: naoto714714/browser-games
Length of output: 157
🌐 Web query:
Kaboom.js 3001.0.0-beta.3 k.solid() k.origin() API documentation
💡 Result:
Short answer — in v3000+ (including 3001.0.0-beta.3):
- k.solid() was removed. Use body({ isStatic: true }) (with area() and pos() as appropriate) to create a static/solid object. [1][2]
- k.origin() was renamed to anchor(). Use anchor("center") or anchor(vec2) for the same anchor/origin behavior; for text alignment use the text option align instead. [1][2][3]
References:
- Kaboom API (v3000+): anchor / BodyCompOpt (isStatic). [1]
- Changelog / breaking changes (removal of solid(), rename origin→anchor). [2]
- StackOverflow example showing origin → anchor replacement. [3]
If you want, I can show small code examples converting origin()/solid() to anchor()/body({isStatic:true}).
🏁 Script executed:
sed -n '209,214p' ./super-mario-bros-1-1-classic/main.js | cat -nRepository: naoto714714/browser-games
Length of output: 690
Kaboom.js API compatibility issue: k.solid() and k.origin() are removed in v3000+
Your project uses Kaboom.js v3001.0.0-beta.3, where both methods have been removed:
k.solid()→ Replace withk.body({ isStatic: true })k.origin('bot')→ Replace withk.anchor('bot')
The code at lines 209-214 uses both methods and will fail at runtime. Update the entity definitions accordingly.
🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/main.js around lines 209 to 214, the entity
definitions use deprecated Kaboom.js APIs k.solid() and k.origin('bot'); replace
k.solid() with k.body({ isStatic: true }) for static colliders (e.g., blocks and
surprise blocks) and replace k.origin('bot') with k.anchor('bot') for setting
the anchor on enemies; update those factory entries accordingly so blocks use
k.body({ isStatic: true }) instead of k.solid(), and enemies use k.anchor('bot')
instead of k.origin('bot').
| function spawnMushroom(pos) { | ||
| const mush = level.spawn('mushroom', pos); | ||
| mush.use(k.body()); | ||
| mush.use(patrol(MUSHROOM_SPEED)); | ||
| mush.use(k.origin('bot')); | ||
| mush.isMushroom = true; | ||
| } |
There was a problem hiding this comment.
level.spawn() メソッドの存在を確認してください。
level.spawn() はKaboom.jsの標準APIではない可能性があります。レベルにオブジェクトを追加する場合は k.add() を使用するのが一般的です。
function spawnMushroom(pos) {
- const mush = level.spawn('mushroom', pos);
- mush.use(k.body());
- mush.use(patrol(MUSHROOM_SPEED));
- mush.use(k.origin('bot'));
- mush.isMushroom = true;
+ const mush = k.add([
+ k.sprite('mushroom'),
+ k.pos(pos),
+ k.area(),
+ k.body(),
+ k.anchor('bot'),
+ patrol(MUSHROOM_SPEED),
+ 'mushroom',
+ ]);
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/main.js around lines 320 to 326, the code calls
level.spawn(...) which is not a standard Kaboom API; replace it with k.add(...)
to add the mushroom to the scene: call k.add with an object that sets the pos
property to pos, the name/tag to 'mushroom' (or use the id field), and include
the same components (k.body(), patrol(MUSHROOM_SPEED), k.origin('bot')), then
set mush.isMushroom = true on the returned game object; if your project defines
a custom level.spawn helper, either confirm and import it or convert callers to
k.add as described.
| function spawnCoin(pos) { | ||
| const coin = level.spawn('coin', pos); | ||
| coin.use(k.origin('bot')); | ||
| coin.use({ floating: false }); | ||
| coin.jump(180); | ||
| k.wait(0.4, () => coin.destroy()); | ||
| collectCoin(); | ||
| } |
There was a problem hiding this comment.
同様に level.spawn() と coin.jump() を確認してください。
spawnCoin も level.spawn() を使用しており、さらに coin.jump() を呼び出していますが、生成されたコインに body コンポーネントがない場合は jump() メソッドが存在しません。
function spawnCoin(pos) {
- const coin = level.spawn('coin', pos);
- coin.use(k.origin('bot'));
- coin.use({ floating: false });
- coin.jump(180);
- k.wait(0.4, () => coin.destroy());
+ const coin = k.add([
+ k.sprite('coin'),
+ k.pos(pos),
+ k.area({ scale: 0.8 }),
+ k.body(),
+ k.anchor('bot'),
+ 'coin',
+ ]);
+ coin.jump(180);
+ k.wait(0.4, () => k.destroy(coin));
collectCoin();
}🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/main.js around lines 342-349, spawnCoin calls
level.spawn(...) and then coin.jump(...) without guarding against level.spawn
returning null/undefined or the spawned coin lacking a body component (so jump
may not exist). Update spawnCoin to (1) check the result of level.spawn and bail
out if falsy, (2) ensure the spawned coin has a body component before calling
coin.jump (either add the body component when spawning or conditionally call
jump only when coin.body or typeof coin.jump === 'function'), and (3) guard
coin.destroy and collectCoin calls so they run only when coin was successfully
created.
| function hitPlayer() { | ||
| if (finished) return; | ||
| if (player.isBig()) { | ||
| player.smallify(); | ||
| k.play('powerdown', { volume: 0.2, detune: -1200 }); | ||
| } else { | ||
| gameOver(); | ||
| } | ||
| } |
There was a problem hiding this comment.
未読み込みのサウンド 'powerdown' を再生しようとしています。
k.play('powerdown', ...) を呼び出していますが、このサウンドは k.loadSound() で読み込まれていません。これによりランタイムエラーが発生する可能性があります。
サウンドを削除するか、適切に読み込んでください:
function hitPlayer() {
if (finished) return;
if (player.isBig()) {
player.smallify();
- k.play('powerdown', { volume: 0.2, detune: -1200 });
+ // サウンドを使用する場合は先にloadSoundで読み込む必要があります
} else {
gameOver();
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function hitPlayer() { | |
| if (finished) return; | |
| if (player.isBig()) { | |
| player.smallify(); | |
| k.play('powerdown', { volume: 0.2, detune: -1200 }); | |
| } else { | |
| gameOver(); | |
| } | |
| } | |
| function hitPlayer() { | |
| if (finished) return; | |
| if (player.isBig()) { | |
| player.smallify(); | |
| // サウンドを使用する場合は先にloadSoundで読み込む必要があります | |
| } else { | |
| gameOver(); | |
| } | |
| } |
🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/main.js around lines 359 to 367, the handler
calls k.play('powerdown', ...) but the 'powerdown' sound is never loaded,
causing a runtime error; fix by either removing the k.play call or, preferably,
add a k.loadSound('powerdown', pathOrBuffer) during your asset initialization
and ensure it completes before gameplay (await or load in preload), then call
k.play('powerdown', { volume: 0.2, detune: -1200 }) only after successful load.
| player.onCollide('coin', (c) => { | ||
| if (c.floating) return; | ||
| collectCoin(); | ||
| c.destroy(); | ||
| }); |
There was a problem hiding this comment.
浮遊コインの収集ロジックを確認してください。
c.floating が true の場合に return していますが、浮遊コイン(マップ上に配置されたコイン)も収集可能であるべきではないでしょうか?現在のロジックでは、タイルとして配置されたコイン(Line 212で floating: true)は収集できません。
player.onCollide('coin', (c) => {
- if (c.floating) return;
collectCoin();
c.destroy();
});🤖 Prompt for AI Agents
In super-mario-bros-1-1-classic/main.js around lines 369 to 373, the collision
handler returns early when c.floating is true which prevents map-placed
("floating") coins from being collected; remove that early-return so coins are
collected regardless of the floating flag. Update the handler to first guard
against double-collection (e.g., check and set a c.collected or similar flag)
then call collectCoin() and c.destroy() so both floating and non-floating coins
are handled safely.
Summary
Testing
Codex Task
Summary by CodeRabbit
リリースノート
新機能
ドキュメンテーション
✏️ Tip: You can customize this high-level summary in your review settings.