Dance Tonite in WebVR

Ero entusiasta quando il team di Google Data Arts ha contattato Moniker e io per discutere insieme delle possibilità offerte da WebVR. Nel corso degli anni ho guardato il lavoro dei loro team e i loro progetti mi hanno sempre colpito. La nostra collaborazione ha dato vita a Dance Tonite, un'esperienza di danza VR in continua evoluzione con LCD Soundsystem e i suoi fan. Ecco come abbiamo fatto.

Il concetto

Abbiamo iniziato con lo sviluppo di una serie di prototipi utilizzando WebVR, uno standard aperto che consente di accedere alla VR visitando un sito web tramite il browser. L'obiettivo è permettere a tutti di vivere più facilmente le esperienze VR, a prescindere dal dispositivo in uso.

L'abbiamo preso a cuore. Qualunque sia la soluzione che abbiamo trovato, dovrebbe funzionare con tutti i tipi di VR, dai visori VR compatibili con telefoni cellulari come Daydream View di Google, Cardboard e Gear VR di Samsung ai sistemi scalabili per le stanze come HTC VIVE e Oculus Rift, che riflettono i tuoi movimenti fisici nel tuo ambiente virtuale. Forse la cosa più importante è che ritenevamo che sarebbe stato nello spirito del web creare qualcosa che funzioni anche per tutti coloro che non possiedono un dispositivo VR.

1. Acquisizione movimento fai da te

Poiché volevamo coinvolgere gli utenti in modo creativo, abbiamo iniziato a esaminare la possibilità di partecipazione ed espressione personale utilizzando la VR. Siamo rimasti colpiti dalla precisione con cui riesci a muoverti e guardarti intorno in VR e dalla fedeltà dimostrata. Questo ci ha dato un'idea. Anziché lasciare che gli utenti guardino o creino qualcosa, che ne dici di registrare i loro movimenti?

Qualcuno che si sta registrando su Dance Tonite. Lo schermo dietro di loro mostra ciò che vede nelle cuffie

Abbiamo realizzato un prototipo in cui abbiamo registrato le posizioni dei nostri occhialini e controller VR mentre ballavamo. Abbiamo sostituito le posizioni registrate con forme astratte e siamo rimasti meravigliati dai risultati. I risultati sono stati così umani e contenevano tanta personalità. Ci siamo resi subito conto che potevamo utilizzare WebVR per acquisire immagini di movimento a basso costo a casa.

Con WebVR, lo sviluppatore ha accesso alla posizione e all'orientamento della testa dell'utente tramite l'oggetto VRPose. Questo valore viene aggiornato a ogni frame dall'hardware VR in modo che il tuo codice possa eseguire il rendering di nuovi frame dal punto di vista corretto. Tramite l'API GamePad con WebVR, possiamo anche accedere alla posizione/orientamento dei controller degli utenti tramite l'oggetto GamepadPose. Semplicemente memorizziamo tutti questi valori di posizione e orientamento a ogni fotogramma, per creare una "registrazione" dei movimenti dell'utente.

2. Minimalismo e costumi

Con le attuali apparecchiature VR in scala locale, siamo in grado di tenere traccia di tre punti del corpo dell'utente: la testa e due mani. In Dance Tonite, volevamo mantenere l'attenzione sull'umanità nel movimento di questi 3 punti nello spazio. Per raggiungere questo obiettivo, abbiamo optato per un'estetica il più minima possibile per concentrarci sul movimento. Ci piaceva l'idea di mettere all'opera il cervello delle persone.

Questo video che mostra il lavoro dello psicologo svedese Gunnar Johansson è stato uno degli esempi a cui abbiamo fatto riferimento quando abbiamo preso in considerazione l'idea di rimuovere il più possibile le cose. Mostra come i punti bianchi fluttuanti siano immediatamente riconoscibili come corpi se visti in movimento.

Visivamente, siamo stati ispirati dalle stanze colorate e dai costumi geometrici in questa registrazione del riassunto del 1970 di Margarete Hastings del Triadic Ballet di Oskar Schlemmer.

Mentre Schlemmer ha scelto costumi geometrici astratti per limitare i movimenti dei ballerini a quelli delle marionette e delle marionette, l'obiettivo opposto era Dance Tonite.

