Andrea Casiraghi · lab
Esperimento

ScrollyTelling: un CMS costruito parlando con l'AI

Un CMS leggero per creare gallerie fotografiche narrative in stile "ScrollyTelling": si scorre la pagina e le foto si susseguono come un piccolo film, con una colonna sonora ambientale. Niente database: solo file PHP e JSON. Tutto il progetto, dal primo bug fix all'ultima rifinitura estetica, è stato costruito in una serie di conversazioni con Claude Code, senza scrivere codice a mano.

8 min di lettura Case study · Claude Code · Web Audio
Guarda com'è fatta

Prima di scoprire come funziona il CMS, esplora una galleria reale. Le immagini vengono presentate a tutto schermo e sono accompagnate da un ambiente sonoro pensato per valorizzarne la fruizione. L'audio è consigliato.

Apri la galleria dal vivo

Cos'è

ScrollyTelling è un piccolo sistema pensato per raccontare per immagini. Ha due facce:

  • Un pannello admin, protetto da password, per creare gallerie, caricare foto, scrivere didascalie e scegliere una colonna sonora.
  • Una pagina pubblica generata automaticamente per ogni galleria: scrolli e le foto scorrono a schermo intero, con un motore audio ambientale.

Nessun database: ogni galleria è un file JSON, le immagini sono file caricati e la pagina pubblica è un file HTML statico rigenerato ad ogni modifica. Chi lo usa non tocca codice: crea la galleria, carica le foto, scrive due righe di descrizione, sceglie un tema musicale, salva, e ottiene un link pronto da condividere.

Pannello admin del CMS ScrollyTelling: sezione Impostazioni con occhiello, titolo, descrizione, scelta del sottofondo musicale e URL pubblico.
Pannello admin · Impostazioni della galleria
Pannello admin del CMS ScrollyTelling: sezione Immagini con area di trascinamento e le card delle foto caricate, ognuna con titolo e didascalia opzionali.
Pannello admin · Caricamento e ordine delle immagini

Come è stato costruito: il metodo

Il progetto non è partito da uno scheletro predefinito o da un framework: è cresciuto un problema alla volta, in una conversazione continua con Claude Code. Il pattern tipico è stato sempre lo stesso:

  1. Segnalazione in linguaggio naturale, spesso imprecisa o "di pancia": non un ticket tecnico, ma un'osservazione come la farebbe chiunque guardando il risultato finale.
  2. Claude indaga il codice esistente prima di scrivere qualsiasi riga: legge i file coinvolti, individua la causa reale (non la prima ipotesi), e solo dopo propone una correzione.
  3. Implementazione mirata, senza aggiungere funzionalità non richieste né "abbellire" codice che non c'entra col problema.
  4. Verifica e resoconto di cosa è cambiato, in linguaggio semplice, con indicazione di eventuali passi manuali da fare (es. "risalva le impostazioni per rigenerare la pagina").
Questo ciclo si è ripetuto per bug fix, nuove funzionalità e rifiniture estetiche allo stesso modo: il prompt non deve essere un progetto tecnico, deve essere un'osservazione onesta di cosa non va o cosa si vorrebbe vedere.

Le funzionalità, con i prompt reali che le hanno generate

Diagnosi di un bug di deploy

Spostato dalla root del dominio a una sottocartella, il sito mostrava una pagina vuota: CSS e JavaScript non si caricavano perché i percorsi erano assoluti (/assets/…) invece che relativi.

Prompt originale

«C'è qualcosa che non va nel render del progetto: il CMS funziona correttamente, ma la pagina pubblica generata risulta completamente rotta a questo link: [link alla pagina].»

Letta la causa (tutti i percorsi assumevano che il sito vivesse nella root), sono stati convertiti in percorsi relativi: più robusti di qualsiasi configurazione manuale, perché funzionano identici ovunque il progetto venga spostato.

Copertina personalizzabile

Prompt originale

«Aggiungiamo dei testi descrittivi in apertura alla galleria: un occhiello, il titolo e una breve descrizione. Mantieni la coerenza tipografica con il resto della pagina.»

Prima la copertina mostrava un testo fisso ("Galleria · N fotografie"). Ora occhiello e descrizione sono campi editabili dal pannello, con lo stesso sistema tipografico del resto della pagina.

Titolo per singola immagine

Prompt originale

«Sopra il campo "didascalia", aggiungi un campo opzionale per un titolo da mostrare accanto al numero della foto, con lo stesso font del numero.»

Ogni foto ha un numero progressivo (01, 02…). Ora gli si può affiancare un titolo opzionale, con lo stesso font del numero per coerenza visiva, mentre la didascalia narrativa resta separata sotto.

Sistema musicale: dalla richiesta generica ai preset su misura

Questa funzione è nata in più passaggi, un buon esempio di come il dialogo iterativo affini il risultato.

Prompt 1 esplorativo

«Suggeriscimi un modo per migliorare la gestione del sottofondo musicale.»

Prompt 2 restringe lo scope

«Limitiamoci a preparare un set di brani sintetizzati, selezionabili alla creazione della galleria. È fattibile?»

Prompt 3 corregge la direzione

«I brani devono essere leggeri e malinconici, in stile fado: niente di aggressivo o troppo dinamico, deve risultare immersivo.»

Il risultato: 4 temi musicali generati via Web Audio API (nessun file audio da gestire), ciascuno con un accordo armonico distinto: non trasposizioni dello stesso accordo, ma quattro "voci" davvero riconoscibili, tutte nel registro malinconico richiesto.

