${monument.name}
+${monument.subtitle}
+ +${monument.description}
+ +diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc194d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.DS_Store +*.log +.env +dist/ +tmp/ diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..87b8e6d --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +dev.discoverygubbio.com \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ce92fb --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# InsideGubbio AR + +Piattaforma di realtà aumentata per esplorare i monumenti di Gubbio. + +## Funzionalità + +- **Geolocalizzazione** — Rileva automaticamente la posizione dell'utente e identifica i monumenti vicini +- **Fotocamera AR** — Inquadra i monumenti per attivare l'esperienza in realtà aumentata +- **Audio guide** — Ascolta le storie di ogni monumento con il toggle audio +- **Pannello informativo** — Leggi descrizioni dettagliate che compaiono dal basso +- **Personaggi storici** — Incontra personaggi legati a ogni monumento +- **Decorazioni AR** — Particelle ed effetti visivi unici per ogni monumento +- **Percorsi guidati** — Scegli tra diversi itinerari tematici + +## Monumenti + +| Monumento | Epoca | Categoria | +|-----------|-------|-----------| +| Palazzo dei Consoli | XIV secolo | Palazzo | +| Basilica di Sant'Ubaldo | XVI secolo | Chiesa | +| Teatro Romano | I secolo a.C. | Archeologico | +| Palazzo Ducale | XV secolo | Palazzo | +| Fontana dei Matti | XIV secolo | Fontana | +| Chiesa di San Francesco | XIII secolo | Chiesa | + +## Struttura + +``` +├── index.html # Pagina principale (SPA) +├── css/ +│ └── style.css # Stili dell'applicazione +├── js/ +│ ├── app.js # Logica principale e navigazione +│ ├── ar.js # Engine AR (fotocamera, overlay, particelle) +│ └── monuments.js # Servizio dati monumenti +├── api/ +│ └── monuments.json # Dati dei monumenti e percorsi +└── assets/ + ├── audio/ # File audio delle guide (da caricare) + └── images/ # Immagini (da caricare) +``` + +## Utilizzo + +1. Apri `index.html` in un browser (o servila con un server HTTP) +2. Dalla home, tocca **Avvia AR** per la modalità automatica con GPS +3. Oppure tocca **Esplora monumenti** per scegliere un monumento specifico +4. Nella vista AR: + - **Audio** — Attiva/disattiva la guida audio + - **Info** — Mostra il pannello con la descrizione completa + - **Personaggio** — Mostra/nascondi il personaggio storico + +## Aggiungere contenuti + +### Audio +Carica i file audio MP3 nella cartella `assets/audio/` con i nomi specificati in `api/monuments.json`. + +### Testi +Modifica le descrizioni in `api/monuments.json` per aggiornare i testi di ogni monumento. + +## Requisiti + +- Browser moderno con supporto a: + - Geolocation API + - MediaDevices API (fotocamera) + - CSS backdrop-filter +- Connessione HTTPS (richiesta per fotocamera e geolocalizzazione) + +## Sviluppo + +Servire i file con un server HTTP locale: + +```bash +# Con Python +python3 -m http.server 8000 + +# Con Node.js +npx serve . +``` + +## Design + +Il design è ispirato a [insidegubbio.framer.website](https://insidegubbio.framer.website), con: +- Palette scura ed elegante +- Accenti dorati e colori per categoria +- Tipografia serif per i titoli (Playfair Display) +- Animazioni fluide e transizioni morbide +- UI ottimizzata per dispositivi mobili diff --git a/api/monuments.json b/api/monuments.json new file mode 100644 index 0000000..68ff386 --- /dev/null +++ b/api/monuments.json @@ -0,0 +1,144 @@ +{ + "monuments": [ + { + "id": "palazzo-dei-consoli", + "name": "Palazzo dei Consoli", + "subtitle": "Il simbolo di Gubbio", + "description": "Il Palazzo dei Consoli è uno dei più imponenti edifici pubblici medievali d'Italia. Costruito tra il 1332 e il 1349 su progetto attribuito a Angelo da Orvieto, domina Piazza Grande con la sua maestosa facciata in pietra bianca. Ospita il Museo Civico con le celebri Tavole Iguvine, sette lastre di bronzo con iscrizioni in lingua umbra risalenti al III-I secolo a.C.", + "shortDescription": "Imponente palazzo medievale del XIV secolo, simbolo della città e sede del Museo Civico.", + "lat": 43.35150, + "lng": 12.57740, + "radius": 100, + "audioFile": "assets/audio/palazzo-consoli.mp3", + "character": { + "name": "Angelo da Orvieto", + "role": "Architetto", + "greeting": "Benvenuto! Sono Angelo da Orvieto, l'architetto di questo magnifico palazzo. Lascia che ti racconti la sua storia..." + }, + "decorations": ["medieval-banner", "stone-particles", "golden-glow"], + "epoch": "XIV secolo", + "category": "palazzo" + }, + { + "id": "basilica-sant-ubaldo", + "name": "Basilica di Sant'Ubaldo", + "subtitle": "Il protettore di Gubbio", + "description": "La Basilica di Sant'Ubaldo si trova sulla cima del Monte Ingino, raggiungibile con una suggestiva funivia. Custodisce le spoglie del santo patrono di Gubbio, Sant'Ubaldo, e i tre Ceri, le grandi strutture di legno protagoniste della celebre Corsa dei Ceri che si tiene ogni 15 maggio. La chiesa attuale risale al XVI secolo.", + "shortDescription": "Basilica sul Monte Ingino che custodisce le spoglie del patrono e i famosi Ceri.", + "lat": 43.35570, + "lng": 12.58110, + "radius": 150, + "audioFile": "assets/audio/basilica-ubaldo.mp3", + "character": { + "name": "Sant'Ubaldo", + "role": "Patrono di Gubbio", + "greeting": "Pace a te, visitatore. Sono Ubaldo, vescovo e protettore di questa città. Ti svelerò i segreti di questo luogo sacro..." + }, + "decorations": ["candlelight", "sacred-glow", "dove-particles"], + "epoch": "XVI secolo", + "category": "chiesa" + }, + { + "id": "teatro-romano", + "name": "Teatro Romano", + "subtitle": "L'eredità di Roma", + "description": "Il Teatro Romano di Gubbio, costruito nel I secolo a.C., è uno dei teatri romani meglio conservati dell'Umbria. Con un diametro di circa 70 metri, poteva ospitare fino a 6.000 spettatori. Ancora oggi viene utilizzato per spettacoli estivi, mantenendo viva una tradizione che dura da oltre duemila anni.", + "shortDescription": "Antico teatro del I secolo a.C., ancora oggi utilizzato per spettacoli dal vivo.", + "lat": 43.34860, + "lng": 12.57970, + "radius": 120, + "audioFile": "assets/audio/teatro-romano.mp3", + "character": { + "name": "Centurione Marco", + "role": "Centurione Romano", + "greeting": "Ave! Sono il Centurione Marco. Questo teatro ha visto duemila anni di storia. Lascia che ti guidi..." + }, + "decorations": ["roman-columns", "laurel-particles", "marble-glow"], + "epoch": "I secolo a.C.", + "category": "archeologico" + }, + { + "id": "palazzo-ducale", + "name": "Palazzo Ducale", + "subtitle": "La corte dei Montefeltro", + "description": "Il Palazzo Ducale di Gubbio fu fatto costruire da Federico da Montefeltro nel 1470, ispirandosi al più celebre Palazzo Ducale di Urbino. Il cortile rinascimentale è un gioiello architettonico. Il palazzo ospita oggi un museo con arredi e opere d'arte che testimoniano lo splendore della corte dei Montefeltro.", + "shortDescription": "Elegante palazzo rinascimentale voluto da Federico da Montefeltro nel 1470.", + "lat": 43.35270, + "lng": 12.57820, + "radius": 80, + "audioFile": "assets/audio/palazzo-ducale.mp3", + "character": { + "name": "Federico da Montefeltro", + "role": "Duca di Urbino", + "greeting": "Benvenuto nella mia dimora eugubina! Sono Federico da Montefeltro. Scopri con me le meraviglie di questo palazzo..." + }, + "decorations": ["renaissance-frame", "gold-particles", "noble-glow"], + "epoch": "XV secolo", + "category": "palazzo" + }, + { + "id": "fontana-dei-matti", + "name": "Fontana dei Matti", + "subtitle": "La tradizione più pazza", + "description": "La Fontana del Bargello, nota come Fontana dei Matti, è una piccola fontana situata in Via dei Consoli. Secondo la tradizione, chi gira tre volte intorno alla fontana riceve la 'patente da matto', un documento goliardico rilasciato dal Comune. È uno dei simboli più amati e divertenti di Gubbio.", + "shortDescription": "La celebre fontana dove si ottiene la 'patente da matto' girando tre volte intorno.", + "lat": 43.35190, + "lng": 12.57710, + "radius": 60, + "audioFile": "assets/audio/fontana-matti.mp3", + "character": { + "name": "Il Matto di Gubbio", + "role": "Giullare", + "greeting": "Ahah! Benvenuto, amico! Sei pronto per diventare matto? Gira tre volte e la patente sarà tua!" + }, + "decorations": ["water-splash", "confetti-particles", "rainbow-glow"], + "epoch": "XIV secolo", + "category": "fontana" + }, + { + "id": "chiesa-san-francesco", + "name": "Chiesa di San Francesco", + "subtitle": "Il luogo del lupo", + "description": "La Chiesa di San Francesco sorge nel luogo dove, secondo la tradizione, San Francesco ammansì il lupo di Gubbio. Costruita nel XIII secolo in stile gotico, conserva affreschi di Ottaviano Nelli e altri pittori eugubini. La chiesa è un importante testimonianza del legame tra Gubbio e il santo di Assisi.", + "shortDescription": "Chiesa gotica del XIII secolo legata alla leggenda di San Francesco e il lupo.", + "lat": 43.34980, + "lng": 12.57580, + "radius": 90, + "audioFile": "assets/audio/chiesa-francesco.mp3", + "character": { + "name": "San Francesco", + "role": "Santo", + "greeting": "Pace e bene, fratello! Qui ammansii il lupo che terrorizzava Gubbio. Lascia che ti racconti questa storia..." + }, + "decorations": ["wolf-shadow", "leaf-particles", "holy-glow"], + "epoch": "XIII secolo", + "category": "chiesa" + } + ], + "routes": [ + { + "id": "percorso-medievale", + "name": "Gubbio Medievale", + "description": "Scopri i tesori del Medioevo eugubino", + "monuments": ["palazzo-dei-consoli", "fontana-dei-matti", "palazzo-ducale"], + "duration": "45 min", + "distance": "1.2 km" + }, + { + "id": "percorso-completo", + "name": "Grand Tour di Gubbio", + "description": "Il percorso completo attraverso tutti i monumenti", + "monuments": ["teatro-romano", "chiesa-san-francesco", "fontana-dei-matti", "palazzo-dei-consoli", "palazzo-ducale", "basilica-sant-ubaldo"], + "duration": "2 ore", + "distance": "4.5 km" + }, + { + "id": "percorso-spirituale", + "name": "Gubbio Sacra", + "description": "Un viaggio tra fede e storia", + "monuments": ["chiesa-san-francesco", "basilica-sant-ubaldo"], + "duration": "1.5 ore", + "distance": "3.2 km" + } + ] +} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..58da6cd --- /dev/null +++ b/css/style.css @@ -0,0 +1,1299 @@ +/* =================================================== + InsideGubbio AR — Stylesheet + Design inspired by insidegubbio.framer.website + =================================================== */ + +/* ---------- CSS Variables ---------- */ +:root { + --bg: #0a0a0f; + --bg-card: #12121a; + --bg-surface: #1a1a26; + --text: #f0ede6; + --text-dim: #8a8698; + --text-muted: #5a5670; + --accent: #d4a04a; + --accent-glow: rgba(212, 160, 74, 0.3); + --cat-palazzo: #d4a04a; + --cat-chiesa: #a08cd4; + --cat-archeologico: #7cb4a0; + --cat-fontana: #5b9bd5; + --radius: 16px; + --radius-sm: 10px; + --radius-xs: 6px; + --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + --font-serif: 'Playfair Display', Georgia, serif; + --safe-bottom: env(safe-area-inset-bottom, 0px); + --safe-top: env(safe-area-inset-top, 0px); +} + +/* ---------- Reset ---------- */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + font-size: 16px; + -webkit-text-size-adjust: 100%; + scroll-behavior: smooth; +} + +body { + font-family: var(--font-sans); + background: var(--bg); + color: var(--text); + overflow-x: hidden; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* ---------- Views ---------- */ +.view { + display: none; + min-height: 100vh; + min-height: 100dvh; +} + +.view.active { + display: block; +} + +/* =================================================== + HOME PAGE + =================================================== */ + +.home-hero { + position: relative; + min-height: 100vh; + min-height: 100dvh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 2rem 1.5rem; + overflow: hidden; +} + +.home-bg-gradient { + position: absolute; + inset: 0; + background: + radial-gradient(ellipse 80% 60% at 50% 0%, rgba(212, 160, 74, 0.08) 0%, transparent 60%), + radial-gradient(ellipse 60% 40% at 80% 80%, rgba(160, 140, 212, 0.06) 0%, transparent 50%), + var(--bg); + z-index: 0; +} + +.home-particles { + position: absolute; + inset: 0; + z-index: 1; + pointer-events: none; +} + +/* Nav */ +.home-nav { + position: absolute; + top: 0; + left: 0; + right: 0; + padding: 1.2rem 1.5rem; + padding-top: calc(1.2rem + var(--safe-top)); + z-index: 10; +} + +.home-logo { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.logo-icon { + color: var(--accent); + font-size: 1.1rem; +} + +.logo-text { + font-family: var(--font-serif); + font-weight: 600; + font-size: 1.1rem; + letter-spacing: -0.02em; +} + +.logo-badge { + background: var(--accent); + color: var(--bg); + font-size: 0.6rem; + font-weight: 700; + padding: 0.15rem 0.4rem; + border-radius: 4px; + text-transform: uppercase; + letter-spacing: 0.08em; +} + +/* Hero Content */ +.home-content { + position: relative; + z-index: 2; + text-align: center; + max-width: 600px; +} + +.home-eyebrow { + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.2em; + color: var(--accent); + margin-bottom: 1.2rem; +} + +.home-title { + font-family: var(--font-serif); + font-size: clamp(2.4rem, 8vw, 4rem); + font-weight: 700; + line-height: 1.1; + letter-spacing: -0.02em; + margin-bottom: 1.2rem; +} + +.home-title em { + font-style: italic; + color: var(--accent); +} + +.home-subtitle { + font-size: 1rem; + line-height: 1.7; + color: var(--text-dim); + margin-bottom: 2.5rem; + max-width: 440px; + margin-left: auto; + margin-right: auto; +} + +/* Buttons */ +.home-actions { + display: flex; + gap: 0.8rem; + justify-content: center; + flex-wrap: wrap; +} + +.btn-primary { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.85rem 1.8rem; + background: var(--accent); + color: var(--bg); + border: none; + border-radius: 50px; + font-family: var(--font-sans); + font-size: 0.9rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + letter-spacing: -0.01em; +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 30px var(--accent-glow); +} + +.btn-primary:active { + transform: translateY(0); +} + +.btn-icon { + font-size: 1.1rem; +} + +.btn-secondary { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.85rem 1.8rem; + background: transparent; + color: var(--text); + border: 1px solid rgba(240, 237, 230, 0.15); + border-radius: 50px; + font-family: var(--font-sans); + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; +} + +.btn-secondary:hover { + border-color: var(--accent); + color: var(--accent); +} + +/* Scroll hint */ +.home-scroll-hint { + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + z-index: 2; +} + +.home-scroll-hint span { + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.15em; + color: var(--text-muted); +} + +.scroll-arrow { + width: 20px; + height: 20px; + border-right: 1.5px solid var(--text-muted); + border-bottom: 1.5px solid var(--text-muted); + transform: rotate(45deg); + animation: scrollBounce 2s ease infinite; +} + +@keyframes scrollBounce { + 0%, 100% { transform: rotate(45deg) translateY(0); opacity: 0.5; } + 50% { transform: rotate(45deg) translateY(6px); opacity: 1; } +} + +/* ===== HOME SECTIONS ===== */ +.home-section { + padding: 5rem 1.5rem; +} + +.home-section-dark { + background: var(--bg-card); +} + +.section-container { + max-width: 900px; + margin: 0 auto; +} + +.section-eyebrow { + font-size: 0.7rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.2em; + color: var(--accent); + margin-bottom: 0.8rem; +} + +.section-title { + font-family: var(--font-serif); + font-size: clamp(1.8rem, 5vw, 2.4rem); + font-weight: 700; + letter-spacing: -0.02em; + margin-bottom: 0.6rem; +} + +.section-subtitle { + color: var(--text-dim); + font-size: 0.95rem; + line-height: 1.6; + margin-bottom: 2.5rem; +} + +.section-cta { + text-align: center; + margin-top: 2.5rem; +} + +/* Steps */ +.steps-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1.5rem; + margin-top: 2.5rem; +} + +.step-card { + background: var(--bg-card); + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: var(--radius); + padding: 2rem 1.5rem; + position: relative; + transition: border-color 0.3s; +} + +.step-card:hover { + border-color: rgba(212, 160, 74, 0.2); +} + +.step-number { + font-size: 0.7rem; + font-weight: 700; + color: var(--accent); + letter-spacing: 0.1em; + margin-bottom: 1rem; +} + +.step-icon { + font-size: 2rem; + margin-bottom: 1rem; +} + +.step-card h3 { + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.step-card p { + font-size: 0.85rem; + line-height: 1.6; + color: var(--text-dim); +} + +/* Home monument preview */ +.home-monument-preview { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 1rem; + margin-top: 2rem; +} + +.home-monument-item { + background: var(--bg-surface); + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: var(--radius-sm); + padding: 1.5rem 1rem; + text-align: center; + cursor: pointer; + transition: all 0.3s ease; +} + +.home-monument-item:hover { + border-color: var(--accent); + transform: translateY(-3px); +} + +.home-monument-icon { + font-size: 2rem; + margin-bottom: 0.8rem; + filter: drop-shadow(0 0 10px var(--accent)); +} + +.home-monument-item h4 { + font-size: 0.85rem; + font-weight: 600; + margin-bottom: 0.3rem; +} + +.home-monument-item span { + font-size: 0.7rem; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.08em; +} + +/* Footer */ +.home-footer { + padding: 3rem 1.5rem; + border-top: 1px solid rgba(255, 255, 255, 0.05); +} + +.footer-content { + max-width: 900px; + margin: 0 auto; + text-align: center; +} + +.footer-content .home-logo { + justify-content: center; + margin-bottom: 0.8rem; +} + +.footer-tagline { + font-size: 0.85rem; + color: var(--text-dim); + margin-bottom: 0.5rem; +} + +.footer-copy { + font-size: 0.7rem; + color: var(--text-muted); +} + +/* =================================================== + EXPLORE PAGE + =================================================== */ + +.explore-nav { + position: sticky; + top: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.8rem 1rem; + padding-top: calc(0.8rem + var(--safe-top)); + background: rgba(10, 10, 15, 0.85); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} + +.nav-back, .nav-ar { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border: none; + background: rgba(255, 255, 255, 0.06); + border-radius: 50%; + color: var(--text); + cursor: pointer; + transition: background 0.3s; +} + +.nav-back:hover, .nav-ar:hover { + background: rgba(212, 160, 74, 0.15); + color: var(--accent); +} + +.explore-content { + padding: 1.5rem; + padding-bottom: calc(2rem + var(--safe-bottom)); + max-width: 900px; + margin: 0 auto; +} + +.explore-section { + margin-bottom: 3rem; +} + +.explore-section-title { + font-family: var(--font-serif); + font-size: 1.6rem; + font-weight: 700; + margin-bottom: 0.3rem; +} + +.explore-section-desc { + font-size: 0.85rem; + color: var(--text-dim); + margin-bottom: 1.5rem; +} + +/* Monument cards */ +.monument-grid { + display: grid; + gap: 1rem; +} + +.monument-card { + display: flex; + background: var(--bg-card); + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: var(--radius); + overflow: hidden; + cursor: pointer; + transition: all 0.3s ease; +} + +.monument-card:hover { + border-color: rgba(212, 160, 74, 0.2); + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); +} + +.monument-card-accent { + width: 4px; + flex-shrink: 0; +} + +.monument-card-body { + padding: 1.2rem; + flex: 1; +} + +.monument-card-epoch { + font-size: 0.65rem; + font-weight: 600; + color: var(--accent); + text-transform: uppercase; + letter-spacing: 0.12em; + margin-bottom: 0.4rem; +} + +.monument-card-title { + font-family: var(--font-serif); + font-size: 1.15rem; + font-weight: 600; + margin-bottom: 0.4rem; +} + +.monument-card-desc { + font-size: 0.8rem; + line-height: 1.5; + color: var(--text-dim); + margin-bottom: 0.8rem; +} + +.monument-card-footer { + display: flex; + justify-content: space-between; + align-items: center; +} + +.monument-card-category { + font-size: 0.65rem; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--text-muted); + background: rgba(255, 255, 255, 0.05); + padding: 0.2rem 0.6rem; + border-radius: 20px; +} + +.monument-card-cta { + font-size: 0.75rem; + font-weight: 600; + color: var(--accent); +} + +/* Route cards */ +.route-grid { + display: grid; + gap: 1rem; +} + +.route-card { + background: var(--bg-card); + border: 1px solid rgba(255, 255, 255, 0.05); + border-radius: var(--radius); + padding: 1.5rem; + transition: border-color 0.3s; +} + +.route-card:hover { + border-color: rgba(212, 160, 74, 0.15); +} + +.route-card-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 0.6rem; +} + +.route-card-header h3 { + font-family: var(--font-serif); + font-size: 1.1rem; + font-weight: 600; +} + +.route-card-meta { + display: flex; + gap: 0.8rem; + font-size: 0.75rem; + color: var(--text-muted); +} + +.route-card-desc { + font-size: 0.85rem; + color: var(--text-dim); + line-height: 1.5; + margin-bottom: 1rem; +} + +.route-card-stops { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.4rem; +} + +.route-stop { + font-size: 0.7rem; + font-weight: 500; + color: var(--accent); + background: rgba(212, 160, 74, 0.1); + padding: 0.25rem 0.6rem; + border-radius: 20px; +} + +.route-connector { + font-size: 0.65rem; + color: var(--text-muted); +} + +/* =================================================== + AR VIEW + =================================================== */ + +.ar-container { + position: fixed; + inset: 0; + background: #000; + overflow: hidden; +} + +#ar-camera { + width: 100%; + height: 100%; + object-fit: cover; +} + +#ar-particles { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 2; +} + +.ar-overlay { + position: absolute; + inset: 0; + z-index: 3; + pointer-events: none; +} + +.ar-overlay > * { + pointer-events: auto; +} + +/* AR Error */ +.ar-error { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + padding: 2rem; +} + +.ar-error-icon { + font-size: 3rem; + margin-bottom: 1rem; + opacity: 0.6; +} + +.ar-error h3 { + font-size: 1.2rem; + margin-bottom: 0.5rem; +} + +.ar-error p { + font-size: 0.85rem; + color: var(--text-dim); + margin-bottom: 1.5rem; +} + +.btn-retry { + padding: 0.6rem 1.5rem; + background: var(--accent); + color: var(--bg); + border: none; + border-radius: 50px; + font-family: var(--font-sans); + font-size: 0.85rem; + font-weight: 600; + cursor: pointer; +} + +/* AR HUD */ +.ar-monument-hud { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +/* AR Top Bar */ +.ar-top-bar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.8rem 1rem; + padding-top: calc(0.8rem + var(--safe-top)); + background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent); +} + +.ar-btn-back { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border: none; + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-radius: 50%; + color: #fff; + cursor: pointer; + transition: background 0.3s; +} + +.ar-btn-back:active { + background: rgba(255, 255, 255, 0.2); +} + +.ar-monument-badge { + display: flex; + flex-direction: column; + align-items: center; + opacity: 0; + transform: translateY(-10px); + transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1); +} + +.ar-monument-badge.visible { + opacity: 1; + transform: translateY(0); +} + +.ar-badge-epoch { + font-size: 0.55rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.15em; + color: var(--accent, #d4a04a); + margin-bottom: 0.15rem; +} + +.ar-badge-name { + font-family: var(--font-serif); + font-size: 1rem; + font-weight: 600; + color: #fff; + text-shadow: 0 1px 4px rgba(0,0,0,0.5); +} + +.ar-distance-indicator { + display: flex; + align-items: center; + justify-content: center; + min-width: 40px; + height: 40px; + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-radius: 20px; + padding: 0 0.8rem; +} + +.ar-distance-value { + font-size: 0.7rem; + font-weight: 600; + color: #fff; +} + +/* AR Scan Frame */ +.ar-scan-frame { + position: absolute; + top: 50%; + left: 50%; + width: 65vw; + max-width: 300px; + height: 65vw; + max-height: 300px; + transform: translate(-50%, -50%) scale(0.8); + opacity: 0; + transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); +} + +.ar-scan-frame.visible { + opacity: 1; + transform: translate(-50%, -50%) scale(1); +} + +.ar-scan-corner { + position: absolute; + width: 24px; + height: 24px; + border-color: var(--accent, #d4a04a); + border-style: solid; + border-width: 0; +} + +.ar-scan-corner.tl { top: 0; left: 0; border-top-width: 2px; border-left-width: 2px; border-radius: 4px 0 0 0; } +.ar-scan-corner.tr { top: 0; right: 0; border-top-width: 2px; border-right-width: 2px; border-radius: 0 4px 0 0; } +.ar-scan-corner.bl { bottom: 0; left: 0; border-bottom-width: 2px; border-left-width: 2px; border-radius: 0 0 0 4px; } +.ar-scan-corner.br { bottom: 0; right: 0; border-bottom-width: 2px; border-right-width: 2px; border-radius: 0 0 4px 0; } + +.ar-scan-line { + position: absolute; + left: 10%; + right: 10%; + height: 1px; + background: var(--accent, #d4a04a); + opacity: 0.5; + top: 0; + animation: scanLine 3s ease-in-out infinite; +} + +@keyframes scanLine { + 0%, 100% { top: 10%; opacity: 0.3; } + 50% { top: 90%; opacity: 0.6; } +} + +/* AR Character Figure — Full-body overlay */ +.ar-character-figure { + position: absolute; + bottom: 18%; + right: 5%; + width: 120px; + display: flex; + flex-direction: column; + align-items: center; + opacity: 0; + transform: translateY(40px) scale(0.8); + transition: all 0.8s cubic-bezier(0.16, 1, 0.3, 1); + pointer-events: none; + z-index: 4; +} + +.ar-character-figure.visible { + opacity: 1; + transform: translateY(0) scale(1); + pointer-events: auto; +} + +.ar-figure-body { + position: relative; + width: 120px; + height: 240px; + display: flex; + flex-direction: column; + align-items: center; +} + +.ar-figure-glow { + position: absolute; + inset: -20px; + border-radius: 50%; + animation: figureFloat 4s ease-in-out infinite; + pointer-events: none; +} + +.ar-figure-svg { + width: 100%; + height: 200px; + filter: drop-shadow(0 0 12px rgba(255,255,255,0.15)); + animation: figureFloat 4s ease-in-out infinite; +} + +.ar-figure-label { + display: flex; + flex-direction: column; + align-items: center; + margin-top: 0.3rem; +} + +.ar-figure-label strong { + font-size: 0.7rem; + font-weight: 600; + color: #fff; + text-shadow: 0 1px 6px rgba(0,0,0,0.8); + text-align: center; +} + +.ar-figure-label span { + font-size: 0.55rem; + color: rgba(255,255,255,0.6); + text-transform: uppercase; + letter-spacing: 0.08em; + text-shadow: 0 1px 4px rgba(0,0,0,0.8); +} + +.ar-figure-speech { + position: absolute; + bottom: 100%; + right: 0; + width: 200px; + margin-bottom: 0.5rem; + background: rgba(0, 0, 0, 0.65); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid rgba(255, 255, 255, 0.12); + border-radius: var(--radius-sm); + padding: 0.7rem 0.9rem; + opacity: 0; + transform: translateY(10px); + transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1); + pointer-events: none; +} + +.ar-figure-speech.visible { + opacity: 1; + transform: translateY(0); + pointer-events: auto; +} + +.ar-figure-speech p { + font-size: 0.72rem; + line-height: 1.45; + color: rgba(255, 255, 255, 0.9); + margin: 0; + padding-right: 1rem; +} + +.ar-figure-speech-close { + position: absolute; + top: 0.3rem; + right: 0.3rem; + background: none; + border: none; + color: rgba(255,255,255,0.5); + font-size: 0.7rem; + cursor: pointer; + padding: 0.2rem; + line-height: 1; +} + +.ar-figure-speech::after { + content: ''; + position: absolute; + bottom: -6px; + right: 30px; + width: 12px; + height: 12px; + background: rgba(0, 0, 0, 0.65); + border-right: 1px solid rgba(255, 255, 255, 0.12); + border-bottom: 1px solid rgba(255, 255, 255, 0.12); + transform: rotate(45deg); +} + +@keyframes figureFloat { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-8px); } +} + +/* AR Controls */ +.ar-controls { + display: flex; + justify-content: center; + gap: 1rem; + padding: 1rem; + padding-bottom: calc(1.5rem + var(--safe-bottom)); + background: linear-gradient(to top, rgba(0,0,0,0.6), transparent); + opacity: 0; + transform: translateY(20px); + transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1) 0.2s; +} + +.ar-controls.visible { + opacity: 1; + transform: translateY(0); +} + +.ar-control-btn { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.35rem; + padding: 0.8rem 1.2rem; + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: var(--radius-sm); + color: #fff; + cursor: pointer; + transition: all 0.3s ease; + font-family: var(--font-sans); + min-width: 80px; +} + +.ar-control-btn span { + font-size: 0.65rem; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.ar-control-btn:active { + transform: scale(0.95); +} + +.ar-control-btn.active { + background: var(--accent, #d4a04a); + border-color: var(--accent, #d4a04a); + color: #000; +} + +.ar-control-btn.active svg { + stroke: #000; +} + +/* AR Text Panel Backdrop */ +.ar-text-backdrop { + position: absolute; + inset: 0; + background: rgba(0, 0, 0, 0.4); + opacity: 0; + pointer-events: none; + transition: opacity 0.4s ease; + z-index: 9; +} + +.ar-text-backdrop.visible { + opacity: 1; + pointer-events: auto; +} + +/* AR Text Panel */ +.ar-text-panel { + position: absolute; + bottom: 0; + left: 0; + right: 0; + max-height: 55vh; + background: rgba(10, 10, 15, 0.94); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border-top: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 20px 20px 0 0; + transform: translateY(100%); + transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1); + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 10; +} + +.ar-text-panel.visible { + transform: translateY(0); +} + +.ar-text-header { + display: flex; + align-items: center; + justify-content: center; + padding: 0.6rem 1rem; + position: sticky; + top: 0; + background: rgba(10, 10, 15, 0.94); + z-index: 1; +} + +.ar-text-handle { + width: 40px; + height: 5px; + background: rgba(255, 255, 255, 0.25); + border-radius: 3px; + cursor: pointer; +} + +.ar-text-close { + position: absolute; + right: 0.8rem; + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: rgba(255, 255, 255, 0.08); + border: none; + border-radius: 50%; + color: rgba(255, 255, 255, 0.6); + cursor: pointer; + transition: all 0.2s; +} + +.ar-text-close:active { + background: rgba(255, 255, 255, 0.15); + color: #fff; +} + +.ar-text-content { + padding: 0 1.5rem 2rem; + padding-bottom: calc(2rem + var(--safe-bottom)); +} + +.ar-text-content h2 { + font-family: var(--font-serif); + font-size: 1.6rem; + font-weight: 700; + margin-bottom: 0.3rem; +} + +.ar-text-subtitle { + font-size: 0.85rem; + color: var(--text-dim); + font-style: italic; + margin-bottom: 1rem; +} + +.ar-text-divider { + width: 40px; + height: 2px; + border-radius: 1px; + margin-bottom: 1rem; +} + +.ar-text-body { + font-size: 0.9rem; + line-height: 1.8; + color: rgba(255, 255, 255, 0.85); + margin-bottom: 1.2rem; +} + +.ar-text-meta { + display: flex; + gap: 0.5rem; +} + +.ar-meta-tag { + font-size: 0.65rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--accent, #d4a04a); + background: rgba(212, 160, 74, 0.1); + padding: 0.3rem 0.8rem; + border-radius: 20px; +} + +/* Nearby hint */ +.ar-nearby-hint { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; + padding: 2rem; +} + +.ar-nearby-hint p { + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 0.5rem; +} + +.ar-hint-sub { + font-size: 0.85rem !important; + font-weight: 400 !important; + color: var(--text-dim); + margin-bottom: 1.5rem !important; +} + +.btn-explore { + padding: 0.7rem 1.5rem; + background: var(--accent); + color: var(--bg); + border: none; + border-radius: 50px; + font-family: var(--font-sans); + font-size: 0.85rem; + font-weight: 600; + cursor: pointer; +} + +/* Toast */ +.ar-toast { + position: fixed; + bottom: 5rem; + left: 50%; + transform: translateX(-50%) translateY(20px); + background: rgba(30, 30, 40, 0.9); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 50px; + padding: 0.6rem 1.2rem; + font-size: 0.8rem; + color: var(--text); + opacity: 0; + transition: all 0.4s ease; + z-index: 1000; + pointer-events: none; +} + +.ar-toast.visible { + opacity: 1; + transform: translateX(-50%) translateY(0); +} + +/* =================================================== + ANIMATIONS + =================================================== */ + +@keyframes fadeInUp { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.home-content { + animation: fadeInUp 0.8s ease 0.2s both; +} + +.home-nav { + animation: fadeIn 0.6s ease 0.1s both; +} + +.home-scroll-hint { + animation: fadeIn 1s ease 1s both; +} + +/* =================================================== + RESPONSIVE + =================================================== */ + +@media (min-width: 768px) { + .monument-grid { + grid-template-columns: repeat(2, 1fr); + } + + .route-grid { + grid-template-columns: repeat(2, 1fr); + } + + .ar-character-figure { + width: 160px; + right: 8%; + } + + .ar-figure-body { + width: 160px; + height: 320px; + } + + .ar-figure-svg { + height: 270px; + } + + .ar-figure-speech { + width: 260px; + } +} + +@media (min-width: 1024px) { + .home-hero { + padding: 4rem 2rem; + } + + .explore-content { + padding: 2rem 2rem; + } +} + +/* Prefers reduced motion */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..7af17a4 --- /dev/null +++ b/index.html @@ -0,0 +1,185 @@ + + +
+ + + + + + +realtà aumentata
++ Inquadra i monumenti e lasciati guidare dalla storia. + Audio, racconti e personaggi prendono vita davanti ai tuoi occhi. +
+come funziona
+Avvicinati a un monumento di Gubbio. L'app rileva la tua posizione automaticamente.
+Punta la fotocamera verso il monumento e guarda la magia prendere forma.
+Ascolta audio, leggi storie e incontra personaggi storici in realtà aumentata.
+monumenti
+Dai palazzi medievali ai teatri romani, ogni angolo di Gubbio ha una storia da raccontare.
+ +Tocca un monumento per esplorarlo in realtà aumentata.
+ +Scegli un percorso guidato per scoprire Gubbio.
+ +${m.shortDescription}
+ +${r.description}
+Nessun monumento nelle vicinanze
'; + hint += 'Avvicinati a uno dei monumenti di Gubbio o scegli dalla lista
'; + hint += ``; + hint += 'Consenti l'accesso alla fotocamera per vivere l'esperienza AR.
+ +${monument.character.greeting}
+ +${monument.subtitle}
+ +${monument.description}
+ +