C’è una legge non scritta di internet: se una cosa esiste, qualcuno proverà a farci girare DOOM. Test di gravidanza, trattori, Flipper Zero (in inglese), termostati. L’elenco è lungo, ridicolo e non smette mai di crescere.
Ma questa settimana lo sviluppatore Niels Leenheer ha portato lo scherzo dove nessuno se l’aspettava. Ha costruito una reimplementazione giocabile di DOOM in cui ogni muro, pavimento, barile e imp è un elemento HTML <div>, visualizzato interamente con CSS. Niente canvas. Niente WebGL. Soltanto fogli di stile a cascata impegnati a fare cose per cui non erano nati.
Puoi giocarci subito nel browser. Lo sviluppatore mette a disposizione una demo giocabile; supporto e prestazioni possono variare fra browser.
Come si costruisce uno sparatutto 3D in CSS?
La risposta breve: con una quantità terrificante di matematica e una conoscenza profonda di funzioni CSS moderne che molti sviluppatori web non hanno mai toccato.
Leenheer ha estratto i dati delle mappe dal file WAD shareware originale del 1993, gli stessi usati dal motore di DOOM, e ha trasformato ogni vertice, segmento di muro e settore in elementi HTML. Ogni muro riceve le coordinate grezze di DOOM come proprietà personalizzate CSS. Poi CSS si occupa della geometria vera e propria: calcola le larghezze con hypot(), gli angoli di rotazione con atan2() e colloca tutto nello spazio 3D con translate3d() e rotateY().
La logica di gioco gira in JavaScript. Ma il rendering, tutto quanto, è puro CSS. JavaScript passa al viewport quattro proprietà personalizzate: X, Y, Z e angolo del giocatore. CSS fa il resto. Questa separazione netta fra logica e grafica è una delle parti più eleganti del progetto.
Muovere il mondo anziché la telecamera
Qui le cose diventano filosoficamente interessanti, in senso nerd. CSS non ha una telecamera. Non puoi puntare una lente virtuale verso una scena 3D e muoverla. Leenheer ha quindi usato un trucco classico della prima grafica tridimensionale: anziché spostare la telecamera nel mondo, sposti l’intero mondo intorno al giocatore.
Fai un passo avanti? Il mondo arretra. Sali le scale? Le scale scendono. Ogni movimento è invertito. Pensarci disorienta, ma nella pratica funziona perfettamente.
Se hai mai esplorato la strana storia dello sviluppo dei videogiochi (in inglese), sai che trucchi del genere sono ovunque. Lo stesso DOOM originale ne era pieno. Il fatto che qualcuno abbia ricreato quello spirito di soluzione creativa dei problemi usando CSS nel 2026 è, francamente, bellissimo.
I pavimenti sono semplici div ribaltati
Gli elementi DOM sono verticali per impostazione predefinita. I pavimenti devono essere orizzontali. Quindi ogni pavimento riceve un rotateX(90deg) che lo ruota nel piano giusto. Leenheer ammette di aver sbagliato il segno al primo tentativo. Il pavimento c’era, ma era rivolto dalla parte sbagliata e invisibile al giocatore. Un classico.
Per le forme irregolari dei settori di DOOM, stanze a L, curve quasi circolari e piattaforme con buchi, ha usato clip-path con tracciati SVG e la regola di riempimento evenodd. La nuova funzione CSS shape() ha reso il tutto più pulito di quanto sarebbe stato anche solo un anno fa. CSS moderno continua a diventare più potente e progetti come questo lo dimostrano.
Il trucco degli spritesheet e la marcia degli zombie
I nemici di DOOM sono sprite 2D sempre rivolti verso la telecamera, una tecnica chiamata billboarding. Ogni nemico ha sprite per diverse angolazioni e il gioco originale memorizzava soltanto cinque serie uniche su otto rotazioni, specchiando le altre. Leenheer ha riprodotto il sistema con spritesheet, animazioni CSS steps() e un ribaltamento scaleX() per le direzioni speculari.
Un problema inatteso: tutti i nemici marciavano in perfetta sincronia. Il piede sinistro di ogni zombieman toccava terra esattamente nello stesso fotogramma. L’effetto era, nelle parole di Leenheer, «profondamente inquietante». La soluzione è stata un animation-delay casuale impostato in JavaScript per sfalsare il ciclo di camminata di ciascun nemico. Un piccolo dettaglio che separa una «demo tecnica» da «qualcosa che sembra vivo».
Tutto è iniziato da un oscilloscopio
Il progetto cssDOOM non è spuntato dal nulla. Leenheer aveva già costruito una versione di DOOM per un oscilloscopio degli anni Ottanta, ottenendo così il codice per estrarre le mappe e una buona comprensione della matematica coinvolta.
Per il ciclo di gioco JavaScript, la parte che riteneva meno interessante, ha usato Claude come aiuto per crearne un’approssimazione a partire dal codice C originale. Il sorgente originale di DOOM è pubblico da anni e Leenheer voleva dedicare il tempo alla parte difficile: far fare a CSS cose per cui non era stato progettato. Il codice completo di cssDOOM è disponibile su GitHub.
Perché conta oltre al meme
«Ci gira DOOM?» è un meme, certo. Ma progetti come cssDOOM sono più di uno scherzo. Sono prove di stress per la tecnologia dei browser. Spingono CSS al limite e mostrano cosa possono gestire i browser moderni. Ogni muro usa hypot(), atan2(), proprietà personalizzate CSS, clip-path e dichiarazioni @property. Sono funzioni del browser combinate in modo insolitamente ambizioso. Supporto e prestazioni possono variare secondo browser e dispositivo.
Keith Clark aveva costruito anni fa una demo FPS solo CSS che dimostrava la fattibilità dell’idea. Leenheer è andato oltre, visualizzando un progetto giocabile con nemici, porte, ascensori e animazioni degli sprite. È una reimplementazione sperimentale, non una rivendicazione di fedeltà completa al motore originale. Il divario fra ciò che CSS poteva fare nel 2010 e ciò che può fare oggi è impressionante.
Se hai mai guardato gli speedrunner smontare i giochi (in inglese) o seguito sviluppatori indipendenti costruire interi mondi da zero (in inglese), sai che le cose più interessanti della tecnologia accadono quando qualcuno decide di ignorare le regole e provare qualcosa di assurdo.
cssDOOM è assurdo. È anche brillante. E puoi giocarci subito su cssdoom.wtf.
Vai. Il tuo browser può reggerlo. Probabilmente.
Traduzione italiana dell’articolo originale in inglese del 2026-03-30. Tradotto il 30 ottobre 2026 con assistenza IA; i riferimenti temporali restano quelli dell’originale.




