Chrome

Kim Asendorf & Leander Herzog
CHROME, collection of 128 channels, 2023

On-Chain multi-channel real-time animation
JavaScript, GLSL, variable dimensions
Ethereum smart contract

View the collection on OpenSea.

PRE-SALE28 Feb, 6 PM CET: Ξ0.5

PUBLIC MINT1 March, 6 PM CET: Ξ0.5

×

Chrome plays with the potential of contemporary software and hardware, from generative realtime graphics and custom smart contracts, to displays with ever increasing resolution and quality. The onchain software work responds to screen size and builds directly on the pixels of the specific display it runs on.

Chrome is a 128 channel realtime animation, coordinated by universal time (UTC). It emerges from a continuous linear motion, interrupted by a choreography between rhythm and random. Every channel is offset one additional second into the future, based on the token id assigned by the custom smart contract. This relation becomes visible when multiple channels are running in a shared space. Compositions emerge and evolve at various regular intervals, without ever repeating. Once per hour the synchronization stops and all channels act individually, before they transition back to coordination.

On March 1, 6PM CET, the 128 channels of Chrome can be minted, in sets of 8 channels (consecutive token ids), in pairs of 2, or as single channel. A 24h pre-sale starts 28 Feb 6PM CET, for collectors on the allowlist.

A "set" is 8 tokens with consecutive ids and time offsets. A pair is 2 tokens with consecutive ids and time offsets. Collectors of multiple channels can display them together and see the time difference, the synchronization and the choreography that emerges between them.

The custom smart contract stores the 15kb code of the work on the ethereum blockchain. It also enables minting sets with consecutive token ids in a single transaction. Check out the collection on OpenSea.