Abbiamo finito per basare la nostra scelta di forme sulla quantità di informazioni che trasmettevano dalla rotazione. La sfera ha lo stesso aspetto, indipendentemente da come è ruotata, ma un cono punta davvero nella direzione in cui appare e ha un aspetto diverso dalla parte anteriore rispetto a quella posteriore.

3. Pedale loop per il movimento

Volevamo mostrare grandi gruppi di persone registrate che ballavano e si muovevano insieme. Non sarebbe possibile fare tutto questo in diretta, dal momento che i dispositivi VR non sono disponibili in numero sufficiente. Ma volevamo comunque che gruppi di persone reagissero l'uno all'altro attraverso il movimento. Abbiamo pensato all'esibizione ricorsiva di Norman McClaren nel suo video del 1964, "Canon".

L'esibizione di McClaren presenta una serie di movimenti altamente coreografati che iniziano a interagire tra loro dopo ogni loop. Proprio come un pedale loop in musica, in cui i musicisti si ballano con se stessi sovrapponendo diversi brani di musica dal vivo, eravamo interessati a vedere se potevamo creare un ambiente in cui gli utenti potessero improvvisare liberamente versioni più vaghe delle esibizioni.

4. Camere comunicanti

Camere comunicanti

Come tanta musica, le tracce di LCD Soundsystem sono composte utilizzando misure precisamente temporizzate. Il brano Tonite, presente nel nostro progetto, presenta misure della durata esatta di 8 secondi. Volevamo che gli utenti eseguissero un'esecuzione per ogni loop di 8 secondi nella traccia. Anche se il ritmo di queste misure non cambia, i contenuti musicali cambiano. Man mano che il brano progredisce, esistono momenti con diversi strumenti e voci a cui gli artisti possono reagire in modi diversi. Ognuna di queste misure viene espressa come una stanza, in cui le persone possono realizzare una performance adatta.

Ottimizzazioni del rendimento: non far perdere i frame

Creare un'esperienza VR multipiattaforma che viene eseguita su un unico codebase con prestazioni ottimali per ogni dispositivo o piattaforma non è un'impresa facile.

In VR, uno degli aspetti più disgustosi che si possono provare è dovuto alla frequenza fotogrammi che non sta al passo con il movimento. Se giri la testa ma le immagini che vedi non corrispondono al movimento percepito dall'orecchio interno, si verifica un'immediata abbandono dello stomaco. Per questo motivo, dovevamo evitare ritardi significativi nella frequenza fotogrammi. Di seguito sono riportate alcune ottimizzazioni che abbiamo implementato.

1. Geometria del buffer istanza

Poiché l'intero progetto utilizza solo pochi oggetti 3D, siamo riusciti a ottenere un enorme miglioramento delle prestazioni utilizzando Instanced Buffer Geometry. In pratica, ti consente di caricare l'oggetto nella GPU una volta e di disegnare tutte le "istanze" dell'oggetto che vuoi in una singola chiamata di disegno. In Dance Tonite, abbiamo solo 3 oggetti diversi (un cono, un cilindro e una stanza con un foro), ma potenzialmente centinaia di copie di questi oggetti. Instance Buffer Geometry fa parte di ThreeJS, ma abbiamo utilizzato il fork sperimentale e in corso di Dusan Bosnjak che implementa THREE.InstanceMesh, il che rende molto più semplice lavorare con Instanced Buffer Geometry.

2. Evitare garbage collector

Come con molti altri linguaggi di scripting, JavaScript libera memoria automaticamente individuando gli oggetti allocati non più utilizzati. Questo processo è chiamato garbage collection.

Gli sviluppatori non hanno alcun controllo su quando ciò accade. I garbage collector potrebbero arrivare alle nostre porte in qualsiasi momento e iniziare a svuotare la spazzatura, causando la perdita di fotogrammi quando si prendono una pausa.

La soluzione a questo problema consiste nel produrre la minor quantità di rifiuti possibile riciclando i nostri oggetti. Anziché creare un nuovo oggetto vettoriale per ogni calcolo, abbiamo contrassegnato gli oggetti graffiati per il riutilizzo. Poiché manteniamo le email al di fuori del nostro ambito, non sono state contrassegnate per la rimozione.

