diff --git a/.gitignore b/.gitignore index b960fea..6308c20 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ dist-ssr # Local media copies (generated by scripts/setup-dev-media.sh) public/media/unlock.mp4 public/media/artifact-room-map.jpg +public/media/ted-celebrate.png public/media/artifacts/ public/media/celebration-pop.mp3 public/media/celebration-horn.mp3 diff --git a/public/media/config.json.example b/public/media/config.json.example index 3b18ed7..1d05213 100644 --- a/public/media/config.json.example +++ b/public/media/config.json.example @@ -1,6 +1,7 @@ { "unlockVideoUrl": "/media/unlock.mp4", "mapImageUrl": "/media/artifact-room-map.jpg", + "tedCelebrateImageUrl": "/media/ted-celebrate.png", "incorrectUrl": "/media/incorrect.mp3", "unlockConfirmUrl": "/media/unlock-confirm.mp3", "celebrationPopUrl": "/media/celebration-pop.mp3", diff --git a/scripts/setup-dev-media.sh b/scripts/setup-dev-media.sh index 81382f4..c929e75 100755 --- a/scripts/setup-dev-media.sh +++ b/scripts/setup-dev-media.sh @@ -26,6 +26,14 @@ cp "$INCORRECT_SOURCE" "$DEST_DIR/incorrect.mp3" cp "$CONFIRM_SOURCE" "$DEST_DIR/unlock-confirm.mp3" python3 "$ROOT/scripts/extract-artifact-room-map.py" "$PDF_SOURCE" "$DEST_DIR/artifact-room-map.jpg" python3 "$ROOT/scripts/extract-artifact-images.py" "$PDF_SOURCE" "$DEST_DIR/artifacts" +TED_CELEBRATE_SOURCE="${TED_CELEBRATE_SOURCE:-$SOURCE_DIR/ted-celebrate.png}" +if [[ -f "$TED_CELEBRATE_SOURCE" ]]; then + cp "$TED_CELEBRATE_SOURCE" "$DEST_DIR/ted-celebrate.png" +elif [[ -f "$ROOT/public/media/ted-celebrate.png" ]]; then + cp "$ROOT/public/media/ted-celebrate.png" "$DEST_DIR/ted-celebrate.png" +else + echo "Warning: ted-celebrate.png not found; puzzle 2 celebration image will be missing" >&2 +fi cp "$ROOT/public/media/config.json.example" "$DEST_DIR/config.json" echo "Copied media to $DEST_DIR/" diff --git a/scripts/setup-prod-media.sh b/scripts/setup-prod-media.sh index 903694d..adcda30 100755 --- a/scripts/setup-prod-media.sh +++ b/scripts/setup-prod-media.sh @@ -26,10 +26,19 @@ cp "$INCORRECT_SOURCE" "$DEST/incorrect.mp3" cp "$CONFIRM_SOURCE" "$DEST/unlock-confirm.mp3" python3 "$ROOT/scripts/extract-artifact-room-map.py" "$PDF_SOURCE" "$DEST/artifact-room-map.jpg" python3 "$ROOT/scripts/extract-artifact-images.py" "$PDF_SOURCE" "$DEST/artifacts" +TED_CELEBRATE_SOURCE="${TED_CELEBRATE_SOURCE:-$SOURCE_DIR/ted-celebrate.png}" +if [[ -f "$TED_CELEBRATE_SOURCE" ]]; then + cp "$TED_CELEBRATE_SOURCE" "$DEST/ted-celebrate.png" +elif [[ -f "$ROOT/public/media/ted-celebrate.png" ]]; then + cp "$ROOT/public/media/ted-celebrate.png" "$DEST/ted-celebrate.png" +else + echo "Warning: ted-celebrate.png not found; puzzle 2 celebration image will be missing" >&2 +fi cat >"$DEST/config.json" <<'EOF' { "unlockVideoUrl": "/media/unlock.mp4", "mapImageUrl": "/media/artifact-room-map.jpg", + "tedCelebrateImageUrl": "/media/ted-celebrate.png", "incorrectUrl": "/media/incorrect.mp3", "unlockConfirmUrl": "/media/unlock-confirm.mp3", "celebrationPopUrl": "/media/celebration-pop.mp3", diff --git a/src/App.css b/src/App.css index cf46c7a..ee42aa3 100644 --- a/src/App.css +++ b/src/App.css @@ -487,10 +487,15 @@ .artifact-bank__grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); - gap: 0.65rem; - max-height: 28rem; - overflow-y: auto; + grid-template-columns: repeat(auto-fill, minmax(8.75rem, 1fr)); + gap: 0.75rem; +} + +@media (max-width: 52rem) { + .artifact-bank__grid { + max-height: 28rem; + overflow-y: auto; + } } .path-slots { @@ -503,8 +508,8 @@ display: flex; align-items: center; gap: 0.65rem; - min-height: 4.5rem; - padding: 0.5rem 0.65rem; + min-height: 5.5rem; + padding: 0.55rem 0.75rem; background: linear-gradient(180deg, #2a2218 0%, #1f1a14 100%); border: 2px solid #4a3f32; border-radius: 0.5rem; @@ -561,7 +566,7 @@ } .artifact-card--overlay { - width: 6.5rem; + width: 8.75rem; opacity: 0.95; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); cursor: grabbing; @@ -575,8 +580,8 @@ } .artifact-card__image { - width: 3.25rem; - height: 3.25rem; + width: 5rem; + height: 5rem; object-fit: contain; flex-shrink: 0; background: #fff; @@ -584,12 +589,17 @@ } .path-slot .artifact-card__image { - width: 2.75rem; - height: 2.75rem; + width: 4rem; + height: 4rem; +} + +.artifact-card--overlay .artifact-card__image { + width: 5rem; + height: 5rem; } .artifact-card__name { - font-size: 0.78rem; + font-size: 0.85rem; line-height: 1.25; color: #f4e4bc; text-align: center; @@ -605,17 +615,110 @@ margin-top: 0.25rem; } -.museum-path__success { - margin: 0.25rem 0 0; - padding: 0.85rem 1.25rem; - font-family: Cinzel, Georgia, serif; - font-size: 1.1rem; - font-weight: 600; - letter-spacing: 0.04em; - color: #e8c547; - text-align: center; - background: rgba(92, 68, 28, 0.5); - border: 1px solid rgba(201, 162, 39, 0.55); - border-radius: 0.5rem; - animation: error-pop 0.25s ease-out; +.museum-path-panel--fade-out { + opacity: 0; + transform: scale(0.98); + pointer-events: none; + transition: + opacity 0.65s ease-out, + transform 0.65s ease-out; +} + +.museum-path-celebration { + position: fixed; + inset: 0; + z-index: 200; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} + +.museum-path-celebration--fade-in { + opacity: 0; + animation: museum-celebration-in 0.9s ease-out 0.35s forwards; +} + +@keyframes museum-celebration-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.museum-path-celebration__bg { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + object-position: center top; +} + +.museum-path-celebration__scrim { + position: absolute; + inset: 0; + background: linear-gradient( + 180deg, + rgba(26, 21, 16, 0.35) 0%, + rgba(26, 21, 16, 0.55) 45%, + rgba(26, 21, 16, 0.72) 100% + ); +} + +.museum-path-celebration__content { + position: relative; + z-index: 1; + max-width: 36rem; + margin: 0 1.5rem; + padding: 2rem 2.25rem; + text-align: center; + background: rgba(45, 36, 25, 0.72); + border: 3px solid #c9a227; + border-radius: 1rem; + box-shadow: + inset 0 0 0 1px rgba(232, 197, 71, 0.35), + 0 16px 48px rgba(0, 0, 0, 0.5); + animation: museum-celebration-content-in 0.8s ease-out 0.7s both; +} + +@keyframes museum-celebration-content-in { + from { + opacity: 0; + transform: translateY(1.25rem) scale(0.96); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +.museum-path-celebration__eyebrow { + margin: 0 0 0.65rem; + font-family: Cinzel, Georgia, serif; + font-size: clamp(1rem, 2.5vw, 1.2rem); + font-weight: 600; + letter-spacing: 0.14em; + text-transform: uppercase; + color: #e8c547; +} + +.museum-path-celebration__title { + margin: 0 0 0.85rem; + font-family: Cinzel, Georgia, serif; + font-size: clamp(2rem, 6vw, 3rem); + font-weight: 700; + line-height: 1.15; + letter-spacing: 0.04em; + color: #f4e4bc; + text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45); +} + +.museum-path-celebration__subtitle { + margin: 0; + font-size: clamp(1rem, 2.5vw, 1.15rem); + line-height: 1.45; + color: #c9b896; } diff --git a/src/MuseumPathCelebration.tsx b/src/MuseumPathCelebration.tsx new file mode 100644 index 0000000..8f170a1 --- /dev/null +++ b/src/MuseumPathCelebration.tsx @@ -0,0 +1,22 @@ +interface MuseumPathCelebrationProps { + imageUrl: string; +} + +export function MuseumPathCelebration({ imageUrl }: MuseumPathCelebrationProps) { + return ( +
You did it!
+You found the right path through the displays.
+@@ -296,19 +309,14 @@ export function MuseumPathPuzzle() {
)} - {phase === 'solved' ? ( -- You found the path! Ted escaped the museum! -
- ) : ( - - )} +