Compare commits
No commits in common. "61d49eab57d3180eba825820b8c0e9bb6dd3fc95" and "e71dab9c4561d2e4111b0126f60a5ff9dd6f2df0" have entirely different histories.
61d49eab57
...
e71dab9c45
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Rename all .png files in this directory to lowercase with underscores replacing spaces.
|
||||
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
|
||||
for f in *.png; do
|
||||
[ -f "$f" ] || continue
|
||||
newname=$(echo "$f" | tr '[:upper:]' '[:lower:]' | tr ' ' '_')
|
||||
if [ "$f" != "$newname" ]; then
|
||||
mv "$f" "$newname"
|
||||
echo "Renamed: $f -> $newname"
|
||||
fi
|
||||
done
|
||||
|
Before Width: | Height: | Size: 4.8 MiB |
|
Before Width: | Height: | Size: 4.8 MiB |
|
Before Width: | Height: | Size: 4.1 MiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 2.7 MiB |
|
Before Width: | Height: | Size: 4.3 MiB |
|
Before Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 3.7 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 3.2 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 3.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 4.6 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 3.8 MiB |
|
Before Width: | Height: | Size: 2.8 MiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
|
@ -1,75 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Regenerates assets/puzzles.json and assets/thumbnails.json from the
|
||||
# images in assets/images/puzzles/.
|
||||
#
|
||||
# Conventions:
|
||||
# Full image: assets/images/puzzles/<name>.png
|
||||
# Thumbnail: assets/images/puzzles/thumb_<name>.png
|
||||
# Puzzle key: puzzle_<name> (hyphens replaced with underscores)
|
||||
# Thumb key: thumb_<name> (hyphens replaced with underscores)
|
||||
# Label: title-cased from <name>, underscores/hyphens → spaces
|
||||
#
|
||||
# Usage: cd <repo-root> && bash assets/images/puzzles/sync_json.sh
|
||||
|
||||
set -euo pipefail
|
||||
cd "$(git rev-parse --show-toplevel)"
|
||||
|
||||
PUZZLE_DIR="assets/images/puzzles"
|
||||
PUZZLES_JSON="assets/puzzles.json"
|
||||
THUMBS_JSON="assets/thumbnails.json"
|
||||
|
||||
puzzles="["
|
||||
thumbs="["
|
||||
first=true
|
||||
|
||||
for img in "$PUZZLE_DIR"/*.png; do
|
||||
base=$(basename "$img" .png)
|
||||
|
||||
# Skip thumbnails, scripts
|
||||
[[ "$base" == thumb_* ]] && continue
|
||||
[[ "$base" == *.sh ]] && continue
|
||||
|
||||
# Derive keys (replace hyphens with underscores for keys)
|
||||
safe="${base//-/_}"
|
||||
puzzle_key="puzzle_${safe}"
|
||||
thumb_key="thumb_${safe}"
|
||||
thumb_file="$PUZZLE_DIR/thumb_${base}.png"
|
||||
|
||||
# Skip if no matching thumbnail
|
||||
if [ ! -f "$thumb_file" ]; then
|
||||
echo "WARNING: No thumbnail for $base — skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Build label: replace underscores/hyphens with spaces, then title-case
|
||||
label=$(echo "$base" | sed 's/[_-]/ /g' | sed 's/\b\(.\)/\u\1/g')
|
||||
|
||||
sep=""
|
||||
$first || sep=","
|
||||
first=false
|
||||
|
||||
puzzles+="${sep}
|
||||
{
|
||||
\"key\": \"${puzzle_key}\",
|
||||
\"path\": \"${PUZZLE_DIR}/${base}.png\",
|
||||
\"label\": \"${label}\"
|
||||
}"
|
||||
|
||||
thumbs+="${sep}
|
||||
{
|
||||
\"key\": \"${thumb_key}\",
|
||||
\"path\": \"${PUZZLE_DIR}/thumb_${base}.png\",
|
||||
\"puzzleKey\": \"${puzzle_key}\"
|
||||
}"
|
||||
done
|
||||
|
||||
puzzles+="
|
||||
]"
|
||||
thumbs+="
|
||||
]"
|
||||
|
||||
echo "$puzzles" > "$PUZZLES_JSON"
|
||||
echo "$thumbs" > "$THUMBS_JSON"
|
||||
|
||||
echo "Updated $PUZZLES_JSON ($(grep -c '"key"' "$PUZZLES_JSON") entries)"
|
||||
echo "Updated $THUMBS_JSON ($(grep -c '"key"' "$THUMBS_JSON") entries)"
|
||||
|
Before Width: | Height: | Size: 3.6 MiB |
|
Before Width: | Height: | Size: 3.7 MiB |
|
Before Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 467 KiB |
|
Before Width: | Height: | Size: 320 KiB |
|
Before Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 407 KiB |
|
Before Width: | Height: | Size: 268 KiB |
|
Before Width: | Height: | Size: 402 KiB |
|
Before Width: | Height: | Size: 349 KiB |
|
Before Width: | Height: | Size: 276 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 326 KiB |
|
Before Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 347 KiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 267 KiB |
|
Before Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 285 KiB |
|
Before Width: | Height: | Size: 304 KiB |
|
Before Width: | Height: | Size: 406 KiB |
|
Before Width: | Height: | Size: 321 KiB |
|
Before Width: | Height: | Size: 311 KiB |
|
Before Width: | Height: | Size: 286 KiB |
|
Before Width: | Height: | Size: 248 KiB |
|
Before Width: | Height: | Size: 298 KiB |
|
Before Width: | Height: | Size: 405 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 327 KiB |
|
Before Width: | Height: | Size: 229 KiB |
|
Before Width: | Height: | Size: 302 KiB |
|
Before Width: | Height: | Size: 335 KiB |
|
Before Width: | Height: | Size: 359 KiB |
|
Before Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.6 MiB |
|
Before Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 4.1 MiB |
|
Before Width: | Height: | Size: 3.7 MiB |
|
|
@ -1,146 +1,46 @@
|
|||
[
|
||||
{
|
||||
"key": "puzzle_above_the_city",
|
||||
"path": "assets/images/puzzles/above_the_city.png",
|
||||
"label": "Above The City"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_abstract_highway",
|
||||
"path": "assets/images/puzzles/abstract_highway.png",
|
||||
"label": "Abstract Highway"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_alpine_mountains",
|
||||
"path": "assets/images/puzzles/alpine_mountains.png",
|
||||
"label": "Alpine Mountains"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_america",
|
||||
"path": "assets/images/puzzles/america.png",
|
||||
"label": "America"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_arctic_fox",
|
||||
"path": "assets/images/puzzles/arctic_fox.png",
|
||||
"label": "Arctic Fox"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_cartoon_land",
|
||||
"path": "assets/images/puzzles/cartoon_land.png",
|
||||
"label": "Cartoon Land"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_christmas_in_the_park",
|
||||
"path": "assets/images/puzzles/christmas_in_the_park.png",
|
||||
"label": "Christmas In The Park"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_combat_mech",
|
||||
"path": "assets/images/puzzles/combat_mech.png",
|
||||
"label": "Combat Mech"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_cottages_on_the_street",
|
||||
"path": "assets/images/puzzles/cottages_on_the_street.png",
|
||||
"label": "Cottages On The Street"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_dwarven_blacksmith",
|
||||
"path": "assets/images/puzzles/dwarven_blacksmith.png",
|
||||
"label": "Dwarven Blacksmith"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_dwarven_mining_village",
|
||||
"path": "assets/images/puzzles/dwarven_mining_village.png",
|
||||
"label": "Dwarven Mining Village"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_ferarri_in_the_driveway",
|
||||
"path": "assets/images/puzzles/ferarri_in_the_driveway.png",
|
||||
"label": "Ferarri In The Driveway"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_floating_castles",
|
||||
"path": "assets/images/puzzles/floating_castles.png",
|
||||
"label": "Floating Castles"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_floating_wizards_village",
|
||||
"path": "assets/images/puzzles/floating_wizards_village.png",
|
||||
"label": "Floating Wizards Village"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_four_seasons_2",
|
||||
"path": "assets/images/puzzles/four_seasons_2.png",
|
||||
"label": "Four Seasons 2"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_fruit_bowl",
|
||||
"path": "assets/images/puzzles/fruit_bowl.png",
|
||||
"label": "Fruit Bowl"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_fuzzy_halloween",
|
||||
"path": "assets/images/puzzles/fuzzy_halloween.png",
|
||||
"label": "Fuzzy Halloween"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_golden_in_the_mountains",
|
||||
"path": "assets/images/puzzles/golden_in_the_mountains.png",
|
||||
"label": "Golden In The Mountains"
|
||||
"label": "Golden in the Mountains"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_good_vs_evil",
|
||||
"path": "assets/images/puzzles/good_vs_evil.png",
|
||||
"label": "Good Vs Evil"
|
||||
"label": "Good vs Evil"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_growing_ea",
|
||||
"path": "assets/images/puzzles/growing_ea.png",
|
||||
"label": "Growing Ea"
|
||||
"label": "Growing Computer Parts"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_guilin_landscape",
|
||||
"path": "assets/images/puzzles/guilin_landscape.png",
|
||||
"label": "Guilin Landscape"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_heavy_storm_in_the_city",
|
||||
"path": "assets/images/puzzles/heavy_storm_in_the_city.png",
|
||||
"label": "Heavy Storm In The City"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_home_sweet_home",
|
||||
"path": "assets/images/puzzles/home_sweet_home.png",
|
||||
"label": "Home Sweet Home"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_jeweled_frogs",
|
||||
"path": "assets/images/puzzles/jeweled_frogs.png",
|
||||
"label": "Jeweled Frogs"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_jungle_macaw",
|
||||
"path": "assets/images/puzzles/jungle_macaw.png",
|
||||
"label": "Jungle Macaw"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_lake_treehouse",
|
||||
"path": "assets/images/puzzles/lake_treehouse.png",
|
||||
"label": "Lake Treehouse"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_lone_ship_in_the_seas",
|
||||
"key": "puzzle_lone_ship",
|
||||
"path": "assets/images/puzzles/lone_ship_in_the_seas.png",
|
||||
"label": "Lone Ship In The Seas"
|
||||
"label": "Lone Ship on the Ocean"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_mini_dennys",
|
||||
"path": "assets/images/puzzles/mini-dennys.png",
|
||||
"label": "Mini Dennys"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_misty_exploration",
|
||||
"key": "puzzle_misty",
|
||||
"path": "assets/images/puzzles/misty_exploration.png",
|
||||
"label": "Misty Exploration"
|
||||
},
|
||||
|
|
@ -149,104 +49,29 @@
|
|||
"path": "assets/images/puzzles/model_village.png",
|
||||
"label": "Model Village"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_moroccan_lounge",
|
||||
"path": "assets/images/puzzles/moroccan_lounge.png",
|
||||
"label": "Moroccan Lounge"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_mountain_blanket",
|
||||
"path": "assets/images/puzzles/mountain_blanket.png",
|
||||
"label": "Mountain Blanket"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_opulant_flowers",
|
||||
"path": "assets/images/puzzles/opulant_flowers.png",
|
||||
"label": "Opulant Flowers"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_orc_and_the_undead",
|
||||
"path": "assets/images/puzzles/orc_and_the_undead.png",
|
||||
"label": "Orc And The Undead"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_red_panda_in_the_bamboo_forest",
|
||||
"path": "assets/images/puzzles/red_panda_in_the_bamboo_forest.png",
|
||||
"label": "Red Panda In The Bamboo Forest"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_robot_in_a_flavela",
|
||||
"path": "assets/images/puzzles/robot_in_a_flavela.png",
|
||||
"label": "Robot In A Flavela"
|
||||
"label": "Robot in a Favela"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_shanty_stack",
|
||||
"path": "assets/images/puzzles/shanty_stack.png",
|
||||
"label": "Shanty Stack"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_sleepy_golden",
|
||||
"path": "assets/images/puzzles/sleepy_golden.png",
|
||||
"label": "Sleepy Golden"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_technorhino",
|
||||
"path": "assets/images/puzzles/technorhino.png",
|
||||
"label": "Technorhino"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_the_beige_tree",
|
||||
"path": "assets/images/puzzles/the_beige_tree.png",
|
||||
"label": "The Beige Tree"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_the_disassembled_android",
|
||||
"key": "puzzle_disassembled_android",
|
||||
"path": "assets/images/puzzles/the_disassembled_android.png",
|
||||
"label": "The Disassembled Android"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_the_old_w0rm",
|
||||
"path": "assets/images/puzzles/the_old_w0rm.png",
|
||||
"label": "The Old W0rm"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_the_swirl",
|
||||
"path": "assets/images/puzzles/the_swirl.png",
|
||||
"label": "The Swirl"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_thoughtful_mandrill",
|
||||
"key": "puzzle_mandrill",
|
||||
"path": "assets/images/puzzles/thoughtful_mandrill.png",
|
||||
"label": "Thoughtful Mandrill"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_tiger_in_bamboo_forest",
|
||||
"path": "assets/images/puzzles/tiger_in_bamboo_forest.png",
|
||||
"label": "Tiger In Bamboo Forest"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_tokyo_mech_2",
|
||||
"path": "assets/images/puzzles/tokyo_mech_2.png",
|
||||
"label": "Tokyo Mech 2"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_tune_the_news",
|
||||
"path": "assets/images/puzzles/tune_the_news.png",
|
||||
"label": "Tune The News"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_turtle_metropolis",
|
||||
"path": "assets/images/puzzles/turtle_metropolis.png",
|
||||
"label": "Turtle Metropolis"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_ultimate_tree_fort",
|
||||
"path": "assets/images/puzzles/ultimate_tree_fort.png",
|
||||
"label": "Ultimate Tree Fort"
|
||||
},
|
||||
{
|
||||
"key": "puzzle_victorian_steampunk_rooftops",
|
||||
"path": "assets/images/puzzles/victorian_steampunk_rooftops.png",
|
||||
"label": "Victorian Steampunk Rooftops"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
@ -1,89 +1,14 @@
|
|||
[
|
||||
{
|
||||
"key": "thumb_above_the_city",
|
||||
"path": "assets/images/puzzles/thumb_above_the_city.png",
|
||||
"puzzleKey": "puzzle_above_the_city"
|
||||
},
|
||||
{
|
||||
"key": "thumb_abstract_highway",
|
||||
"path": "assets/images/puzzles/thumb_abstract_highway.png",
|
||||
"puzzleKey": "puzzle_abstract_highway"
|
||||
},
|
||||
{
|
||||
"key": "thumb_alpine_mountains",
|
||||
"path": "assets/images/puzzles/thumb_alpine_mountains.png",
|
||||
"puzzleKey": "puzzle_alpine_mountains"
|
||||
},
|
||||
{
|
||||
"key": "thumb_america",
|
||||
"path": "assets/images/puzzles/thumb_america.png",
|
||||
"puzzleKey": "puzzle_america"
|
||||
},
|
||||
{
|
||||
"key": "thumb_arctic_fox",
|
||||
"path": "assets/images/puzzles/thumb_arctic_fox.png",
|
||||
"puzzleKey": "puzzle_arctic_fox"
|
||||
},
|
||||
{
|
||||
"key": "thumb_cartoon_land",
|
||||
"path": "assets/images/puzzles/thumb_cartoon_land.png",
|
||||
"puzzleKey": "puzzle_cartoon_land"
|
||||
},
|
||||
{
|
||||
"key": "thumb_christmas_in_the_park",
|
||||
"path": "assets/images/puzzles/thumb_christmas_in_the_park.png",
|
||||
"puzzleKey": "puzzle_christmas_in_the_park"
|
||||
},
|
||||
{
|
||||
"key": "thumb_combat_mech",
|
||||
"path": "assets/images/puzzles/thumb_combat_mech.png",
|
||||
"puzzleKey": "puzzle_combat_mech"
|
||||
},
|
||||
{
|
||||
"key": "thumb_cottages_on_the_street",
|
||||
"path": "assets/images/puzzles/thumb_cottages_on_the_street.png",
|
||||
"puzzleKey": "puzzle_cottages_on_the_street"
|
||||
},
|
||||
{
|
||||
"key": "thumb_dwarven_blacksmith",
|
||||
"path": "assets/images/puzzles/thumb_dwarven_blacksmith.png",
|
||||
"puzzleKey": "puzzle_dwarven_blacksmith"
|
||||
},
|
||||
{
|
||||
"key": "thumb_dwarven_mining_village",
|
||||
"path": "assets/images/puzzles/thumb_dwarven_mining_village.png",
|
||||
"puzzleKey": "puzzle_dwarven_mining_village"
|
||||
},
|
||||
{
|
||||
"key": "thumb_ferarri_in_the_driveway",
|
||||
"path": "assets/images/puzzles/thumb_ferarri_in_the_driveway.png",
|
||||
"puzzleKey": "puzzle_ferarri_in_the_driveway"
|
||||
},
|
||||
{
|
||||
"key": "thumb_floating_castles",
|
||||
"path": "assets/images/puzzles/thumb_floating_castles.png",
|
||||
"puzzleKey": "puzzle_floating_castles"
|
||||
},
|
||||
{
|
||||
"key": "thumb_floating_wizards_village",
|
||||
"path": "assets/images/puzzles/thumb_floating_wizards_village.png",
|
||||
"puzzleKey": "puzzle_floating_wizards_village"
|
||||
},
|
||||
{
|
||||
"key": "thumb_four_seasons_2",
|
||||
"path": "assets/images/puzzles/thumb_four_seasons_2.png",
|
||||
"puzzleKey": "puzzle_four_seasons_2"
|
||||
},
|
||||
{
|
||||
"key": "thumb_fruit_bowl",
|
||||
"path": "assets/images/puzzles/thumb_fruit_bowl.png",
|
||||
"puzzleKey": "puzzle_fruit_bowl"
|
||||
},
|
||||
{
|
||||
"key": "thumb_fuzzy_halloween",
|
||||
"path": "assets/images/puzzles/thumb_fuzzy_halloween.png",
|
||||
"puzzleKey": "puzzle_fuzzy_halloween"
|
||||
},
|
||||
{
|
||||
"key": "thumb_golden_in_the_mountains",
|
||||
"path": "assets/images/puzzles/thumb_golden_in_the_mountains.png",
|
||||
|
|
@ -104,149 +29,49 @@
|
|||
"path": "assets/images/puzzles/thumb_guilin_landscape.png",
|
||||
"puzzleKey": "puzzle_guilin_landscape"
|
||||
},
|
||||
{
|
||||
"key": "thumb_heavy_storm_in_the_city",
|
||||
"path": "assets/images/puzzles/thumb_heavy_storm_in_the_city.png",
|
||||
"puzzleKey": "puzzle_heavy_storm_in_the_city"
|
||||
},
|
||||
{
|
||||
"key": "thumb_home_sweet_home",
|
||||
"path": "assets/images/puzzles/thumb_home_sweet_home.png",
|
||||
"puzzleKey": "puzzle_home_sweet_home"
|
||||
},
|
||||
{
|
||||
"key": "thumb_jeweled_frogs",
|
||||
"path": "assets/images/puzzles/thumb_jeweled_frogs.png",
|
||||
"puzzleKey": "puzzle_jeweled_frogs"
|
||||
},
|
||||
{
|
||||
"key": "thumb_jungle_macaw",
|
||||
"path": "assets/images/puzzles/thumb_jungle_macaw.png",
|
||||
"puzzleKey": "puzzle_jungle_macaw"
|
||||
},
|
||||
{
|
||||
"key": "thumb_lake_treehouse",
|
||||
"path": "assets/images/puzzles/thumb_lake_treehouse.png",
|
||||
"puzzleKey": "puzzle_lake_treehouse"
|
||||
},
|
||||
{
|
||||
"key": "thumb_lone_ship_in_the_seas",
|
||||
"key": "thumb_lone_ship",
|
||||
"path": "assets/images/puzzles/thumb_lone_ship_in_the_seas.png",
|
||||
"puzzleKey": "puzzle_lone_ship_in_the_seas"
|
||||
"puzzleKey": "puzzle_lone_ship"
|
||||
},
|
||||
{
|
||||
"key": "thumb_mini_dennys",
|
||||
"path": "assets/images/puzzles/thumb_mini-dennys.png",
|
||||
"puzzleKey": "puzzle_mini_dennys"
|
||||
},
|
||||
{
|
||||
"key": "thumb_misty_exploration",
|
||||
"key": "thumb_misty",
|
||||
"path": "assets/images/puzzles/thumb_misty_exploration.png",
|
||||
"puzzleKey": "puzzle_misty_exploration"
|
||||
"puzzleKey": "puzzle_misty"
|
||||
},
|
||||
{
|
||||
"key": "thumb_model_village",
|
||||
"path": "assets/images/puzzles/thumb_model_village.png",
|
||||
"puzzleKey": "puzzle_model_village"
|
||||
},
|
||||
{
|
||||
"key": "thumb_moroccan_lounge",
|
||||
"path": "assets/images/puzzles/thumb_moroccan_lounge.png",
|
||||
"puzzleKey": "puzzle_moroccan_lounge"
|
||||
},
|
||||
{
|
||||
"key": "thumb_mountain_blanket",
|
||||
"path": "assets/images/puzzles/thumb_mountain_blanket.png",
|
||||
"puzzleKey": "puzzle_mountain_blanket"
|
||||
},
|
||||
{
|
||||
"key": "thumb_opulant_flowers",
|
||||
"path": "assets/images/puzzles/thumb_opulant_flowers.png",
|
||||
"puzzleKey": "puzzle_opulant_flowers"
|
||||
},
|
||||
{
|
||||
"key": "thumb_orc_and_the_undead",
|
||||
"path": "assets/images/puzzles/thumb_orc_and_the_undead.png",
|
||||
"puzzleKey": "puzzle_orc_and_the_undead"
|
||||
},
|
||||
{
|
||||
"key": "thumb_red_panda_in_the_bamboo_forest",
|
||||
"path": "assets/images/puzzles/thumb_red_panda_in_the_bamboo_forest.png",
|
||||
"puzzleKey": "puzzle_red_panda_in_the_bamboo_forest"
|
||||
},
|
||||
{
|
||||
"key": "thumb_robot_in_a_flavela",
|
||||
"path": "assets/images/puzzles/thumb_robot_in_a_flavela.png",
|
||||
"puzzleKey": "puzzle_robot_in_a_flavela"
|
||||
},
|
||||
{
|
||||
"key": "thumb_shanty_stack",
|
||||
"path": "assets/images/puzzles/thumb_shanty_stack.png",
|
||||
"puzzleKey": "puzzle_shanty_stack"
|
||||
},
|
||||
{
|
||||
"key": "thumb_sleepy_golden",
|
||||
"path": "assets/images/puzzles/thumb_sleepy_golden.png",
|
||||
"puzzleKey": "puzzle_sleepy_golden"
|
||||
},
|
||||
{
|
||||
"key": "thumb_technorhino",
|
||||
"path": "assets/images/puzzles/thumb_technorhino.png",
|
||||
"puzzleKey": "puzzle_technorhino"
|
||||
},
|
||||
{
|
||||
"key": "thumb_the_beige_tree",
|
||||
"path": "assets/images/puzzles/thumb_the_beige_tree.png",
|
||||
"puzzleKey": "puzzle_the_beige_tree"
|
||||
},
|
||||
{
|
||||
"key": "thumb_the_disassembled_android",
|
||||
"key": "thumb_disassembled_android",
|
||||
"path": "assets/images/puzzles/thumb_the_disassembled_android.png",
|
||||
"puzzleKey": "puzzle_the_disassembled_android"
|
||||
"puzzleKey": "puzzle_disassembled_android"
|
||||
},
|
||||
{
|
||||
"key": "thumb_the_old_w0rm",
|
||||
"path": "assets/images/puzzles/thumb_the_old_w0rm.png",
|
||||
"puzzleKey": "puzzle_the_old_w0rm"
|
||||
},
|
||||
{
|
||||
"key": "thumb_the_swirl",
|
||||
"path": "assets/images/puzzles/thumb_the_swirl.png",
|
||||
"puzzleKey": "puzzle_the_swirl"
|
||||
},
|
||||
{
|
||||
"key": "thumb_thoughtful_mandrill",
|
||||
"key": "thumb_mandrill",
|
||||
"path": "assets/images/puzzles/thumb_thoughtful_mandrill.png",
|
||||
"puzzleKey": "puzzle_thoughtful_mandrill"
|
||||
},
|
||||
{
|
||||
"key": "thumb_tiger_in_bamboo_forest",
|
||||
"path": "assets/images/puzzles/thumb_tiger_in_bamboo_forest.png",
|
||||
"puzzleKey": "puzzle_tiger_in_bamboo_forest"
|
||||
},
|
||||
{
|
||||
"key": "thumb_tokyo_mech_2",
|
||||
"path": "assets/images/puzzles/thumb_tokyo_mech_2.png",
|
||||
"puzzleKey": "puzzle_tokyo_mech_2"
|
||||
},
|
||||
{
|
||||
"key": "thumb_tune_the_news",
|
||||
"path": "assets/images/puzzles/thumb_tune_the_news.png",
|
||||
"puzzleKey": "puzzle_tune_the_news"
|
||||
},
|
||||
{
|
||||
"key": "thumb_turtle_metropolis",
|
||||
"path": "assets/images/puzzles/thumb_turtle_metropolis.png",
|
||||
"puzzleKey": "puzzle_turtle_metropolis"
|
||||
"puzzleKey": "puzzle_mandrill"
|
||||
},
|
||||
{
|
||||
"key": "thumb_ultimate_tree_fort",
|
||||
"path": "assets/images/puzzles/thumb_ultimate_tree_fort.png",
|
||||
"puzzleKey": "puzzle_ultimate_tree_fort"
|
||||
},
|
||||
{
|
||||
"key": "thumb_victorian_steampunk_rooftops",
|
||||
"path": "assets/images/puzzles/thumb_victorian_steampunk_rooftops.png",
|
||||
"puzzleKey": "puzzle_victorian_steampunk_rooftops"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
@ -46,25 +46,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
this._playerNames = new Map(); // playerId -> name
|
||||
this._remoteLabels = new Map(); // playerId -> { bg: Graphics, text: Text }
|
||||
|
||||
// Reset state from any previous puzzle
|
||||
this._completed = false;
|
||||
this._completionTime = null;
|
||||
this._ready = false;
|
||||
this._heldPiece = null;
|
||||
this._isPanning = false;
|
||||
this._isBoxSelecting = false;
|
||||
this._boxStartWorld = null;
|
||||
this._boxSelectedIds = null;
|
||||
this._startTime = null;
|
||||
this._currentMusic = null;
|
||||
this._musicStarted = false;
|
||||
this._timerEl = null;
|
||||
this._playersListEl = null;
|
||||
this._connStatusEl = null;
|
||||
this._trackInfoEl = null;
|
||||
this._muteBtn = null;
|
||||
this._minZoom = null;
|
||||
|
||||
// Network join from MainMenuScene
|
||||
if (this.cfg._networkJoin) {
|
||||
this._isNetworked = true;
|
||||
|
|
@ -197,9 +178,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
update() {
|
||||
if (!this._ready) return;
|
||||
|
||||
// Update puzzle timer once per second
|
||||
this._updateTimer();
|
||||
|
||||
// Fallback: detect when music track has finished (Phaser 3.9 'complete' event can be unreliable)
|
||||
if (this._currentMusic && this._musicStarted && !this._currentMusic.isPlaying && !this._currentMusic.isPaused) {
|
||||
this._playNextTrack();
|
||||
|
|
@ -332,9 +310,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
this._panLastY = 0;
|
||||
this._ready = true;
|
||||
|
||||
// Puzzle timer — restore from saved state or start fresh
|
||||
this._startTime = (saved && saved.startTime) ? saved.startTime : Date.now();
|
||||
|
||||
// Box selection state (CTRL+drag)
|
||||
this._isBoxSelecting = false;
|
||||
this._boxStartWorld = null; // { x, y } in world coords
|
||||
|
|
@ -421,7 +396,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
}
|
||||
|
||||
this._setupNetworkListeners();
|
||||
this._updatePlayersList();
|
||||
} else if (NetworkManager.connected) {
|
||||
// Host — create the room on the server
|
||||
this._isNetworked = true;
|
||||
|
|
@ -438,7 +412,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
completed: false,
|
||||
bgKey: this._bgKey,
|
||||
bgPath: this._bgPath,
|
||||
startTime: this._startTime,
|
||||
});
|
||||
NetworkManager.createRoom(this.cfg.roomCode, state.serialize(), this.cfg.playerName);
|
||||
this._setupNetworkListeners();
|
||||
|
|
@ -575,7 +548,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
this._playerNames.set(msg.playerId, msg.playerName);
|
||||
}
|
||||
console.log(`${msg.playerName || 'Player ' + msg.playerId} joined the room`);
|
||||
this._updatePlayersList();
|
||||
}
|
||||
|
||||
_onNetworkPlayerLeft(msg) {
|
||||
|
|
@ -592,7 +564,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
}
|
||||
this._playerNames.delete(msg.playerId);
|
||||
console.log(`Player ${msg.playerId} left the room`);
|
||||
this._updatePlayersList();
|
||||
}
|
||||
|
||||
_onNetworkCompleted() {
|
||||
|
|
@ -1108,8 +1079,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
const gm = this._groupManager;
|
||||
if (gm.groupCount === 1 && gm.pieceCount === this._pieces.length) {
|
||||
this._completed = true;
|
||||
// Freeze the timer
|
||||
this._completionTime = Date.now() - this._startTime;
|
||||
StorageManager.clearCurrent();
|
||||
this._showCompletion(true);
|
||||
}
|
||||
|
|
@ -1169,46 +1138,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
this.time.delayedCall(animate ? 1300 : 0, () => this._showDomCompletion());
|
||||
}
|
||||
|
||||
// ─── Room Stats helpers ──────────────────────────────────────────────
|
||||
|
||||
_updateTimer() {
|
||||
if (!this._timerEl || !this._startTime || this._completed) return;
|
||||
const elapsed = Math.floor((Date.now() - this._startTime) / 1000);
|
||||
this._timerEl.textContent = this._formatTime(elapsed);
|
||||
}
|
||||
|
||||
_formatTime(totalSeconds) {
|
||||
const h = Math.floor(totalSeconds / 3600);
|
||||
const m = Math.floor((totalSeconds % 3600) / 60);
|
||||
const s = totalSeconds % 60;
|
||||
return String(h).padStart(2, '0') + ':' +
|
||||
String(m).padStart(2, '0') + ':' +
|
||||
String(s).padStart(2, '0');
|
||||
}
|
||||
|
||||
_updatePlayersList() {
|
||||
if (!this._playersListEl) return;
|
||||
const names = [];
|
||||
// Add local player first
|
||||
if (this.cfg.playerName) {
|
||||
names.push(this.cfg.playerName + ' (you)');
|
||||
}
|
||||
// Add remote players
|
||||
this._playerNames.forEach((name) => {
|
||||
names.push(name);
|
||||
});
|
||||
if (names.length === 0) {
|
||||
this._playersListEl.textContent = '\u2014';
|
||||
} else {
|
||||
this._playersListEl.innerHTML = '';
|
||||
names.forEach(n => {
|
||||
const row = document.createElement('div');
|
||||
row.textContent = n;
|
||||
this._playersListEl.appendChild(row);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ─── DOM UI ──────────────────────────────────────────────────────────
|
||||
|
||||
// ─── Music ──────────────────────────────────────────────────────────
|
||||
|
|
@ -1455,219 +1384,9 @@ class PuzzleScene extends Phaser.Scene {
|
|||
this._saveState();
|
||||
this.scene.start('MainMenuScene');
|
||||
});
|
||||
Object.assign(backBtn.style, { top: '10px', left: '10px' });
|
||||
Object.assign(backBtn.style, { top: '1%', left: '0.5%' });
|
||||
this._uiLayer.appendChild(backBtn);
|
||||
|
||||
// Room Stats panel — below menu button
|
||||
// States: 'expanded' → 'folded' (content hidden, title visible) → 'collapsed' (icon only)
|
||||
const statsPanel = document.createElement('div');
|
||||
Object.assign(statsPanel.style, {
|
||||
position: 'absolute',
|
||||
top: '50px',
|
||||
left: '10px',
|
||||
background: 'rgba(0, 0, 0, 0.55)',
|
||||
padding: '10px 16px',
|
||||
borderRadius: '4px',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
color: '#ddeeff',
|
||||
fontSize: '14px',
|
||||
lineHeight: '1.6',
|
||||
overflow: 'hidden',
|
||||
transition: 'width 0.3s ease, padding 0.3s ease',
|
||||
width: 'auto',
|
||||
});
|
||||
|
||||
// Title row with collapse toggle
|
||||
const statsHeader = document.createElement('div');
|
||||
Object.assign(statsHeader.style, {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
pointerEvents: 'auto',
|
||||
userSelect: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
});
|
||||
|
||||
const toggleIcon = document.createElement('span');
|
||||
Object.assign(toggleIcon.style, {
|
||||
fontSize: '14px',
|
||||
color: '#8899bb',
|
||||
display: 'inline-block',
|
||||
flexShrink: '0',
|
||||
});
|
||||
toggleIcon.textContent = '\u25B2'; // ▲
|
||||
|
||||
const statsTitle = document.createElement('span');
|
||||
Object.assign(statsTitle.style, {
|
||||
fontWeight: 'bold',
|
||||
fontSize: '15px',
|
||||
color: '#ddeeff',
|
||||
letterSpacing: '0.05em',
|
||||
marginLeft: '8px',
|
||||
overflow: 'hidden',
|
||||
transition: 'max-width 0.3s ease, opacity 0.25s ease, margin 0.3s ease',
|
||||
display: 'inline-block',
|
||||
maxWidth: '200px',
|
||||
opacity: '1',
|
||||
});
|
||||
statsTitle.textContent = 'Room Stats';
|
||||
|
||||
statsHeader.appendChild(toggleIcon);
|
||||
statsHeader.appendChild(statsTitle);
|
||||
statsPanel.appendChild(statsHeader);
|
||||
|
||||
// Collapsible content wrapper
|
||||
const statsContent = document.createElement('div');
|
||||
Object.assign(statsContent.style, {
|
||||
overflow: 'hidden',
|
||||
transition: 'max-height 0.3s ease, opacity 0.25s ease',
|
||||
opacity: '1',
|
||||
});
|
||||
|
||||
// Puzzle Time
|
||||
const timeLabel = document.createElement('div');
|
||||
Object.assign(timeLabel.style, { color: '#8899bb', fontSize: '12px', marginTop: '6px' });
|
||||
timeLabel.textContent = 'Puzzle Time';
|
||||
statsContent.appendChild(timeLabel);
|
||||
|
||||
this._timerEl = document.createElement('div');
|
||||
Object.assign(this._timerEl.style, {
|
||||
color: '#ddeeff',
|
||||
fontSize: '16px',
|
||||
fontFamily: 'monospace',
|
||||
fontWeight: 'bold',
|
||||
});
|
||||
this._timerEl.textContent = '00:00:00';
|
||||
statsContent.appendChild(this._timerEl);
|
||||
|
||||
// Players
|
||||
const playersLabel = document.createElement('div');
|
||||
Object.assign(playersLabel.style, { color: '#8899bb', fontSize: '12px', marginTop: '8px' });
|
||||
playersLabel.textContent = 'Players';
|
||||
statsContent.appendChild(playersLabel);
|
||||
|
||||
this._playersListEl = document.createElement('div');
|
||||
Object.assign(this._playersListEl.style, {
|
||||
color: '#ddeeff',
|
||||
fontSize: '13px',
|
||||
});
|
||||
statsContent.appendChild(this._playersListEl);
|
||||
|
||||
statsPanel.appendChild(statsContent);
|
||||
|
||||
// Measure natural height after first render
|
||||
requestAnimationFrame(() => {
|
||||
statsContent.style.maxHeight = statsContent.scrollHeight + 'px';
|
||||
});
|
||||
|
||||
// Collapse / expand state machine
|
||||
let statsState = 'expanded'; // 'expanded' | 'folded' | 'collapsed'
|
||||
let animating = false;
|
||||
|
||||
const collapseContent = () => {
|
||||
// Phase 1: fold content up
|
||||
animating = true;
|
||||
statsContent.style.maxHeight = statsContent.scrollHeight + 'px';
|
||||
statsContent.offsetHeight; // eslint-disable-line no-unused-expressions
|
||||
statsContent.style.maxHeight = '0px';
|
||||
statsContent.style.opacity = '0';
|
||||
toggleIcon.textContent = '\u25BC'; // ▼
|
||||
|
||||
statsContent.addEventListener('transitionend', function onFolded(ev) {
|
||||
if (ev.propertyName !== 'max-height') return;
|
||||
statsContent.removeEventListener('transitionend', onFolded);
|
||||
statsState = 'folded';
|
||||
// Phase 2: collapse title horizontally
|
||||
collapseTitle();
|
||||
});
|
||||
};
|
||||
|
||||
const collapseTitle = () => {
|
||||
// Snapshot current width so we can animate from it
|
||||
const currentW = statsPanel.offsetWidth;
|
||||
statsPanel.style.width = currentW + 'px';
|
||||
statsPanel.offsetHeight; // eslint-disable-line no-unused-expressions
|
||||
|
||||
statsTitle.style.maxWidth = '0px';
|
||||
statsTitle.style.opacity = '0';
|
||||
statsTitle.style.marginLeft = '0px';
|
||||
// Icon is ~14px + 8px padding each side = 30px
|
||||
statsPanel.style.width = '30px';
|
||||
statsPanel.style.padding = '8px';
|
||||
|
||||
statsTitle.addEventListener('transitionend', function onTitleDone(ev) {
|
||||
if (ev.propertyName !== 'max-width') return;
|
||||
statsTitle.removeEventListener('transitionend', onTitleDone);
|
||||
toggleIcon.textContent = '\u25B6'; // ▶
|
||||
statsState = 'collapsed';
|
||||
animating = false;
|
||||
});
|
||||
};
|
||||
|
||||
const expandTitle = () => {
|
||||
// Phase 1: expand title horizontally
|
||||
animating = true;
|
||||
toggleIcon.textContent = '\u25BC'; // ▼
|
||||
statsPanel.style.padding = '10px 16px';
|
||||
statsPanel.style.width = 'auto';
|
||||
// Measure the full expanded width, then animate to it
|
||||
const fullW = statsPanel.offsetWidth;
|
||||
statsPanel.style.width = '30px';
|
||||
statsPanel.offsetHeight; // eslint-disable-line no-unused-expressions
|
||||
statsPanel.style.width = fullW + 'px';
|
||||
statsTitle.style.maxWidth = '200px';
|
||||
statsTitle.style.opacity = '1';
|
||||
statsTitle.style.marginLeft = '8px';
|
||||
|
||||
statsTitle.addEventListener('transitionend', function onTitleBack(ev) {
|
||||
if (ev.propertyName !== 'max-width') return;
|
||||
statsTitle.removeEventListener('transitionend', onTitleBack);
|
||||
statsPanel.style.width = 'auto';
|
||||
statsState = 'folded';
|
||||
// Phase 2: expand content
|
||||
expandContent();
|
||||
});
|
||||
};
|
||||
|
||||
const expandContent = () => {
|
||||
// Measure natural height
|
||||
statsContent.style.transition = 'none';
|
||||
statsContent.style.maxHeight = 'none';
|
||||
const fullHeight = statsContent.scrollHeight;
|
||||
statsContent.style.maxHeight = '0px';
|
||||
statsContent.offsetHeight; // eslint-disable-line no-unused-expressions
|
||||
statsContent.style.transition = 'max-height 0.3s ease, opacity 0.25s ease';
|
||||
statsContent.style.maxHeight = fullHeight + 'px';
|
||||
statsContent.style.opacity = '1';
|
||||
toggleIcon.textContent = '\u25B2'; // ▲
|
||||
|
||||
statsContent.addEventListener('transitionend', function onExpanded(ev) {
|
||||
if (ev.propertyName !== 'max-height') return;
|
||||
statsContent.removeEventListener('transitionend', onExpanded);
|
||||
statsContent.style.maxHeight = 'none';
|
||||
statsState = 'expanded';
|
||||
animating = false;
|
||||
});
|
||||
};
|
||||
|
||||
statsHeader.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
if (animating) return;
|
||||
if (statsState === 'expanded') {
|
||||
collapseContent();
|
||||
} else if (statsState === 'collapsed') {
|
||||
expandTitle();
|
||||
}
|
||||
});
|
||||
|
||||
// Hover feedback on toggle icon
|
||||
statsHeader.addEventListener('mouseenter', () => { toggleIcon.style.color = '#ddeeff'; });
|
||||
statsHeader.addEventListener('mouseleave', () => { toggleIcon.style.color = '#8899bb'; });
|
||||
|
||||
this._uiLayer.appendChild(statsPanel);
|
||||
this._updatePlayersList();
|
||||
|
||||
// Music controls — top-right
|
||||
const musicRow = document.createElement('div');
|
||||
Object.assign(musicRow.style, {
|
||||
|
|
@ -1680,9 +1399,9 @@ class PuzzleScene extends Phaser.Scene {
|
|||
});
|
||||
|
||||
const btnStyle = {
|
||||
background: '#1565c0',
|
||||
background: 'rgba(0, 0, 0, 0.55)',
|
||||
color: '#ddeeff',
|
||||
border: '1px solid #64b5f6',
|
||||
border: '1px solid #4477bb',
|
||||
borderRadius: '4px',
|
||||
fontSize: '1.8vmin',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
|
|
@ -1696,16 +1415,16 @@ class PuzzleScene extends Phaser.Scene {
|
|||
skipBtn.textContent = '\u23ED'; // next track symbol
|
||||
skipBtn.title = 'Next Track';
|
||||
Object.assign(skipBtn.style, btnStyle);
|
||||
skipBtn.addEventListener('mouseenter', () => { skipBtn.style.background = '#1e88e5'; });
|
||||
skipBtn.addEventListener('mouseleave', () => { skipBtn.style.background = '#1565c0'; });
|
||||
skipBtn.addEventListener('mouseenter', () => { skipBtn.style.background = '#223355'; });
|
||||
skipBtn.addEventListener('mouseleave', () => { skipBtn.style.background = 'rgba(0, 0, 0, 0.55)'; });
|
||||
skipBtn.addEventListener('click', () => this._skipTrack());
|
||||
|
||||
// Mute/unmute button
|
||||
this._muteBtn = document.createElement('button');
|
||||
this._muteBtn.title = 'Mute / Unmute';
|
||||
Object.assign(this._muteBtn.style, btnStyle);
|
||||
this._muteBtn.addEventListener('mouseenter', () => { this._muteBtn.style.background = '#1e88e5'; });
|
||||
this._muteBtn.addEventListener('mouseleave', () => { this._muteBtn.style.background = '#1565c0'; });
|
||||
this._muteBtn.addEventListener('mouseenter', () => { this._muteBtn.style.background = '#223355'; });
|
||||
this._muteBtn.addEventListener('mouseleave', () => { this._muteBtn.style.background = 'rgba(0, 0, 0, 0.55)'; });
|
||||
this._muteBtn.addEventListener('click', () => {
|
||||
this._toggleMute();
|
||||
this._muteBtn.textContent = this._musicMuted ? '\uD83D\uDD07' : '\uD83D\uDD0A';
|
||||
|
|
@ -1764,14 +1483,12 @@ class PuzzleScene extends Phaser.Scene {
|
|||
});
|
||||
title.textContent = 'Puzzle Complete!';
|
||||
|
||||
const timeLabel = document.createElement('div');
|
||||
Object.assign(timeLabel.style, {
|
||||
const roomLabel = document.createElement('div');
|
||||
Object.assign(roomLabel.style, {
|
||||
color: '#aaccff',
|
||||
fontSize: '2.5vmin',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
fontSize: '2.2vmin',
|
||||
});
|
||||
const totalSec = Math.floor((this._completionTime || 0) / 1000);
|
||||
timeLabel.textContent = `Total Puzzle Time: ${this._formatTime(totalSec)}`;
|
||||
roomLabel.textContent = `Room: ${this.cfg.roomCode}`;
|
||||
|
||||
const btnRow = document.createElement('div');
|
||||
Object.assign(btnRow.style, {
|
||||
|
|
@ -1789,7 +1506,7 @@ class PuzzleScene extends Phaser.Scene {
|
|||
btnRow.appendChild(menuBtn);
|
||||
|
||||
overlay.appendChild(title);
|
||||
overlay.appendChild(timeLabel);
|
||||
overlay.appendChild(roomLabel);
|
||||
overlay.appendChild(btnRow);
|
||||
this._uiLayer.appendChild(overlay);
|
||||
}
|
||||
|
|
@ -1800,9 +1517,9 @@ class PuzzleScene extends Phaser.Scene {
|
|||
Object.assign(btn.style, {
|
||||
position: 'absolute',
|
||||
padding: '0.8vmin 2vmin',
|
||||
background: '#1565c0',
|
||||
background: '#1a2a4a',
|
||||
color: '#ddeeff',
|
||||
border: '1px solid #64b5f6',
|
||||
border: '1px solid #4477bb',
|
||||
borderRadius: '4px',
|
||||
fontSize: '1.6vmin',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
|
|
@ -1811,8 +1528,8 @@ class PuzzleScene extends Phaser.Scene {
|
|||
whiteSpace: 'nowrap',
|
||||
});
|
||||
// Hover effect
|
||||
btn.addEventListener('mouseenter', () => { btn.style.background = '#1e88e5'; btn.style.borderColor = '#64b5f6'; });
|
||||
btn.addEventListener('mouseleave', () => { btn.style.background = '#1565c0'; btn.style.borderColor = '#64b5f6'; });
|
||||
btn.addEventListener('mouseenter', () => { btn.style.background = '#223355'; btn.style.borderColor = '#66aaff'; });
|
||||
btn.addEventListener('mouseleave', () => { btn.style.background = '#1a2a4a'; btn.style.borderColor = '#4477bb'; });
|
||||
btn.addEventListener('click', onClick);
|
||||
return btn;
|
||||
}
|
||||
|
|
@ -1878,7 +1595,6 @@ class PuzzleScene extends Phaser.Scene {
|
|||
completed: this._completed || false,
|
||||
bgKey: this._bgKey,
|
||||
bgPath: this._bgPath,
|
||||
startTime: this._startTime,
|
||||
});
|
||||
StorageManager.save(state);
|
||||
StorageManager.saveCurrent(this.cfg.roomCode);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
class PuzzleState {
|
||||
constructor({ imageKey, imagePath, pieceCount, roomCode, cols, rows, pieces, groups, completed, bgKey, bgPath, startTime }) {
|
||||
constructor({ imageKey, imagePath, pieceCount, roomCode, cols, rows, pieces, groups, completed, bgKey, bgPath }) {
|
||||
this.imageKey = imageKey;
|
||||
this.imagePath = imagePath;
|
||||
this.pieceCount = pieceCount;
|
||||
|
|
@ -11,7 +11,6 @@ class PuzzleState {
|
|||
this.completed = completed || false;
|
||||
this.bgKey = bgKey || 'bg_dark_wood';
|
||||
this.bgPath = bgPath || 'assets/images/ui/dark_wood.jpg';
|
||||
this.startTime = startTime || Date.now();
|
||||
}
|
||||
|
||||
serialize() {
|
||||
|
|
@ -34,7 +33,6 @@ class PuzzleState {
|
|||
completed: this.completed,
|
||||
bgKey: this.bgKey,
|
||||
bgPath: this.bgPath,
|
||||
startTime: this.startTime,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||