Ad esempio, questo è il nostro codice per convertire la matrice della posizione della testa e delle mani dell'utente nell'array di valori di posizione/rotazione memorizzati in ogni frame. Riutilizzando SERIALIZE_POSITION, SERIALIZE_ROTATION e SERIALIZE_SCALE, evitiamo l'allocazione della memoria e la garbage collection che si verificherebbero se creassimo nuovi oggetti ogni volta che viene chiamata la funzione.

const SERIALIZE_POSITION = new THREE.Vector3();
const SERIALIZE_ROTATION = new THREE.Quaternion();
const SERIALIZE_SCALE = new THREE.Vector3();
export const serializeMatrix = (matrix) => {
    matrix.decompose(SERIALIZE_POSITION, SERIALIZE_ROTATION, SERIALIZE_SCALE);
    return SERIALIZE_POSITION.toArray()
    .concat(SERIALIZE_ROTATION.toArray())
    .map(compressNumber);
};

3. Serializzazione dei movimenti e della riproduzione progressiva

Per acquisire i movimenti degli utenti nella realtà virtuale, dovevamo serializzare la posizione e la rotazione delle cuffie e dei controller e caricare questi dati sui nostri server. Abbiamo iniziato ad acquisire tutte le matrici di trasformazione per ogni frame. Questo approccio ha funzionato bene, ma con 16 numeri moltiplicati per 3 posizioni ciascuno a 90 frame al secondo, generava file molto grandi e quindi a lunghe attese durante il caricamento e il download dei dati. Estrarre solo i dati di posizione e rotazionali dalle matrici di trasformazione siamo riusciti a ridurre questi valori da 16 a 7.

Poiché i visitatori sul web spesso fanno clic su un link senza sapere esattamente cosa aspettarsi, dobbiamo mostrare rapidamente i contenuti visivi, altrimenti abbandoneranno il sito in pochi secondi.

Per questo motivo, volevamo assicurarci che il nostro progetto potesse iniziare a essere eseguito il prima possibile. Inizialmente, utilizzavamo JSON come formato per caricare i dati sugli spostamenti. Il problema è che dobbiamo caricare il file JSON completo prima di poterlo analizzare. Non molto progressiva.

Per fare in modo che un progetto come Dance Tonite venga visualizzato con la massima frequenza fotogrammi possibile, il browser ha a disposizione soltanto un po' di tempo ogni frame per i calcoli JavaScript. Se impieghi troppo tempo, le animazioni iniziano a interrompersi. All'inizio, abbiamo riscontrato delle interruzioni perché questi enormi file JSON venivano decodificati dal browser.

Abbiamo trovato un comodo formato di dati in modalità flusso basato su NDJSON o JSON delimitato da una nuova riga. Il trucco è creare un file con una serie di stringhe JSON valide, ciascuna sulla propria riga. In questo modo puoi analizzare il file durante il caricamento e visualizzare le prestazioni prima che vengano caricate completamente.

Ecco l'aspetto di una sezione di una delle nostre registrazioni:

{"fps":15,"count":1,"loopIndex":"1","hideHead":false}
[-464,17111,-6568,-235,-315,-44,9992,-3509,7823,-7074, ... ]
[-583,17146,-6574,-215,-361,-38,9991,-3743,7821,-7092, ... ]
[-693,17158,-6580,-117,-341,64,9993,-3977,7874,-7171, ... ]
[-772,17134,-6591,-93,-273,205,9994,-4125,7889,-7319, ... ]
[-814,17135,-6620,-123,-248,408,9988,-4196,7882,-7376, ... ]
[-840,17125,-6644,-173,-227,530,9982,-4174,7815,-7356, ... ]
[-868,17120,-6670,-148,-183,564,9981,-4069,7732,-7366, ... ]
...

Con NDJSON possiamo conservare la rappresentazione dei dati dei singoli frame delle prestazioni come stringhe. Abbiamo potuto attendere di aver raggiunto il tempo necessario prima di decodificarle in dati posizionali, così da distribuire l'elaborazione necessaria nel tempo.

