From ad7a2b8250cd875051a270f1add044f626f32073 Mon Sep 17 00:00:00 2001 From: jessikitty Date: Tue, 19 May 2026 21:46:19 +1000 Subject: [PATCH] feat(1.3.0): vintage Polaroid pile theme, filmstrip video frame, floating animation, warm vignette --- public/css/style.css | 557 ++++++++++--------------------------------- 1 file changed, 123 insertions(+), 434 deletions(-) diff --git a/public/css/style.css b/public/css/style.css index 60c69e7..dbb3393 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1,449 +1,138 @@ -/* === Reset & Base === */ -*, *::before, *::after { - margin: 0; - padding: 0; - box-sizing: border-box; -} +/* === Reset === */ +*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } +html, body { width: 100%; height: 100%; overflow: hidden; background: #1a1510; color: #fff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; cursor: none; } +body.setup-mode { cursor: default; } +.screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } -html, body { - width: 100%; - height: 100%; - overflow: hidden; - background: #000; - color: #fff; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; - -webkit-font-smoothing: antialiased; - cursor: none; -} +/* === SETUP === */ +#setup-screen { background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%); display: flex; align-items: center; justify-content: center; cursor: default; } +.setup-container { width: 90%; max-width: 600px; max-height: 90vh; overflow-y: auto; padding: 2rem; } +.setup-header { text-align: center; margin-bottom: 2rem; } +.setup-header h1 { font-size: 2.2rem; font-weight: 300; letter-spacing: 0.05em; margin-bottom: 0.5rem; } +.setup-logo { width: 96px; height: 96px; margin-bottom: 0.75rem; border-radius: 16px; } +.subtitle { font-size: 0.95rem; color: #888; } +.subtitle.connected { color: #4ade80; } +.section h2 { font-size: 1rem; font-weight: 500; color: #aaa; text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: 1rem; } +.source-buttons { display: flex; gap: 0.75rem; margin-bottom: 1rem; } +.source-btn { flex: 1; padding: 1rem; background: rgba(255,255,255,0.06); border: 2px solid rgba(255,255,255,0.1); border-radius: 12px; color: #fff; font-size: 0.95rem; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 0.5rem; transition: all 0.2s ease; } +.source-btn:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.25); } +.source-btn.selected { background: rgba(99,102,241,0.2); border-color: #6366f1; } +.source-icon { font-size: 1.5rem; } +.albums-list { max-height: 300px; overflow-y: auto; margin-bottom: 1.5rem; } +.loading-text { text-align: center; color: #666; padding: 1rem; } +.album-item { display: flex; align-items: center; gap: 1rem; padding: 0.75rem 1rem; background: rgba(255,255,255,0.04); border: 2px solid transparent; border-radius: 10px; margin-bottom: 0.5rem; cursor: pointer; transition: all 0.2s ease; animation: fadeIn 0.3s ease forwards; } +.album-item:hover { background: rgba(255,255,255,0.08); } +.album-item.selected { background: rgba(99,102,241,0.15); border-color: #6366f1; } +.album-thumb { width: 48px; height: 48px; border-radius: 8px; object-fit: cover; background: #222; } +.album-info { flex: 1; } +.album-name { font-size: 1rem; font-weight: 500; } +.album-count { font-size: 0.8rem; color: #888; margin-top: 2px; } +.start-btn { display: block; width: 100%; padding: 1rem; background: #6366f1; border: none; border-radius: 12px; color: #fff; font-size: 1.1rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; } +.start-btn:hover:not(:disabled) { background: #4f46e5; transform: translateY(-1px); } +.start-btn:disabled { opacity: 0.3; cursor: not-allowed; } +.setup-error { text-align: center; padding: 2rem; } +.setup-error p { margin-bottom: 0.75rem; } +.setup-error .error-detail { color: #888; font-size: 0.85rem; } +.setup-error button { margin-top: 1rem; padding: 0.75rem 2rem; background: #6366f1; border: none; border-radius: 8px; color: #fff; font-size: 1rem; cursor: pointer; } +.spinner { display: inline-block; width: 24px; height: 24px; border: 2px solid rgba(255,255,255,0.2); border-top-color: #fff; border-radius: 50%; animation: spin 0.8s linear infinite; margin-right: 0.5rem; vertical-align: middle; } +@keyframes spin { to { transform: rotate(360deg); } } +@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } -body.setup-mode { - cursor: default; -} - -/* === Screens === */ -.screen { - position: absolute; - top: 0; left: 0; - width: 100%; height: 100%; -} - -/* === Setup Screen === */ -#setup-screen { - background: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 50%, #16213e 100%); - display: flex; - align-items: center; - justify-content: center; - cursor: default; -} - -.setup-container { - width: 90%; - max-width: 600px; - max-height: 90vh; - overflow-y: auto; - padding: 2rem; -} - -.setup-header { - text-align: center; - margin-bottom: 2rem; -} - -.setup-header h1 { - font-size: 2.2rem; - font-weight: 300; - letter-spacing: 0.05em; - margin-bottom: 0.5rem; -} - -.subtitle { - font-size: 0.95rem; - color: #888; -} - -.subtitle.connected { - color: #4ade80; -} - -.subtitle.error { - color: #f87171; -} - -/* === Source Buttons === */ -.section h2 { - font-size: 1rem; - font-weight: 500; - color: #aaa; - text-transform: uppercase; - letter-spacing: 0.1em; - margin-bottom: 1rem; -} - -.source-buttons { - display: flex; - gap: 0.75rem; - margin-bottom: 1rem; -} - -.source-btn { - flex: 1; - padding: 1rem; - background: rgba(255, 255, 255, 0.06); - border: 2px solid rgba(255, 255, 255, 0.1); - border-radius: 12px; - color: #fff; - font-size: 0.95rem; - cursor: pointer; - display: flex; - flex-direction: column; - align-items: center; - gap: 0.5rem; - transition: all 0.2s ease; -} - -.source-btn:hover { - background: rgba(255, 255, 255, 0.1); - border-color: rgba(255, 255, 255, 0.25); -} - -.source-btn.selected { - background: rgba(99, 102, 241, 0.2); - border-color: #6366f1; -} - -.source-icon { - font-size: 1.5rem; -} - -/* === Albums List === */ -.albums-list { - max-height: 300px; - overflow-y: auto; - margin-bottom: 1.5rem; -} - -.loading-text { - text-align: center; - color: #666; - padding: 1rem; -} - -.album-item { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.75rem 1rem; - background: rgba(255, 255, 255, 0.04); - border: 2px solid transparent; - border-radius: 10px; - margin-bottom: 0.5rem; - cursor: pointer; - transition: all 0.2s ease; -} - -.album-item:hover { - background: rgba(255, 255, 255, 0.08); -} - -.album-item.selected { - background: rgba(99, 102, 241, 0.15); - border-color: #6366f1; -} - -.album-thumb { - width: 48px; - height: 48px; - border-radius: 8px; - object-fit: cover; - background: #222; -} - -.album-info { - flex: 1; -} - -.album-name { - font-size: 1rem; - font-weight: 500; -} - -.album-count { - font-size: 0.8rem; - color: #888; - margin-top: 2px; -} - -/* === Start Button === */ -.start-btn { - display: block; - width: 100%; - padding: 1rem; - background: #6366f1; - border: none; - border-radius: 12px; - color: #fff; - font-size: 1.1rem; - font-weight: 600; - cursor: pointer; - transition: all 0.2s ease; - letter-spacing: 0.03em; -} - -.start-btn:hover:not(:disabled) { - background: #4f46e5; - transform: translateY(-1px); -} - -.start-btn:disabled { - opacity: 0.3; - cursor: not-allowed; -} - -/* === Setup Error === */ -.setup-error { - text-align: center; - padding: 2rem; -} - -.setup-error p { - margin-bottom: 0.75rem; -} - -.error-detail { - color: #888; - font-size: 0.85rem; -} - -.setup-error button { - margin-top: 1rem; - padding: 0.75rem 2rem; - background: #6366f1; - border: none; - border-radius: 8px; - color: #fff; - font-size: 1rem; - cursor: pointer; -} - -/* === Slideshow === */ -#slideshow-screen { - background: #000; -} +/* === SLIDESHOW - VINTAGE POLAROID PILE === */ +#slideshow-screen { background: #1a1510; } .bg-blur { - position: absolute; - top: -20px; left: -20px; - width: calc(100% + 40px); - height: calc(100% + 40px); - background-size: cover; - background-position: center; - filter: blur(30px) brightness(0.35); - opacity: 0; - transition: opacity 1.5s ease; - z-index: 1; + position: absolute; top: -30px; left: -30px; + width: calc(100% + 60px); height: calc(100% + 60px); + background-size: cover; background-position: center; + filter: blur(40px) brightness(0.3) saturate(0.6) sepia(0.3); + opacity: 0; transition: opacity 2s ease; z-index: 1; +} +.bg-blur.visible { opacity: 1; } + +.bg-vignette { + position: absolute; top: 0; left: 0; width: 100%; height: 100%; + background: radial-gradient(ellipse at center, transparent 40%, rgba(15,12,8,0.7) 100%); + z-index: 2; pointer-events: none; } -.bg-blur.visible { - opacity: 1; +/* --- Photo pile --- */ +#photo-pile { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 3; pointer-events: none; } +.pile-frame { position: absolute; top: 50%; left: 50%; width: 30vmin; height: 34vmin; transform: translate(-50%, -50%); opacity: 0; transition: all 1.5s ease; pointer-events: none; } +.pile-frame.visible { opacity: 1; } + +/* --- Main floating frame --- */ +.main-frame { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 5; opacity: 0; transition: opacity 1.2s ease; animation: float 25s ease-in-out infinite; } +.main-frame.visible { opacity: 1; } + +@keyframes float { + 0% { transform: translate(-50%, -50%) rotate(0deg) translateX(0) translateY(0); } + 15% { transform: translate(-50%, -50%) rotate(0.8deg) translateX(8px) translateY(-5px); } + 30% { transform: translate(-50%, -50%) rotate(-0.5deg) translateX(-5px) translateY(6px); } + 50% { transform: translate(-50%, -50%) rotate(0.3deg) translateX(6px) translateY(3px); } + 65% { transform: translate(-50%, -50%) rotate(-0.7deg) translateX(-8px) translateY(-4px); } + 80% { transform: translate(-50%, -50%) rotate(0.4deg) translateX(4px) translateY(7px); } + 100% { transform: translate(-50%, -50%) rotate(0deg) translateX(0) translateY(0); } } -.photo-layer { - position: absolute; - top: 0; left: 0; - width: 100%; height: 100%; - background-size: contain; - background-position: center; - background-repeat: no-repeat; - opacity: 0; - transition: opacity 2s ease; - z-index: 2; +/* Polaroid */ +.main-frame.polaroid .frame-border { + background: #f5f0e8; padding: 12px 12px 44px 12px; + box-shadow: 0 4px 30px rgba(0,0,0,0.5), 0 1px 3px rgba(0,0,0,0.2), inset 0 0 0 1px rgba(0,0,0,0.05); + border-radius: 2px; position: relative; +} +.main-frame.polaroid .frame-media { display: block; max-width: 72vmin; max-height: 54vmin; width: auto; height: auto; object-fit: contain; background: #2a2520; min-width: 40vmin; min-height: 30vmin; } +.main-frame.polaroid .filmstrip-top, .main-frame.polaroid .filmstrip-bottom { display: none; } + +/* Film strip */ +.main-frame.filmstrip .frame-border { + background: #1a1a1a; padding: 0; + box-shadow: 0 4px 30px rgba(0,0,0,0.5), 0 1px 3px rgba(0,0,0,0.2); + border-radius: 2px; position: relative; +} +.main-frame.filmstrip .frame-media { display: block; max-width: 72vmin; max-height: 54vmin; width: auto; height: auto; object-fit: contain; background: #000; min-width: 40vmin; min-height: 30vmin; } + +.filmstrip-top, .filmstrip-bottom { display: none; position: absolute; left: 0; width: 100%; height: 22px; background: #1a1a1a; z-index: 6; } +.filmstrip-top { top: -22px; border-radius: 2px 2px 0 0; } +.filmstrip-bottom { bottom: -22px; border-radius: 0 0 2px 2px; } +.main-frame.filmstrip .filmstrip-top, .main-frame.filmstrip .filmstrip-bottom { + display: block; + background-image: repeating-linear-gradient(90deg, transparent 0px, transparent 10px, #333 10px, #333 12px, transparent 12px, transparent 16px, rgba(255,255,255,0.08) 16px, rgba(255,255,255,0.08) 26px, transparent 26px, transparent 28px, #333 28px, #333 30px, transparent 30px, transparent 40px); + background-size: 40px 22px; background-position: 5px center; } -.photo-layer.active { - opacity: 1; -} +/* === OVERLAY === */ +.overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10; pointer-events: none; opacity: 1; transition: opacity 0.5s ease; } +.overlay.hidden { opacity: 0; } +.overlay-top-right { position: absolute; top: 1.5rem; right: 2rem; text-align: right; text-shadow: 0 2px 8px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6); } +.clock { font-size: 2.5rem; font-weight: 200; letter-spacing: 0.05em; line-height: 1.2; } +.date-display { font-size: 0.95rem; font-weight: 300; color: rgba(255,255,255,0.8); margin-top: 0.25rem; } +.overlay-bottom { position: absolute; bottom: 0; left: 0; width: 100%; padding: 1.5rem 2rem 1rem; background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 100%); } +.exif-info { font-size: 0.85rem; font-weight: 300; color: rgba(255,255,255,0.75); margin-bottom: 0.75rem; text-shadow: 0 1px 4px rgba(0,0,0,0.8); } +.progress-bar { width: 100%; height: 3px; background: rgba(255,255,255,0.15); border-radius: 2px; overflow: hidden; } +.progress-fill { height: 100%; width: 0%; background: rgba(255,255,255,0.5); border-radius: 2px; transition: width 0.3s linear; } -/* === Overlay === */ -.overlay { - position: absolute; - top: 0; left: 0; - width: 100%; height: 100%; - z-index: 10; - pointer-events: none; - opacity: 1; - transition: opacity 0.5s ease; -} +/* === CONTROLS === */ +.touch-zone { position: absolute; top: 0; height: 100%; z-index: 20; cursor: pointer; } +.touch-left { left: 0; width: 20%; } +.touch-center { left: 20%; width: 60%; } +.touch-right { right: 0; width: 20%; } +.settings-btn { position: absolute; top: 1rem; left: 1rem; width: 44px; height: 44px; background: rgba(0,0,0,0.5); border: 1px solid rgba(255,255,255,0.2); border-radius: 50%; color: #fff; font-size: 1.2rem; cursor: pointer; z-index: 30; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; } +.settings-btn.visible { opacity: 1; pointer-events: auto; } -.overlay.hidden { - opacity: 0; -} - -.overlay-top-right { - position: absolute; - top: 1.5rem; - right: 2rem; - text-align: right; - text-shadow: 0 2px 8px rgba(0, 0, 0, 0.8), 0 0 20px rgba(0, 0, 0, 0.5); -} - -.clock { - font-size: 2.5rem; - font-weight: 200; - letter-spacing: 0.05em; - line-height: 1.2; -} - -.date-display { - font-size: 0.95rem; - font-weight: 300; - color: rgba(255, 255, 255, 0.8); - margin-top: 0.25rem; -} - -.overlay-bottom { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - padding: 1.5rem 2rem 1rem; - background: linear-gradient(to top, rgba(0,0,0,0.6) 0%, transparent 100%); -} - -.exif-info { - font-size: 0.85rem; - font-weight: 300; - color: rgba(255, 255, 255, 0.75); - margin-bottom: 0.75rem; - text-shadow: 0 1px 4px rgba(0, 0, 0, 0.8); -} - -.progress-bar { - width: 100%; - height: 3px; - background: rgba(255, 255, 255, 0.15); - border-radius: 2px; - overflow: hidden; -} - -.progress-fill { - height: 100%; - width: 0%; - background: rgba(255, 255, 255, 0.5); - border-radius: 2px; - transition: width 0.3s linear; -} - -/* === Touch Zones === */ -.touch-zone { - position: absolute; - top: 0; - height: 100%; - z-index: 20; - cursor: pointer; -} - -.touch-left { - left: 0; - width: 20%; -} - -.touch-center { - left: 20%; - width: 60%; -} - -.touch-right { - right: 0; - width: 20%; -} - -/* === Settings Button === */ -.settings-btn { - position: absolute; - top: 1rem; - left: 1rem; - width: 44px; - height: 44px; - background: rgba(0, 0, 0, 0.5); - border: 1px solid rgba(255, 255, 255, 0.2); - border-radius: 50%; - color: #fff; - font-size: 1.2rem; - cursor: pointer; - z-index: 30; - opacity: 0; - transition: opacity 0.3s ease; - pointer-events: none; -} - -.settings-btn.visible { - opacity: 1; - pointer-events: auto; -} - -/* === Scrollbar Styling === */ -.albums-list::-webkit-scrollbar, -.setup-container::-webkit-scrollbar { - width: 6px; -} - -.albums-list::-webkit-scrollbar-track, -.setup-container::-webkit-scrollbar-track { - background: transparent; -} - -.albums-list::-webkit-scrollbar-thumb, -.setup-container::-webkit-scrollbar-thumb { - background: rgba(255, 255, 255, 0.15); - border-radius: 3px; -} - -/* === Responsive === */ +/* === RESPONSIVE === */ @media (max-width: 600px) { - .setup-container { - padding: 1.25rem; - } - .setup-header h1 { - font-size: 1.6rem; - } - .clock { - font-size: 1.8rem; - } - .overlay-top-right { - top: 1rem; - right: 1rem; - } - .overlay-bottom { - padding: 1rem 1rem 0.5rem; - } - .source-buttons { - flex-direction: column; - } + .setup-container { padding: 1.25rem; } + .setup-header h1 { font-size: 1.6rem; } + .clock { font-size: 1.8rem; } + .overlay-top-right { top: 1rem; right: 1rem; } + .overlay-bottom { padding: 1rem 1rem 0.5rem; } + .source-buttons { flex-direction: column; } + .main-frame.polaroid .frame-border { padding: 8px 8px 32px 8px; } + .main-frame.polaroid .frame-media, .main-frame.filmstrip .frame-media { max-width: 85vmin; max-height: 60vmin; } + .pile-frame { width: 25vmin; height: 29vmin; } } -/* === Loading Spinner === */ -.spinner { - display: inline-block; - width: 24px; - height: 24px; - border: 2px solid rgba(255,255,255,0.2); - border-top-color: #fff; - border-radius: 50%; - animation: spin 0.8s linear infinite; - margin-right: 0.5rem; - vertical-align: middle; -} - -@keyframes spin { - to { transform: rotate(360deg); } -} - -/* === Fade-in Animation === */ -@keyframes fadeIn { - from { opacity: 0; transform: translateY(10px); } - to { opacity: 1; transform: translateY(0); } -} - -.album-item { - animation: fadeIn 0.3s ease forwards; -} +.albums-list::-webkit-scrollbar, .setup-container::-webkit-scrollbar { width: 6px; } +.albums-list::-webkit-scrollbar-track, .setup-container::-webkit-scrollbar-track { background: transparent; } +.albums-list::-webkit-scrollbar-thumb, .setup-container::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 3px; }