<!DOCTYPE HTML><html><head><meta name='viewport' content='width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=2.0'></head><body><script>let tId=1;let GL=()=>{let cv,gl,vSh,fSh,gSh,mSh,vBf,fPr,gPr,mPr,gFbo,fFbos,fFboId=0,fX,fY,fW,fH,bAr,bxs,imgTx,imgFrmL=0,imgFrmC=0,cBx,bCl,tOf,gri=16,gPx=0,gCl=[255,255,255],gVs=true,eAr=[],eL=[1800,7200,300,3600,7200,14400],eId=-1,eT=-1;let dcd=decodeURIComponent;let{floor,max,pow,random}=Math;let shAr=a=>{a.sort(()=>random()-.5)};let swIt=a=>{let i1=floor(random()*a.length);let i2=floor(random()*a.length);let i=a[i1];a[i1]=a[i2];a[i2]=i};let getTOf=()=>{let d=new Date;let da=d.getDate();let m=d.getMonth();let y=d.getFullYear();let f=new Date(y,m,da,0,0,0,0);return d.getTime()-f.getTime()};let ini=async()=>{tOf=getTOf()-(tId-1)*1e3;vSh='in vec3 pos;out vec2 vUv;void main(){gl_Position=vec4(pos,1.);vUv=.5*(pos.xy+1.);}';fSh='uniform sampler2D bfr,img;uniform vec2 res;uniform float t;uniform vec4[8] bxs;in vec2 vUv;out vec4 frag;float ib(vec2 v,vec2 bl,vec2 tr){vec2 s=step(bl,v)-step(tr,v);return s.x*s.y;}float rand(vec2 co){return fract(sin(dot(co.xy,vec2(12.9898,78.233)))*43758.5453);}float oscSin(float x){return sin(x*.1)*.4;}float oscSqr(float x){return mod((x*.025),1.)<.5?-.5:.5;}float oscTri(float x){return abs(mod((x*.03),(.5*2.))-.5);}float hash(float n){return fract(sin(n)*1e4);}float noise(vec3 x){const vec3 step=vec3(110,241,171);vec3 i=floor(x);vec3 f=fract(x);float n=dot(i,step);vec3 u=f*f*(3.-2.*f);return mix(mix(mix(hash(n+dot(step,vec3(0,0,0))),hash(n+dot(step,vec3(1,0,0))),u.x),mix(hash(n+dot(step,vec3(0,1,0))),hash(n+dot(step,vec3(1,1,0))),u.x),u.y),mix(mix(hash(n+dot(step,vec3(0,0,1))),hash(n+dot(step,vec3(1,0,1))),u.x),mix(hash(n+dot(step,vec3(0,1,1))),hash(n+dot(step,vec3(1,1,1))),u.x),u.y),u.z);}void main(){vec3 col=texture(bfr,vUv).rgb;vec2 pos=floor(vUv*res);if(pos.x==0.){col=texture(img,vUv).rgb;}if(ib(pos,vec2(bxs[0].x,bxs[0].y),vec2(bxs[0].x+bxs[0].z,bxs[0].y+bxs[0].w))>=1.){float y=(noise(vec3(vUv.x*.048,vUv.y*64.,t*1.6))-.5)*2.;vec2 of=vec2(1./res.x,1./res.y*y);col=texture(bfr,vUv-of).rgb;}if(ib(pos,vec2(bxs[1].x,bxs[1].y),vec2(bxs[1].x+bxs[1].z,bxs[1].y+bxs[1].w))>=1.){float x=oscSqr(pos.y)*2.;float y=mod(oscSin(t*2.4+pos.y*2.)*1.,2.)-1.;vec2 of=vec2(1./res.x*x,1./res.y*y);col=texture(bfr,vUv-of).rgb;}if(ib(pos,vec2(bxs[2].x,bxs[2].y),vec2(bxs[2].x+bxs[2].z,bxs[2].y+bxs[2].w))>=1.){float y=0.;if(mod(pos.x,floor(t))<=4.){y+=1.;}if(mod(pos.y*10.,floor(t))<=4.){y-=1.;}vec2 of=vec2(1./res.x,1./res.y*y);col=texture(bfr,vUv-of).rgb;}if(ib(pos,vec2(bxs[3].x,bxs[3].y),vec2(bxs[3].x+bxs[3].z,bxs[3].y+bxs[3].w))>=1.){vec2 of=vec2(1./res.x,0.);col=vec3(1.,1.,1.)-texture(bfr,vUv-of).rgb;}if(ib(pos,vec2(bxs[4].x,bxs[4].y),vec2(bxs[4].x+bxs[4].z,bxs[4].y+bxs[4].w))>=1.){vec2 of=vec2(1./res.x,(noise(vec3(vUv.xx,t*10.))-.5)*2./res.y);col=texture(bfr,vUv-of).rgb;}if(ib(pos,vec2(bxs[5].x,bxs[5].y),vec2(bxs[5].x+bxs[5].z,bxs[5].y+bxs[5].w))>=1.){vec2 of=vec2(1./res.x,0.);col=texture(bfr,vUv-of).rgb;if(rand(pos+t)<.004){col+=vec3(1.,1.,1.);}else{col=vec3(1.,1.,1.)-col;}}if(ib(pos,vec2(bxs[6].x,bxs[6].y),vec2(bxs[6].x+bxs[6].z,bxs[6].y+bxs[6].w))>=1.){vec2 of=vec2(1./res.x,1./res.y*(oscTri(t*8.)-.25)*3.);col=texture(bfr,vUv-of).rgb;}if(ib(pos,vec2(bxs[7].x,bxs[7].y),vec2(bxs[7].x+bxs[7].z,bxs[7].y+bxs[7].w))>=1.){float dy=mod(pos.y,32.)<16.?10.:-10.;vec2 of=vec2(1./res.x,1./res.y*dy);col=texture(bfr,vUv-of).rgb;}frag=vec4(col,1.);}';gSh='uniform vec2 res;uniform float t;in vec2 vUv;out vec4 frag;vec3 mod289(vec3 x){return x-floor(x*(1./289.))*289.;}vec4 mod289(vec4 x){return x-floor(x*(1./289.))*289.;}vec4 permute(vec4 x){return mod289(((x*34.)+1.)*x);}vec4 tInvSqrt(vec4 r){return 1.79284291400159-0.85373472095314*r;}vec3 fade(vec3 t){return t*t*t*(t*(t*6.-15.)+10.);}/*Classic Perlin noise,Copyright(c)2011 Stefan Gustavson.All rights reserved.https://github.com/ashima/webgl-noise*/float pnoise(vec3 P,vec3 rep){vec3 Pi0=mod(floor(P),rep);vec3 Pi1=mod(Pi0+vec3(1.),rep);Pi0=mod289(Pi0);Pi1=mod289(Pi1);vec3 Pf0=fract(P);vec3 Pf1=Pf0-vec3(1.);vec4 ix=vec4(Pi0.x,Pi1.x,Pi0.x,Pi1.x);vec4 iy=vec4(Pi0.yy,Pi1.yy);vec4 iz0=Pi0.zzzz;vec4 iz1=Pi1.zzzz;vec4 ixy=permute(permute(ix)+iy);vec4 ixy0=permute(ixy+iz0);vec4 ixy1=permute(ixy+iz1);vec4 gx0=ixy0*(1./7.);vec4 gy0=fract(floor(gx0)*(1./7.))-.5;gx0=fract(gx0);vec4 gz0=vec4(.5)-abs(gx0)-abs(gy0);vec4 sz0=step(gz0,vec4(0.));gx0-=sz0*(step(0.,gx0)-.5);gy0-=sz0*(step(0.,gy0)-.5);vec4 gx1=ixy1*(1./7.);vec4 gy1=fract(floor(gx1)*(1./7.))-.5;gx1=fract(gx1);vec4 gz1=vec4(.5)-abs(gx1)-abs(gy1);vec4 sz1=step(gz1,vec4(0.));gx1-=sz1*(step(0.,gx1)-.5);gy1-=sz1*(step(0.,gy1)-.5);vec3 g000=vec3(gx0.x,gy0.x,gz0.x);vec3 g100=vec3(gx0.y,gy0.y,gz0.y);vec3 g010=vec3(gx0.z,gy0.z,gz0.z);vec3 g110=vec3(gx0.w,gy0.w,gz0.w);vec3 g001=vec3(gx1.x,gy1.x,gz1.x);vec3 g101=vec3(gx1.y,gy1.y,gz1.y);vec3 g011=vec3(gx1.z,gy1.z,gz1.z);vec3 g111=vec3(gx1.w,gy1.w,gz1.w);vec4 norm0=tInvSqrt(vec4(dot(g000,g000),dot(g010,g010),dot(g100,g100),dot(g110,g110)));g000*=norm0.x;g010*=norm0.y;g100*=norm0.z;g110*=norm0.w;vec4 norm1=tInvSqrt(vec4(dot(g001,g001),dot(g011,g011),dot(g101,g101),dot(g111,g111)));g001*=norm1.x;g011*=norm1.y;g101*=norm1.z;g111*=norm1.w;float n000=dot(g000,Pf0);float n100=dot(g100,vec3(Pf1.x,Pf0.yz));float n010=dot(g010,vec3(Pf0.x,Pf1.y,Pf0.z));float n110=dot(g110,vec3(Pf1.xy,Pf0.z));float n001=dot(g001,vec3(Pf0.xy,Pf1.z));float n101=dot(g101,vec3(Pf1.x,Pf0.y,Pf1.z));float n011=dot(g011,vec3(Pf0.x,Pf1.yz));float n111=dot(g111,Pf1);vec3 fade_xyz=fade(Pf0);vec4 n_z=mix(vec4(n000,n100,n010,n110),vec4(n001,n101,n011,n111),fade_xyz.z);vec2 n_yz=mix(n_z.xy,n_z.zw,fade_xyz.y);float n_xyz=mix(n_yz.x,n_yz.y,fade_xyz.x);return 2.2*n_xyz;}void main(){vec2 rel=vec2(max(res.xy/res.yx,vec2(1.)));float r=pnoise(vec3(vUv*rel*1.7,t*.04),vec3(141.,50.2,455.3));float g=pnoise(vec3(vUv*rel*1.6,t*.041),vec3(25.,1.,333.3));float b=pnoise(vec3(vUv*rel*1.5,t*.042),vec3(100.1,644.,23.23));vec3 col=vec3(r,g,b)*2.;if(g>b){discard;}frag=vec4(col,1.);}';mSh='uniform float grid;uniform vec2 res;uniform sampler2D fb,gd;uniform vec4 fBox,cBx;uniform vec3 bCl,gCl;uniform bool gVs;in vec2 vUv;out vec4 frag;float ib(vec2 v,vec2 bl,vec2 tr){vec2 s=step(bl,v)-step(tr,v);return s.x*s.y;}void main(){vec4 col=texture(gd,vUv);vec2 pos=floor(vec2(vUv.x*res.x,(1.-vUv.y)*res.y));frag=texture(gd,vUv);if(ib(pos,vec2(cBx.x,cBx.y),vec2(cBx.x+cBx.z,cBx.y+cBx.w))>=1.){frag=vec4(bCl,1.);}if(gVs){if(mod(pos.x,grid)==0.&&mod(pos.y,grid)==0.){frag=vec4(gCl,1.);}}if(ib(pos,vec2(fBox.x,fBox.y),vec2(fBox.x+fBox.z,fBox.y+fBox.w))>=1.){vec2 fUv=(pos-fBox.xy)/(fBox.zw-vec2(1.,1.));frag=texture(fb,fUv);}}';cv=document.createElement('canvas');cv.style.width=cv.style.height='100%';cv.style.verticalAlign='bottom';document.body.append(cv);gl=cv.getContext('webgl2',{antialias:true,preserveDrawingBuffer:true,willReadFrequently:true});gl.blendFunc(gl.ONE,gl.ONE_MINUS_SRC_ALPHA);gl.disable(gl.BLEND);gl.disable(gl.DEPTH_TEST);gl.clearColor(0,0,0,1);vBf=crBf([-1,1,0,-1,-1,0,1,1,0,1,-1,0]);fPr=crPr(vSh,fSh);gPr=crPr(vSh,gSh);mPr=crPr(vSh,mSh);return gl};let seClFs=(w,h,c)=>{cBx=[0,0,w,h];bCl=c;gCl=[255-c[0],255-c[1],255-c[2]]};let rsClFs=()=>{cBx=[0,0,0,0];bCl=[0,0,0];gCl=[255,255,255]};let upClFs=()=>{if(eT%8==0){bCl=[255,0,0];gCl=[0,0,255]}else{bCl=[0,0,255];gCl=[255,0,0]}};let seFbLay=(w,h)=>{let gR=floor(h/gPx);fW=w;fX=0;let lm=(tId-1)%8;switch(lm){case 0:fH=gPx*1;fY=gPx*gR-fH;break;case 1:fH=gPx*2;fY=gPx*gR-fH;break;case 2:fH=gPx*3;fY=gPx*gR-fH;break;case 3:fH=gPx*1;fY=gPx*floor(gR/2);break;case 4:fH=gPx*2;fY=fY=gPx*floor(gR/2)-gPx;break;case 5:fH=gPx*3;fY=0;break;case 6:fH=gPx*2;fY=0;break;case 7:fH=gPx*1;fY=0;break;default:break}};let setFbFs=(w,h)=>{fX=fY=0;fW=w;fH=h};let seFbBxs=(w,h)=>{bAr=[];let v=Array.from({length:7},()=>floor(random()*w));v.sort((a,b)=>{return a-b});let x=1;for(let i=0;i<v.length;i++){bAr.push([x,0,v[i]-x,h]);x=v[i]}bAr.push([x,0,w-x,h]);shAr(bAr);bxs=bAr.flat()};let seFbBx=(w,h)=>{bAr=Array(8).fill([0,0,0,0]);bAr[floor(random()*8)]=[1,0,w,h];bxs=bAr.flat()};let seDbFbBx=(w,h)=>{let i=[...Array(8).keys()];shAr(i);let s=floor(random()*w);bAr=Array(8).fill([0,0,0,0]);bAr[i[0]]=[1,0,s,h];bAr[i[1]]=[s,0,w-s,h];bxs=bAr.flat()};let isCa=false;let caId=0;let caT=0;let setCa=()=>{caT=0;isCa=true};let upCa=(w,h)=>{if(caT<=0){eAr[caId].r(w,h);caId=floor(random()*5);eAr[caId].s(w,h);caT=60+floor(random()*240)}else{eAr[caId].u(w,h)}caT--};let rsCa=(w,h)=>{eAr[caId].r(w,h);isCa=false};let seFb=(w,h)=>{imgTx=crTx(1,h,crPx(1,h));for(let f in fFbos){gl.deleteFramebuffer(f.fbo);gl.deleteTexture(f.tx)}fFbos=[];fFbos.push(crFbo(w,h,null));fFbos.push(crFbo(w,h,null));fFboId=0};let se=(w,h,s)=>{if(max(w/h,1)==1){gPx=floor(w/gri)}else{gPx=floor(h/gri)}cBx=[0,0,0,0];bCl=[0,0,0];seFbLay(w,h);seFbBxs(fW,fH);seFb(fW,fH);if(gFbo){gl.deleteFramebuffer(gFbo.fbo);gl.deleteTexture(gFbo.tx)}gFbo=crFbo(w*s,h*s,null)};let rz=s=>{if(cv.width!=cv.clientWidth*s||cv.height!=cv.clientHeight*s){cv.width=cv.clientWidth*s;cv.height=cv.clientHeight*s;return[cv.width/s,cv.height/s]}return false};eAr[0]={s:(w,h)=>{seClFs(w,h,[0,0,0])},u:()=>{},r:rsClFs};eAr[1]={s:(w,h)=>{seClFs(w,h,[255,255,255])},u:()=>{},r:rsClFs};eAr[2]={s:(w,h)=>{seClFs(w,h,[0,0,255])},u:upClFs,r:rsClFs};eAr[3]={s:(w,h)=>{setFbFs(w,h);let id=floor(random()*3);switch(id){case 0:seFbBxs(fW,fH);break;case 1:seFbBx(fW,fH);break;case 2:seDbFbBx(fW,fH);break;default:break}seFb(fW,fH)},u:()=>{},r:(w,h)=>{seFbLay(w,h);seFbBxs(fW,fH);seFb(fW,fH)}};eAr[4]={s:()=>{setFbFs(0,0);gVs=false},u:()=>{},r:(w,h)=>{seFbLay(w,h);seFbBxs(fW,fH);seFb(fW,fH);gVs=true}};eAr[5]={s:setCa,u:upCa,r:rsCa};let upEv=(w,h)=>{let ms=getTOf()-(tId-1)*200;let s=floor(ms/1e3);let m=floor(s/60);if(!isCa&&m%60==0&&s%60==0){eId=5;eAr[eId].s(w,h);eT=eL[eId]}if(eT<=0){if(eT==0){eAr[eId].r(w,h);eId=-1}else{if(m%33==0&&s%60==0){eId=0}else if(m%33==16&&s%60==0){eId=1}else if(m%19==0&&s%60==0){eId=4}else if(m%5==0&&s%60==47){eId=3}else if(m%3==0&&s%60==23){eId=2}if(eId>=0){eAr[eId].s(w,h);eT=eL[eId]}}}else if(eT>0){eAr[eId].u(w,h)}eT--};let upImgTx=h=>{if(imgFrmL==imgFrmC){imgTx=crTx(1,h,crPx(1,h));imgFrmL=pow(2,4+floor(random()*4));imgFrmC=0}imgFrmC++};let rn=(w,h,s,t)=>{upEv(w,h);if(random()<.01){swIt(bAr);bxs=bAr.flat()}upImgTx(fH);rnF(fW,fH,t);rnG(w,h,s,t);rnM(w,h,s)};let sePr=p=>{gl.useProgram(p);p.vertexPosAttrib=gl.getAttribLocation(p,'pos');gl.enableVertexAttribArray(p.vertexPosAttrib);gl.bindBuffer(gl.ARRAY_BUFFER,vBf);gl.vertexAttribPointer(p.vertexPosAttrib,3,gl.FLOAT,false,0,0)};let rnF=(w,h,t)=>{let pId=fFboId;let cId=fFboId^=1;sePr(fPr);gl.bindFramebuffer(gl.FRAMEBUFFER,fFbos[cId].fbo);gl.viewport(0,0,w,h);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);gl.activeTexture(gl.TEXTURE0+pId);gl.bindTexture(gl.TEXTURE_2D,fFbos[pId].tx);gl.activeTexture(gl.TEXTURE0+2);gl.bindTexture(gl.TEXTURE_2D,imgTx);gl.uniform1f(gl.getUniformLocation(fPr,'t'),t/1e3);gl.uniform4fv(gl.getUniformLocation(fPr,'bxs'),bxs);gl.uniform2f(gl.getUniformLocation(fPr,'res'),w,h);gl.uniform1i(gl.getUniformLocation(fPr,'bfr'),pId);gl.uniform1i(gl.getUniformLocation(fPr,'img'),2);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};let rnG=(w,h,s,t)=>{sePr(gPr);gl.bindFramebuffer(gl.FRAMEBUFFER,gFbo.fbo);gl.viewport(0,0,w*s,h*s);gl.uniform1f(gl.getUniformLocation(gPr,'t'),(t+tOf)/1e3);gl.uniform2f(gl.getUniformLocation(gPr,'res'),w,h);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};let rnM=(w,h,s)=>{sePr(mPr);gl.bindFramebuffer(gl.FRAMEBUFFER,null);gl.viewport(0,0,w*s,h*s);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);gl.activeTexture(gl.TEXTURE0+fFboId);gl.bindTexture(gl.TEXTURE_2D,fFbos[fFboId].tx);gl.activeTexture(gl.TEXTURE0+2);gl.bindTexture(gl.TEXTURE_2D,gFbo.tx);gl.uniform2f(gl.getUniformLocation(mPr,'res'),w,h);gl.uniform1f(gl.getUniformLocation(mPr,'grid'),gPx);gl.uniform4fv(gl.getUniformLocation(mPr,'fBox'),[fX,fY,fW,fH]);gl.uniform4fv(gl.getUniformLocation(mPr,'cBx'),cBx);gl.uniform3fv(gl.getUniformLocation(mPr,'bCl'),bCl);gl.uniform3fv(gl.getUniformLocation(mPr,'gCl'),gCl);gl.uniform1i(gl.getUniformLocation(mPr,'gVs'),gVs);gl.uniform1i(gl.getUniformLocation(mPr,'fb'),fFboId);gl.uniform1i(gl.getUniformLocation(mPr,'gd'),2);gl.drawArrays(gl.TRIANGLE_STRIP,0,4)};let crPr=(v,f)=>{let p=gl.createProgram();let vs=crSh(dcd('%23version 300 es%0A')+v,gl.VERTEX_SHADER);let fs=crSh(dcd('%23version 300 es%0Aprecision highp float;')+f,gl.FRAGMENT_SHADER);gl.attachShader(p,vs);gl.attachShader(p,fs);gl.linkProgram(p);return p};let crSh=(sr,tp)=>{let s=gl.createShader(tp);gl.shaderSource(s,sr);gl.compileShader(s);return s};let crFbo=(w,h,p)=>{let f=gl.createFramebuffer();let t=crTx(w,h,p);gl.bindFramebuffer(gl.FRAMEBUFFER,f);gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,t,0);return{fbo:f,tx:t}};let crTx=(w,h,p)=>{let t=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,t);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,w,h,0,gl.RGBA,gl.UNSIGNED_BYTE,p);return t};let crBf=d=>{let b=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,b);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(d),gl.STATIC_DRAW);return b};let crPx=(w,h)=>{let b=pow(2,1+floor(random()*4));let u=new Uint8Array(w*h*4);for(let i=0;i<w*h;i++){let c=i%b==0?255:0;u[i*4]=u[i*4+1]=u[i*4+2]=c;u[i*4+3]=255;if(random()<.1)b=pow(2,1+floor(random()*4))}return u};return{ini:ini,se:se,rn:rn,rz:rz}};let Bdl=()=>{let gl,scl,dims;let ini=async()=>{document.querySelector('html').style.height='100%';let bs=document.body.style;bs.margin=0;bs.height='100%';bs.overflow='hidden';bs.background='black';gl=GL();let glCtx=await gl.ini();scl=Math.min(window.devicePixelRatio,2);dims=gl.rz(scl);set();ani(0);document.addEventListener('visibilitychange',async()=>{if(!document.hidden){if(glCtx.isContextLost()){location.reload()}}})};let set=()=>{gl.se(dims[0],dims[1],scl)};let ani=time=>{let resized=gl.rz(scl);if(resized){scl=Math.min(window.devicePixelRatio,2);dims=resized;set()}gl.rn(dims[0],dims[1],scl,time);requestAnimationFrame(ani)};return{ini:ini}};let b=Bdl();b.ini();</script></body></html>

From Feb 1 to Feb 28, Chrome is presented as a site specific installation. A stack of 8 displays shows the first 8 of 128 Chrome channels, visualizing the 1 second offsets as 1 meter offsets in physical space.

source code

For collectors of multiple Chrome channels: Chrome channels are coordinated by universal time (UTC). To show them together, machines should have accurate time: Under reasonable operating conditions, systems can be configured to maintain 1ms (millisecond) accuracy or better (with respect to UTC). Configuring Systems for High Accuracy
You can have the date and time set automatically using a network time server. Set the date and time on your Mac

Thank you to Ernst-Hermann Asendorf for helping with craft, Thomas Brüggemann and Danny Franzreb for photography and videography, and to our friends and family for feedback and support.