4. Movimento interpolazione

Poiché speravamo di visualizzare tra le 30 e le 60 prestazioni in esecuzione contemporaneamente, abbiamo dovuto ridurre la velocità di trasmissione dati oltre il limite. Il Data Arts Team ha affrontato lo stesso problema nel suo progetto Virtual Art Sessions, in cui ha riprodotto le registrazioni di artisti che dipingono in VR utilizzando Tilt Brush. Il problema è stato risolto creando versioni intermedie dei dati utente con frequenze fotogrammi più basse e interpolando tra i frame durante la riproduzione. Siamo rimasti sorpresi nel vedere che difficilmente riuscivamo a individuare la differenza tra una registrazione interpolata a 15 f/s e la registrazione originale a 90 f/s.

Per verificarlo personalmente, puoi forzare Dance Tonite a riprodurre i dati a diverse velocità utilizzando la stringa di query ?dataRate=. Puoi utilizzarlo per confrontare il movimento registrato a 90 frame al secondo, 45 frame al secondo o 15 frame al secondo.

Per la posizione, viene eseguita un'interpolazione lineare tra il fotogramma chiave precedente e il successivo, in base alla vicinanza tra i fotogrammi chiave (rapporto):

const { x: x1, y: y1, z: z1 } = getPosition(previous, performanceIndex, limbIndex);
const { x: x2, y: y2, z: z2 } = getPosition(next, performanceIndex, limbIndex);
interpolatedPosition = new THREE.Vector3();
interpolatedPosition.set(
    x1 + (x2 - x1) * ratio,
    y1 + (y2 - y1) * ratio,
    z1 + (z2 - z1) * ratio
    );

Per l'orientamento, viene eseguita un'interpolazione lineare sferica (slerp) tra i fotogrammi chiave. L'orientamento è archiviato come quaternioni.

const quaternion = getQuaternion(previous, performanceIndex, limbIndex);
quaternion.slerp(
    getQuaternion(next, performanceIndex, limbIndex),
    ratio
    );

5. Sincronizzazione dei movimenti con la musica

Per sapere quale fotogramma delle animazioni registrate riprodurre, dobbiamo conoscere l'ora attuale della musica fino al millisecondo. Abbiamo scoperto che, sebbene l'elemento audio HTML sia perfetto per caricare e riprodurre progressivamente l'audio, la proprietà time fornita non cambia in sincronizzazione con il loop di frame del browser. È sempre un po' off. A volte una frazione di ms troppo presto, a volte una frazione troppo tardi.

Nelle nostre splendide registrazioni di danza, ciò porta a balbuzie, che vogliamo evitare a ogni costo. Per rimediare al problema, abbiamo implementato il nostro nostro timer in JavaScript. In questo modo possiamo essere certi che la quantità di tempo che cambia da un frame all'altro corrisponde esattamente alla quantità di tempo trascorsa dall'ultimo frame. Ogni volta che il timer risulta non sincronizzato per oltre 10 ms con la musica, lo ripetiamo nuovamente.

6. Cultura e nebbia

Ogni storia ha bisogno di un buon finale e volevamo fare qualcosa di sorprendente per gli utenti che sono arrivati alla fine della nostra esperienza. Uscendo dall'ultima stanza, entri in un paesaggio tranquillo di coni e cilindri. "È questa la fine?" ti chiedi. Mentre ti sposti più in là nel campo, all'improvviso i toni della musica generano diversi gruppi di coni e cilindri in ballerini. Ti ritrovi nel bel mezzo di una grande festa! Poi, quando la musica si interrompe improvvisamente, tutto cade in terra.

Anche se è stato molto bello per gli spettatori, ha introdotto alcuni ostacoli in termini di rendimento da risolvere. I dispositivi VR su scala locale e i loro dispositivi di gioco di fascia alta si sono dimostrati perfettamente con le 40 prestazioni extra necessarie per il nostro nuovo finale. Tuttavia, la frequenza fotogrammi su alcuni dispositivi mobili si è dimezzata.