Prompt successivo raffinamento dopo l'ascolto

«Il sottofondo musicale non mi convince: c'è sempre un rumore di mare in sottofondo, i temi sono troppo simili tra loro, e non mi convince il cambio di tonalità a metà scroll.»

Da qui: rimossa la transizione di accordo a metà ascolto (la "deformazione"), rumore ambientale relegato a un solo tema, differenze fra i temi rese più marcate su tempo, registro e riverbero.

Prompt finale estensione della funzione

«Aggiungiamo un'opzione "personale" che permetta di caricare una traccia audio propria (ad esempio un brano royalty-free scaricato online) in alternativa ai temi generati.»

Aggiunta la possibilità di caricare un proprio brano (mp3/ogg/wav/m4a) in alternativa ai temi generativi, con relativo credito visibile in pagina (per attribuzioni CC / royalty-free) e icona di collegamento a un sito esterno.

Rifinitura visiva: meno effetti, più immagine

Prompt originale

«Ci sono troppi effetti di zoom sulle immagini, e lo sfondo sfocato dietro le foto è troppo invasivo: proviamo a toglierlo e lasciare l'immagine pulita. Aggiungi anche un po' di margine sopra e sotto le immagini, senza sovrapporre le miniature.»

Rimosso lo sfondo sfocato dietro ogni foto, ridotto drasticamente l'effetto "Ken Burns", aggiunto un margine sopra e sotto calcolato per non invadere mai la fascia delle miniature in basso.

Debug di un bug introdotto a mano

Prompt originale

«Se sostituisco l'audio con una traccia personale, la pagina si rompe completamente: il frontend non carica più.»

Un elemento HTML era stato rinominato durante una modifica manuale al template, ma il JavaScript cercava ancora il vecchio nome: un riferimento a un elemento inesistente mandava in errore silenzioso l'intero script. Diagnosi e correzione mirata, senza toccare il resto.

Refactor architetturale su richiesta esplicita

Prompt originale

«Nel CSS usi molti selettori per ID invece che per classe: perché questa scelta? Non è replicabile: ad esempio due pulsanti non possono condividere la stessa classe. Preferirei un'impostazione più lineare, con elementi riutilizzabili, senza abusare degli ID.»

Una critica tecnica puntuale, accolta con una spiegazione del perché e un piano condiviso prima di agire. Risultato: ogni ID resta solo un aggancio per il JavaScript, mentre tutto lo stile vive in classi CSS riutilizzabili (pattern base + modificatore, es. .film-btn + .film-btn--mute): zero comportamento cambiato, struttura molto più manutenibile.

Cosa dice questo progetto sullo sviluppare con l'AI

  • La direzione conta più della sintassi. Guidare lo sviluppo significa definire con precisione requisiti, vincoli e criteri di accettazione; la traduzione in codice corretto è il livello successivo, delegabile all'AI a condizione di mantenere il controllo sulle decisioni tecniche.
  • Il requisito qualitativo è un requisito a tutti gli effetti. Le osservazioni percettive su ritmo visivo, intensità di un effetto o resa sonora vanno formalizzate in parametri misurabili: ampiezza dello zoom, presenza di rumore ambientale, densità armonica. Il valore del processo sta nel rendere operativo un criterio soggettivo.
  • L'iterazione è parte del metodo, non un suo scarto. Il sistema musicale è passato per specificazione progressiva: da un obiettivo generico a una specifica verificabile (quattro temi distinti, registro malinconico, assenza di transizioni intrusive). Ogni ciclo ha ridotto l'ambiguità del requisito.
  • Disambiguare prima di implementare riduce il costo dell'errore. Esplicitare i valori di default e il comportamento nei casi limite (dati mancanti, campi opzionali, stati non previsti) evita di consolidare scelte implicite, costose da correggere a valle.
  • Il codice generato è revisionabile come qualsiasi altro. Una scelta architetturale, ad esempio l'uso di selettori per ID anziché per classi, può essere discussa nel merito, motivata e sottoposta a refactoring, con gli stessi criteri di manutenibilità applicati al codice scritto manualmente.

In sintesi

CosaCome è natoRisultato
Fix percorsi assolutiSegnalazione di una pagina rottaPercorsi relativi, portabili ovunque
Copertina personalizzabileRichiesta di più testo in aperturaOcchiello / titolo / descrizione editabili
Titoli per immagineRichiesta puntuale su un campoTitolo opzionale accanto al numero
Musica generativaSuggerimento → scope → correzione di direzione4 temi fado immersivi, coerenti tra loro
Audio personalizzatoEstensione esplicita della funzioneUpload traccia propria + credito CC
Pulizia visivaFeedback estetico direttoMeno zoom, niente sfondo sfocato, più aria
Refactor CSSCritica tecnica motivataID solo come hook JS, stile tutto su classi

Vuoi vederlo in azione? Apri la galleria "Emotional" generata con questo CMS.

Parliamo del prossimo sviluppo.

Nessun database o cookie: i dati servono solo per risponderti via email (art. 13-14 GDPR), non sono conservati né condivisi con terzi. Titolare: Andrea Casiraghi, andrea.l.casiraghi@gmail.com.

Non sono riuscito a inviare il messaggio. Riprova, o scrivimi direttamente a andrea.l.casiraghi@gmail.com.