feat: Add main menu assets and refactor puzzle thumbnail handling

- Add main menu UI image and background music (with updated track metadata)
- Rename puzzle assets to include `.png` extensions for consistency
- Introduce `thumbnails.json` manifest to decouple thumbnail paths from puzzle data
- Update `NewPuzzleScene.js` to load thumbnails explicitly via manifest instead of inferring paths
- Update `PuzzleScene.js` to ensure full puzzle images are loaded fresh on initial entry (not during network joins or restores)
This commit is contained in:
Brian Fertig 2026-04-05 09:53:11 -06:00
parent baf8653f81
commit 535825ba20
13 changed files with 110 additions and 20 deletions

Binary file not shown.

View File

@ -1,22 +1,22 @@
[ [
{ {
"path": "assets/audio/music/track_01.mp3", "path": "assets/audio/music/track_01.mp3",
"title": "Track 01", "title": "Digital Memories",
"artist": "Unknown Artist" "artist": "AI Com Truise"
}, },
{ {
"path": "assets/audio/music/track_02.mp3", "path": "assets/audio/music/track_02.mp3",
"title": "Track 02", "title": "Synthwave Highway",
"artist": "Unknown Artist" "artist": "AI The Midnight"
}, },
{ {
"path": "assets/audio/music/track_03.mp3", "path": "assets/audio/music/track_03.mp3",
"title": "Track 03", "title": "Orbital Perspective",
"artist": "Unknown Artist" "artist": "AI Tangerine Dream"
}, },
{ {
"path": "assets/audio/music/track_04.mp3", "path": "assets/audio/music/track_04.mp3",
"title": "Track 04", "title": "Just Puzzlin'",
"artist": "Unknown Artist" "artist": "AI Earthless"
} }
] ]

View File

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

View File

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

View File

Before

Width:  |  Height:  |  Size: 325 KiB

After

Width:  |  Height:  |  Size: 325 KiB

View File

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 280 KiB

View File

Before

Width:  |  Height:  |  Size: 386 KiB

After

Width:  |  Height:  |  Size: 386 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 MiB

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

View File

@ -41,7 +41,7 @@
}, },
{ {
"key": "puzzle_misty", "key": "puzzle_misty",
"path": "assets/images/puzzles/misty_exploration", "path": "assets/images/puzzles/misty_exploration.png",
"label": "Misty Exploration" "label": "Misty Exploration"
}, },
{ {
@ -66,12 +66,12 @@
}, },
{ {
"key": "puzzle_mandrill", "key": "puzzle_mandrill",
"path": "assets/images/puzzles/thoughtful_mandrill", "path": "assets/images/puzzles/thoughtful_mandrill.png",
"label": "Thoughtful Mandrill" "label": "Thoughtful Mandrill"
}, },
{ {
"key": "puzzle_ultimate_tree_fort", "key": "puzzle_ultimate_tree_fort",
"path": "assets/images/puzzles/ultimate_tree_fort", "path": "assets/images/puzzles/ultimate_tree_fort.png",
"label": "Ultimate Tree Fort" "label": "Ultimate Tree Fort"
} }
] ]

77
assets/thumbnails.json Normal file
View File