Per ovviare a questo problema, abbiamo introdotto la nebbia. Dopo una certa distanza, tutto diventa nero. Poiché non dobbiamo calcolare o tracciare ciò che non è visibile, riduciamo le prestazioni nelle stanze che non sono visibili e questo ci consente di risparmiare il lavoro sia per la CPU che per la GPU. Ma come decidere la distanza giusta?

Alcuni dispositivi sono in grado di sopportare qualsiasi cosa, mentre altri sono più restrittivi. Abbiamo scelto di implementare una scala scorrevole. Misurando continuamente la quantità di fotogrammi al secondo, possiamo regolare di conseguenza la distanza della nebbia. Se la frequenza fotogrammi funziona senza problemi, proviamo a svolgere più operazioni di rendering spingendo la nebbia. Se la frequenza fotogrammi non è abbastanza fluida, avviciniamo la nebbia, in modo da saltare le prestazioni di rendering al buio.

// this is called every frame
// the FPS calculation is based on stats.js by @mrdoob
tick: (interval = 3000) => {
    frames++;
    const time = (performance || Date).now();
    if (prevTime == null) prevTime = time;
    if (time > prevTime + interval) {
    fps = Math.round((frames * 1000) / (time - prevTime));
    frames = 0;
    prevTime = time;
    const lastCullDistance = settings.cullDistance;

    // if the fps is lower than 52 reduce the cull distance
    if (fps <= 52) {
        settings.cullDistance = Math.max(
        settings.minCullDistance,
        settings.cullDistance - settings.roomDepth
        );
    }
    // if the FPS is higher than 56, increase the cull distance
    else if (fps > 56) {
        settings.cullDistance = Math.min(
        settings.maxCullDistance,
        settings.cullDistance + settings.roomDepth
        );
    }
    }

    // gradually increase the cull distance to the new setting
    cullDistance = cullDistance * 0.95 + settings.cullDistance * 0.05;

    // mask the edge of the cull distance with fog
    viewer.fog.near = cullDistance - settings.roomDepth;
    viewer.fog.far = cullDistance;
}

Ce n'è per tutti i gusti: creare la VR per il web

Progettare e sviluppare esperienze multipiattaforma e asimmetriche significa tenere conto delle esigenze di ogni utente in base al dispositivo utilizzato. E a ogni decisione di progettazione, dovevamo capire quale sarebbe l'impatto sugli altri utenti. Come ci si assicura che ciò che si vede in VR sia eccitante come senza VR e viceversa?

1. La sfera gialla

I nostri utenti VR con dimensioni di base realizzerebbero le esibizioni, ma come vivrebbero il progetto gli utenti di dispositivi VR mobili (come Cardboard, Daydream View o Samsung Gear)? Per questo motivo, abbiamo introdotto un nuovo elemento nel nostro ambiente: la sfera gialla.

La sfera gialla
La sfera gialla

Quando guardi il progetto in VR, lo fai dal punto di vista della sfera gialla. Mentre fluttuano da una stanza all'altra, i ballerini reagiscono alla tua presenza. Ti fanno i gesti, ballano intorno a te, fanno movimenti divertenti dietro la schiena e si allontanano rapidamente per evitare di colpirti contro di te. La sfera gialla è sempre al centro dell'attenzione.

Il motivo è che durante la registrazione di un'esibizione, la sfera gialla si sposta al centro della stanza in sincronizzazione con la musica e si ripiega. La posizione della sfera dà all'artista un'idea di dove si trova nel tempo e di quanto tempo è rimasto nel suo loop. Offre loro l'obiettivo naturale di creare un rendimento in base.

2. Un altro punto di vista

Non volevamo escludere gli utenti senza VR, soprattutto perché sarebbero stati probabilmente il nostro pubblico più numeroso. Invece di creare un'esperienza VR falsa, volevamo offrire ai dispositivi basati su schermo un'esperienza personale. Abbiamo avuto l'idea di mostrare i risultati dal punto di vista isometrico. Questa prospettiva ha una ricca storia nel campo dei giochi per computer. È stato utilizzato per la prima volta in Zaxxon, uno sparatutto spaziale del 1982. Mentre gli utenti di realtà virtuale lo fanno, la prospettiva isometrica offre una visione divina dell'azione. Abbiamo scelto di ingrandire leggermente i modelli, per dare un tocco estetico alla casa delle bambole.

3. Ombre: finchè non ce la fai

Abbiamo scoperto che per alcuni nostri utenti faticava a vedere la profondità nel nostro punto di vista isometrico. Sono sicura che sia per questo motivo che Zaxxon è stato anche uno dei primi giochi per computer della storia a proiettare un'ombra dinamica sotto i suoi oggetti volanti.

Ombre

Ho scoperto che creare ombre in 3D è difficile. Soprattutto per i dispositivi stretti, come i cellulari. Inizialmente abbiamo dovuto prendere la difficile decisione di escluderli dall'equazione, ma dopo aver chiesto consiglio all'autore di Three.js e all'esperto demo hacker Mr doob, è venuto l'idea di... falso.

Anziché dover calcolare in che modo ciascuno dei nostri oggetti fluttuanti nasconde la luce e, di conseguenza, genera ombre di forme diverse, disegniamo la stessa immagine circolare di texture sfocata sotto ciascuno di essi. Poiché le nostre immagini non cercano di imitare la realtà, abbiamo scoperto che potremmo farla franca molto facilmente con poche modifiche. Quando gli oggetti si avvicinano al pavimento, le texture diventano più scure e più piccole. Quando si spostano in alto, le texture più trasparenti e più grandi.

Per crearle, abbiamo utilizzato questa texture con un gradiente da bianco a nero tenue (senza trasparenza alfa). Impostiamo il materiale come trasparente e utilizziamo una combinazione sottrattiva. Questo li aiuta a integrarsi perfettamente quando si sovrappongono:

function createShadow() {
    const texture = new THREE.TextureLoader().load(shadowTextureUrl);
    const material = new THREE.MeshLambertMaterial({
        map: texture,
        transparent: true,
        side: THREE.BackSide,
        depthWrite: false,
        blending: THREE.SubtractiveBlending,
    });
    const geometry = new THREE.PlaneBufferGeometry(0.5, 0.5, 1, 1);
    const plane = new THREE.Mesh(geometry, material);
    return plane;
    }

4. Presenza

Facendo clic sulla testa di un artista, i visitatori che non hanno la realtà virtuale possono osservare le cose dal punto di vista del ballerino. Da questo punto di vista, diventano evidenti molti piccoli dettagli. Cercando di mantenere le performance al passo, i ballerini si scambiano rapidamente uno sguardo. Quando la sfera entra nella stanza, la vedi guardare nervosamente nella sua direzione. Anche se uno spettatore non può influenzare questi movimenti, trasmette sorprendentemente bene la sensazione di immersione. Ancora una volta, abbiamo preferito optare per questa soluzione piuttosto che presentare ai nostri utenti una versione VR fittizia controllata con il mouse.

5. Condivisione delle registrazioni

Sappiamo quanto tu possa essere orgoglioso di realizzare una registrazione complessa con una coreografia di 20 livelli di artisti che reagiscono l'uno all'altro. Sapevamo che i nostri utenti probabilmente vorranno mostrarlo ai loro amici. Ma un fermo immagine di questa impresa non comunica abbastanza. Volevamo invece permettere ai nostri utenti di condividere un video delle loro performance. In realtà, perché non una GIF? Le nostre animazioni sono piatte, perfette per le tavolozze dei colori limitate del formato.

Condivisione delle registrazioni

Abbiamo adottato GIF.js, una libreria JavaScript che consente di codificare GIF animate dall'interno del browser. Esegue la migrazione della codifica dei frame ai web worker, che sono in grado di essere eseguiti in background come processi separati, riuscendo così a sfruttare più processori che lavorano fianco a fianco.

Purtroppo, a causa del numero di frame necessari per le animazioni, il processo di codifica era ancora troppo lento. La GIF è in grado di creare file di piccole dimensioni utilizzando una tavolozza dei colori limitata. Abbiamo scoperto che la maggior parte del tempo veniva dedicata a trovare il colore più vicino a ciascun pixel. Siamo riusciti a ottimizzare questo processo di dieci volte hackerando in una piccola scorciatoia: se il colore del pixel è lo stesso dell'ultimo, usa lo stesso colore della tavolozza di prima.