@ -0,0 +1,77 @@
[
{
"key": "thumb_america",
"path": "assets/images/puzzles/thumb_america.png",
"puzzleKey": "puzzle_america"
},
{
"key": "thumb_dwarven_mining_village",
"path": "assets/images/puzzles/thumb_dwarven_mining_village.png",
"puzzleKey": "puzzle_dwarven_mining_village"
},
{
"key": "thumb_golden_in_the_mountains",
"path": "assets/images/puzzles/thumb_golden_in_the_mountains.png",
"puzzleKey": "puzzle_golden_in_the_mountains"
},
{
"key": "thumb_good_vs_evil",
"path": "assets/images/puzzles/thumb_good_vs_evil.png",
"puzzleKey": "puzzle_good_vs_evil"
},
{
"key": "thumb_growing_ea",
"path": "assets/images/puzzles/thumb_growing_ea.png",
"puzzleKey": "puzzle_growing_ea"
},
{
"key": "thumb_guilin_landscape",
"path": "assets/images/puzzles/thumb_guilin_landscape.png",
"puzzleKey": "puzzle_guilin_landscape"
},
{
"key": "thumb_home_sweet_home",
"path": "assets/images/puzzles/thumb_home_sweet_home.png",
"puzzleKey": "puzzle_home_sweet_home"
},
{
"key": "thumb_lone_ship",
"path": "assets/images/puzzles/thumb_lone_ship_in_the_seas.png",
"puzzleKey": "puzzle_lone_ship"
},
{
"key": "thumb_misty",
"path": "assets/images/puzzles/thumb_misty_exploration.png",
"puzzleKey": "puzzle_misty"
},
{
"key": "thumb_model_village",
"path": "assets/images/puzzles/thumb_model_village.png",
"puzzleKey": "puzzle_model_village"
},
{
"key": "thumb_opulant_flowers",
"path": "assets/images/puzzles/thumb_opulant_flowers.png",
"puzzleKey": "puzzle_opulant_flowers"
},
{
"key": "thumb_robot_in_a_flavela",
"path": "assets/images/puzzles/thumb_robot_in_a_flavela.png",
"puzzleKey": "puzzle_robot_in_a_flavela"
},
{
"key": "thumb_disassembled_android",
"path": "assets/images/puzzles/thumb_the_disassembled_android.png",
"puzzleKey": "puzzle_disassembled_android"
},
{
"key": "thumb_mandrill",
"path": "assets/images/puzzles/thumb_thoughtful_mandrill.png",
"puzzleKey": "puzzle_mandrill"
},
{
"key": "thumb_ultimate_tree_fort",
"path": "assets/images/puzzles/thumb_ultimate_tree_fort.png",
"puzzleKey": "puzzle_ultimate_tree_fort"
}
]

View File

@ -18,8 +18,9 @@ class NewPuzzleScene extends Phaser.Scene {
} }
preload() { preload() {
// Load the puzzle list JSON; images are loaded dynamically in create() // Load puzzle list and thumbnail manifest; full images are loaded by PuzzleScene
this.load.json('puzzle_list', 'assets/puzzles.json'); this.load.json('puzzle_list', 'assets/puzzles.json');
this.load.json('thumbnail_list', 'assets/thumbnails.json');
} }
create() { create() {
@ -59,12 +60,18 @@ class NewPuzzleScene extends Phaser.Scene {
sep.fillTriangle(960, 100, 966, 105, 960, 110); sep.fillTriangle(960, 100, 966, 105, 960, 110);
sep.fillTriangle(960, 100, 954, 105, 960, 110); sep.fillTriangle(960, 100, 954, 105, 960, 110);
// Read puzzle list from cache, then load any images not yet in the texture cache // Read puzzle list and thumbnail manifest from cache
this._puzzleImages = this.cache.json.get('puzzle_list'); this._puzzleImages = this.cache.json.get('puzzle_list');
this._thumbnails = this.cache.json.get('thumbnail_list') || [];
const toLoad = this._puzzleImages.filter(img => !this.textures.exists(img.key)); // Build a lookup from puzzleKey -> thumbnail entry
this._thumbByPuzzleKey = {};
this._thumbnails.forEach(t => { this._thumbByPuzzleKey[t.puzzleKey] = t; });
// Only load thumbnail textures (full images are loaded by PuzzleScene)
const toLoad = this._thumbnails.filter(t => !this.textures.exists(t.key));
if (toLoad.length > 0) { if (toLoad.length > 0) {
toLoad.forEach(img => this.load.image(img.key, img.path)); toLoad.forEach(t => this.load.image(t.key, t.path));
this.load.once('complete', () => this._buildDomUI()); this.load.once('complete', () => this._buildDomUI());
this.load.start(); this.load.start();
} else { } else {
@ -131,9 +138,8 @@ class NewPuzzleScene extends Phaser.Scene {
}); });
const thumb = document.createElement('img'); const thumb = document.createElement('img');
// Use thumbnail version: insert "thumb_" before the filename const thumbEntry = this._thumbByPuzzleKey[img.key];
const lastSlash = img.path.lastIndexOf('/'); thumb.src = thumbEntry ? thumbEntry.path : img.path;
thumb.src = img.path.substring(0, lastSlash + 1) + 'thumb_' + img.path.substring(lastSlash + 1);
Object.assign(thumb.style, { Object.assign(thumb.style, {
display: 'block', display: 'block',
width: '100%', width: '100%',

View File

@ -106,6 +106,13 @@ class PuzzleScene extends Phaser.Scene {
} }
} }
} }
// Fresh start from NewPuzzleScene — load the full image if not cached
if (!this.cfg._networkJoin && !this.cfg._restore) {
if (!this.textures.exists(this.cfg.imageKey)) {
this.load.image(this.cfg.imageKey, this.cfg.imagePath);
}
}
} }
create() { create() {