Ora avevamo codifiche veloci, ma i file GIF risultanti erano troppo grandi. Il formato GIF consente di indicare in che modo ogni frame deve essere visualizzato sopra l'ultimo definendone il metodo di eliminazione. Per ottenere file più piccoli, invece di aggiornare ogni pixel ogni frame, aggiorniamo solo i pixel modificati. Rallentare nuovamente il processo di codifica, tuttavia, riduceva notevolmente le dimensioni dei file.

6. Terra solida: Google Cloud e Firebase

Il backend di un sito con "contenuti generati dagli utenti" può essere spesso complicato e fragile, ma abbiamo creato un sistema semplice e solido grazie a Google Cloud e Firebase. Quando un esecutore carica una nuova danza nel sistema, viene autenticato in modo anonimo da Firebase Authentication. Avrà l'autorizzazione a caricare la propria registrazione in uno spazio temporaneo utilizzando Cloud Storage for Firebase. Al termine del caricamento, il computer client chiama un trigger HTTP di Cloud Functions for Firebase utilizzando il token Firebase. Questo attiva un processo server che convalida l'invio, crea un record di database e sposta la registrazione in una directory pubblica su Google Cloud Storage.

Terra piena

Tutti i nostri contenuti pubblici sono archiviati in una serie di file flat in un bucket Cloud Storage. Ciò significa che i nostri dati sono rapidamente accessibili in tutto il mondo e non dobbiamo preoccuparci che carichi di traffico elevati influiscano in alcun modo sulla disponibilità dei dati.

Abbiamo utilizzato endpoint Firebase Realtime Database e funzioni Cloud Functions per creare un semplice strumento di moderazione/selezione che ci consente di guardare ogni nuovo invio in VR e di pubblicare nuove playlist da qualsiasi dispositivo.

7. Service worker

I service worker sono un'innovazione abbastanza recente che consente di gestire la memorizzazione nella cache degli asset del sito web. Nel nostro caso, i Service worker caricano i nostri contenuti con una velocità estrema per i visitatori di ritorno e permettono persino il funzionamento offline del sito. Si tratta di funzioni importanti, dal momento che molti dei nostri visitatori utilizzano connessioni mobili di qualità diversa.

Aggiungere un service worker al progetto è stato facile grazie a un pratico plug-in Webpack che gestisce per te la maggior parte dei lavori più complessi. Nella configurazione seguente, generiamo un service worker che memorizza automaticamente nella cache tutti i nostri file statici. Verrà estratto il file della playlist più recente dalla rete, se disponibile, poiché la playlist verrà aggiornata continuamente. Tutti i file JSON delle registrazioni devono essere estratti dalla cache, se disponibili, perché non cambieranno mai.

const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
config.plugins.push(
    new SWPrecacheWebpackPlugin({
    dontCacheBustUrlsMatching: /\.\w{8}\./,
    filename: 'service-worker.js',
    minify: true,
    navigateFallback: 'index.html',
    staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
    runtimeCaching: [{
        urlPattern: /playlist\.json$/,
        handler: 'networkFirst',
    }, {
        urlPattern: /\/recordings\//,
        handler: 'cacheFirst',
        options: {
        cache: {
            maxEntries: 120,
            name: 'recordings',
        },
        },
    }],
    })
);

Attualmente, il plug-in non gestisce risorse multimediali caricate progressivamente come i file musicali, pertanto abbiamo risolto il problema impostando l'intestazione Cloud Storage Cache-Control di questi file su public, max-age=31536000, in modo che il browser memorizzi nella cache il file per un massimo di un anno.

Conclusione

Non vediamo l'ora di vedere come gli artisti applicheranno questa esperienza e la useranno come strumento per l'espressione creativa usando il movimento. Abbiamo rilasciato tutto il codice open source, che puoi trovare all'indirizzo https://github.com/puckey/dance-tonite. In questi primi giorni di realtà virtuale, e soprattutto di WebVR, non vediamo l'ora di scoprire quali nuove creatività e direzioni inaspettate prenderà questo nuovo mezzo. Balla grande.