# data[].attributes.blurb.html
The web is a weird and wonderful place, but it is so much more than what is happening in that browser window. We’re going on a journey to find the web in some really strange places. From using audio to draw SVG images on old 1980’s oscilloscopes to a CSS-controlled flamethrower - if permitted by local law. From a JavaScript-based “bad clock” that can’t seem to tell the correct time, to the offline dinosaur game on a laser projector. What do all these have in common? They are all a little bit out there and were so much fun to create. They use modern web standards and require a little bit of that weird and wonderful from the web.

# data[].attributes.slidedeck.data[].slides[].desc.html
Hi… I’m Niels. First of all, thanks to Vasilis for inviting me. It’s been a lovely conference… so far… and I loved hearing about what everybody wants the web to be.

# data[].attributes.slidedeck.data[].slides[].desc.html
And we’ve seen the web can be many different things to many people. But I do want to talk a bit about the web I want. The web I want is created by and for people – like you and me. The best part of the web has always been the web as an expression of creativity. Or sometimes as an expression of an healthy personal obsession. I fell in love with the web back in 1993 in the time of De Digital Stad and Geocities where people shared whatever was on their mind. I can still get truly delighted by visiting a website. Not often, but the work the students here made was truly delightful. And that is not because of the technology that is used, but by the creativity. For me the web is weird, wonderful, fun, inspiring and creative place

# data[].attributes.slidedeck.data[].slides[].desc.html
Now I too get obsessed sometimes. And I really think that is a healthy thing. For me an obsession is often a period of focus and creativity and sometimes unexpected, and sometimes slightly unhinged results. It’s healthy to care about something – even though you may be the only one that cares. I call them obsessions, but you can also call it inspiration.

# data[].attributes.slidedeck.data[].slides[].desc.html
One of my latest projects was recreating DOOM - a game from 1993 - completely in CSS. Every wall, every floor, every barrel, every enemy is a div. Rotated into 3D space using CSS 3D transforms. You can play it on cssdoom.wtf… even works on you phone… not now… la-ter…

# data[].attributes.slidedeck.data[].slides[].desc.html
I do run a company called Salonhub – which makes software for hair salons – and that includes the whole point-of-sale system. So I started building an open source library for printing on receipt printers from the web. And that lead to me having a receipt printer collection. This is just a fraction of my total collection. But even these “serious” projects have unexpected results…

# data[].attributes.slidedeck.data[].slides[].desc.html
I created this Camera Boy project that allows you to take a selfie and print it using horrible dithering – just like the original Gameboy Camera. So all my serious hard work have not been for nothing.

# data[].attributes.slidedeck.data[].slides[].desc.html
Another project I did was creating a robot arm that plays the xylophone. Well…. It’s a little bit more complicated than that. You connect the headphone port of the keyboard to the microphone port of your computer. And when you play a note, a website that uses WebAudio analyses the sound and figures out the actual note. That page then uses WebMIDI to send the note to a second computer that also runs a webpage, picks up the MIDI note and then uses WebUSB to play the note on the xylophone. This feels like a musical Rube-Goldberg machine

# data[].attributes.slidedeck.data[].slides[].desc.html
But like Sanne said… The web should be optional – it often feels like the web is consuming all my time, but there is so much more that do not involve spending all my time behind a screen. Some people buy skateboards, but every year I travel to the arctic circle and try to photograph the northern lights, which… well I started out with just an iPhone and ended up with a special setup to shoot timelapses and dual cameras with special lenses and… It still definitely feels like an obsession. But even with all that technology, the best part is lying flat on your back - in the snow, minus 25 – and just watching the sky light up and just look and forget about that photo. Forget about that technology and be there in the moment.

# data[].attributes.slidedeck.data[].slides[].desc.html
I think there is a central theme in all of my obsessions and experiments. Sometimes it is heavily technical, but it is always something that connects on a personal level. Either through the unexpected or absurdity, or sometimes just nostalgia.

# data[].attributes.slidedeck.data[].slides[].desc.html
CssDOOM was not only to experiment with new CSS techniques, but also to relive some of that wonder of when I first saw DOOM back in 1993 and spend so, so much time playing that game.

# data[].attributes.slidedeck.data[].slides[].desc.html
Same thing with the Camera Boy… I took that with me to a conference and there was line of people wanting to take a terrible selfies. On some level the attendees connected with it. And that is what I want to web to be to. I do care about the technology, I think it is great. But what I care much more about is making connections. But that said. Lately I’ve been obsessed…

# data[].attributes.slidedeck.data[].slides[].desc.html
…with clocks. Maybe not as much as Vasilis – but still. And I am going to share a bit about that obsession, because the clocks I’ve build are all built using web technologies. And they are very much weird and wonderful. This is the web I want. I want the web to be a place where you can express your creativity.

# data[].attributes.slidedeck.data[].slides[].desc.html
But my fascination with clocks really started when I saw these clocks that Vasilis made. It really inspired me and dropped me head-first in a months long obsession with Raspberry Pis and touch screens. There was just one thing. For me personally a clock should be round. For me when I think of a clock it is always round. These are great. But my clock needed to be round. So I went on a quest to find a round touch screen.

# data[].attributes.slidedeck.data[].slides[].desc.html
And I found one. Meet project Bad Clock.

# data[].attributes.slidedeck.data[].slides[].desc.html
This project consists of several components – first that round screen that is just perfect for a clock. To be honest without that round screen I probably would have abandoned this project – it was perfect for what I had in mind. Connected to it is a Raspberry Pi 5 – which means lots of computing power – which we are going to need. I had plans. And of course some custom hardware, such as rotary encoder which you can use to wind the clock – something that a clock definitely needs

# data[].attributes.slidedeck.data[].slides[].desc.html
Meet our bad clock. It’s a perfect round screen. It does have some issues though. The screen flickers sometimes. Just like there is some bad solder joint. And just randomly numbers can stop working – which is not really good for a clock, but it’s not called Project Bad Clock for nothing.

# data[].attributes.slidedeck.data[].slides[].desc.html
One thing that is always annoying with clocks is summertime and wintertime. Nobody knows how that works. And every year we manually have to adjust all the clocks in our house and we never know how. Is it forwards, or backwards. And this is a world wide problem. On this map you see an overview of the different DSTs. In the US the wintertime starts on a different date than in Europe. But even this is a simplification. Because the colors are grouped by week. So not all blue or yellow countries start their DSTs not on the same date or time. Just ballpark.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now our clock also does not understand wintertime and summertime. It can do four things. It can do the right thing – unlikely, but it is possible. Or it will forget it, so you manually have to adjust it. Or… it will move the clock forwards when it needs to go backwards or vice versa. Or… it does the right thing, but for the wrong location. Maybe the clock thinks it is in Australia and it will change it to winter time on May 5th and back to summer time in the fall.

# data[].attributes.slidedeck.data[].slides[].desc.html
And sometimes the clock pretends to be a VCR… Nobody knows how to set the time on a VCR… So it just blinks 12:00. Apologies to the students here… A VCR is basically a DVD player that uses magnetic tape… Apologies again… A DVD is basically Netflix but you have to go to a physical store to borrow a physical copy on a shiny disk before you can watch anything. And you have to return a day or two later, because otherwise you’ll get a fine. Anyway…

# data[].attributes.slidedeck.data[].slides[].desc.html
The clock also contains a full Box2D simulation and everything you see on screen are in these simulated environments that have motors connected to the hands. But these environments also have gravity. And thanks to an accelerometer I can set that gravity in the same direction as real gravity is. So no matter how you hold the clock, the simulated gravity is giving the appearance of actual gravity.

# data[].attributes.slidedeck.data[].slides[].desc.html
And when you touch the hands it determines the force you use and sometimes that is too much and the hands break off from the pivot point and start flying. Actually once in a while one of the hands will come loose on its own and drop down swinging on the pivot point. And if you don’t put it back within an hour or so it will just fall to the floor. Not good for telling the time, but perfect for a bad clock.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now, I put this on the internet and after a bit I got this response…

# data[].attributes.slidedeck.data[].slides[].desc.html
Yeah… I mean…

# data[].attributes.slidedeck.data[].slides[].desc.html
I’ve got work to do. It doesn’t make any sense. Why would you? I still have this talk to write. I don’t have the time. I can’t possibly spend 10 hours and 17 minutes on a gravity simulation of beans… Just because somebody on the internet says something.

# data[].attributes.slidedeck.data[].slides[].desc.html
So I added 120 beans to the gravity model added a liquid simulation as well, including a method where beans and liquid would leave brown smudges on the glass whenever the beans are touching the glass.

# data[].attributes.slidedeck.data[].slides[].desc.html
In the gravity simulation it looks like this. Every bean is a circle with the bean oval randomly sized. That way the beans can overlap a bit and the distribution looks uneven – which is perfect. The hands can interact with the beans and you can even stir the beans and pick up individual beans with the hour hand. That one is thick enough to actual drag the beans along on the screen. The clock now has a bean mode.

# data[].attributes.slidedeck.data[].slides[].desc.html
You’ll also noticed that I added a menu that has the buttons drop down from the top. Not very user friendly because the buttons are always in a different place and maybe even in a different order and even sometimes up-side down. I reluctantly added a reset button as well – but as I added more and more quirks the clock became so useless that sometime you just need to…

# data[].attributes.slidedeck.data[].slides[].desc.html
You’ll also notice the digital 7 segment displays are in the gravity simulation. Which is because if you shake it in digital clock face mode, the segments drop down on the floor. But… the best part is… The clocks just keeps running. So if the time changes different segments still light up.

# data[].attributes.slidedeck.data[].slides[].desc.html
And finally this knob. Well…. You need to wind the clock. Every day you have to wind it up otherwise it will start running slower and slower to eventually just stop. But the tricky part is, you do not know how much to wind it. And if you wind it up to much…

# data[].attributes.slidedeck.data[].slides[].desc.html
… the forces on those gears just build up and up and they start slipping and the teeth just break off.

# data[].attributes.slidedeck.data[].slides[].desc.html
Let see that again… I can watch this all day. I just love this clock. And I am not the only one – I have an office at home and every evening my 11 year old sneaks in and messes my clock up in a new way so that when I go back to work it has beans… or the hands are on the floor… or… But… that is just 1 clock. I promised clocks – multiple.

# data[].attributes.slidedeck.data[].slides[].desc.html
And that brings me to laser projectors. I’ve always been fascinated by them and ever since I saw Seb Lee Delisle talk about lasers 10 years ago. Now I knew nothing of how lasers work – Seb did explain some of the issues he ran into recreating the classic Asteroids game – which is a shooter from 1979 created by Atari.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now the original game used a special display system called the QuadraScan, which did not use the scanlines that normal televisions or computer monitors used. Instead it directly steered the electron beam to draw these vector shapes. Which is actually a really great fit for a laser projector… Instead of steering an electron beam using electrostatic plates, you are steering a laser beam using mirrors. Completely different technology from vastly different eras. But using some of the same principles.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now, before you get excited about me showing a laser clock… They are really cool. But I don’t have one. And they are expensive. It’s not like my name is Seb Lee Delisle who has probably a couple of spare ones just stacked up behind couch. So… I’m sorry.

# data[].attributes.slidedeck.data[].slides[].desc.html
But… that game of Asteroids kept lingering in the back of my head and I figured that an oscilloscope could function in the same way as that QuadraScan display. You can set an scope in X/Y mode and then steer the electron beam. Exactly what we want for our clock. Yes. I wanted to build a clock. The best part: oscilloscopes are pretty cheap compared to laser projectors. Are they sustainable… Sorry Hidde, not really. This is probably not clock you want to keep running the whole day… And also for other reasons too…

# data[].attributes.slidedeck.data[].slides[].desc.html
And they are really cool too. I just love the aesthetic – it really feels you have wandered into the lab of a mad scientist with all of those buttons. And if you think of it. It literally is a small particle accelerator that fires electrons at about a quarter of the speed of light. And it is pointed right at your face. Only to be caught by a small layer of phosphor.

# data[].attributes.slidedeck.data[].slides[].desc.html
But of course we want to use web technology to create this clock. So this part of the talk is titled: “How I used CSS Animations to draw a clock on an oscilloscope”

# data[].attributes.slidedeck.data[].slides[].desc.html
Eh… wait…

# data[].attributes.slidedeck.data[].slides[].desc.html
Small correction: How I blew up an 1980s oscilloscope and almost caused a fire”. Yeah…

# data[].attributes.slidedeck.data[].slides[].desc.html
Well… that is also not entirely accurate.

# data[].attributes.slidedeck.data[].slides[].desc.html
Let’s go with how I build a physics simulation for a terrible 1980s oscilloscope in JavaScript.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now before we start… I want to take a minute and let’s think about what a clock really is… What does the word clock actually mean? No.. Justus, I don’t mean philosophically…

# data[].attributes.slidedeck.data[].slides[].desc.html
It is a circle and three lines. And on the web we can use SVG for that. Four simple shapes… Vectors… just like that Asteroid game.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now, how would we draw these shapes on the scope? The face-melting electron beam is steered - or better deflected - by two electrically charged plates, called the x- and Y-plates. And by deflecting the beam vertically and horizontally we can trace the image that we want. And do that multiple times per second and our image appears. Now most oscilloscopes have an X/Y mode where you have two input channels that are directly controlling the x- and Y-plates.

# data[].attributes.slidedeck.data[].slides[].desc.html
So we need to generate two signals, one for X and one for Y and it needs to trace the image we want to draw. Let’s start with the clock face, the circle. That is actually pretty simple to generate. This is the circle and it is pretty much high school math – sorry about that. Turns out my math professor was right all those years ago – I am going to need math later in life. I don’t think he expected it to be this though.

# data[].attributes.slidedeck.data[].slides[].desc.html
So this is the circle and if you look closely it actually starts to make sense. We just make a wave form directly from the X/Y coordinates of the circumference of the circle.

# data[].attributes.slidedeck.data[].slides[].desc.html
And we can make any shape with that method. Every shape can be expressed in that two channel signal.

# data[].attributes.slidedeck.data[].slides[].desc.html
Even triangles…. Which are three lines… and we need three lines for our clock. Just oriented slightly different.

# data[].attributes.slidedeck.data[].slides[].desc.html
So this is what our clock looks like. If you look closely at the red signal, we have a sine wave, that the circle, and three triangles, those are the clock hands that are drawn from the centre out and then back to the centre. That is one triangle. Then another back and forth for the second hand. And another one for the third. On the white trace we can also see the beam jumping from the centre to the outer circle. Because we cannot turn our face melting particle accelerator off for a split second, we just have to move the beam really, really fast… Which will come back to bite us in the ass later on.

# data[].attributes.slidedeck.data[].slides[].desc.html
So we have our SVG. This is just a static clock. The first thing we need to do is animate it, so the hands start moving.

# data[].attributes.slidedeck.data[].slides[].desc.html
And we can use CSS for that. We rotate the hand around the centre of the clock and in case of the hour hand that takes 12 hours times 60 minutes times 60 seconds. Which is 43.200 seconds. We do want to set the clock at the right time, and we can do that by turning back the time, sort of. We set a negative animation delay, which means the animation is not waiting to start, but it has already started back in the past. And we do this for every hand. And with that we have a fully working CSS clock.

# data[].attributes.slidedeck.data[].slides[].desc.html
Which is great in the browser, but we want to get the coordinates so that we can create that wave form. And luckily there are some great APIs build into the browser. For every SVG shape we can the coordinates at specific points along the path using getPointAtLength(), we just need to apply the transform to that, because transforms do not affect the elements geometry, it just changes where it is rendered. So if we want to know where it is rendered, we need the transform matrices…. And I am not going to explain them all in detail, the APIs are on mdn…

# data[].attributes.slidedeck.data[].slides[].desc.html
So we trace along the paths of the SVG elements and we get our coordinates. And we end up with two arrays with numbers. And if we plot those numbers in a graph, you can see the sinus wave again, and the three triangles.

# data[].attributes.slidedeck.data[].slides[].desc.html
The next step involves WebAudio – this is the method we are using to generate that signal that we can output to the oscilloscope. Because we are hooking up the scope using a simple audio cable from the computer to the X and the Y input. Our left audio channel contains the X values and the right audio channel contains the Y values.

# data[].attributes.slidedeck.data[].slides[].desc.html
And we do this 30 times per second… So when the shapes move or change using CSS animations, we capture the state every frame and render a new waveform that we output to the scope. CSS animations on a oscilloscope.

# data[].attributes.slidedeck.data[].slides[].desc.html
So I built a web app that does exactly this. It has a small editor which you can use to edit your SVG and CSS and it will just inject that into the DOM and sample the geometry 30 times per second. And it outputs the waveforms to the oscilloscope.

# data[].attributes.slidedeck.data[].slides[].desc.html
Did you see that? The scope was not yet set in X/Y mode and you could see the wave form we generated, the sinus wave and the three triangles for the hands.

# data[].attributes.slidedeck.data[].slides[].desc.html
Let’s set it to XY mode. And there it is…

# data[].attributes.slidedeck.data[].slides[].desc.html
And at this point the oscilloscope decided to… explode. Now this is just the aftermath… I was too busy finding the power plug, scrambling to find my phone to film it and at the same time a big column of smoke was rising up and sparks went flying everywhere. And then I realised — I should probably unplug my computer too. What if this thing sends a couple thousand volts back down the audio cable?

# data[].attributes.slidedeck.data[].slides[].desc.html
Now what…

# data[].attributes.slidedeck.data[].slides[].desc.html
Redundancy!… I may have overreacted… But I am getting ahead of myself. My scope has exploded. I have a signal generator to finish, but no way to actually continue until I get my scope repaired or find a replacement.

# data[].attributes.slidedeck.data[].slides[].desc.html
And I find myself on the train to Beyond Tellerrand in Berlin last November. It’s a five hour ride and I have nothing to do… So I decide to built my own oscilloscope simulator. Can’t be that difficult, right?

# data[].attributes.slidedeck.data[].slides[].desc.html
But I don’t want a clean X/Y plot of the data. That is too clean. I want a 1980s oscilloscope with all of its faults and limitations. So the first thing we do is add a whole bunch of noise. But that is just the starting point. We also want to replicate how the phosphor works in a real scope. And what we really want is a physics simulation of the electron beam and how it is deflected by the electrostatic x and y plates. But I have to do it from memory and from a few photos I managed to snap before the scope exploded.

# data[].attributes.slidedeck.data[].slides[].desc.html
And this is where things go off the rails. I did a deep dive into how scopes work. Electromagnetic Force, Acceleration, Velocity, Damping, Euler integration of how velocity moves the beam. And another Euler integration of all of these steps together. Overshoot amplitude decay… And we haven’t even talked about Energy deposition based on beam velocity, The P31 phosphor physics, like phosphor saturation, phosphor persistence, Beam dwelling at direction changes causing brighter dots on the screen.

# data[].attributes.slidedeck.data[].slides[].desc.html
Now, is this really accurate. No… Yes… Sort of… The X and Y plates of the scope are an lr circuit and the beam isn’t really affected by a Spring-Mass-Damper system, like we are modelling. But they are mathematically equivalent. Sort of… On a high level. But good enough. I was about to calculate how the electrons are exciting the phosphor and then I realised… that I have a life. I have a family and work and so many other projects. I actually don’t care about this. And apparently there was an end to the rabbit hole for me. It’s a black box. We have a web worker that gets the X and Y points runs the physics simulation on it and we get a whole set of new points back that we draw on the screen. And it turns out I only care about how it looks. Does it look the same as a real scope? Yes. So great. Which in itself is already amazing. I totally confirm that my methods are right… Besides….

# data[].attributes.slidedeck.data[].slides[].desc.html
I still want to create a laser clock. But first… let me show you the oscilloscope. ==== do live demo here ====

# data[].attributes.slidedeck.data[].slides[].desc.html
I have some other projects.

# data[].attributes.slidedeck.data[].slides[].desc.html
On the train to Beyond Tellerrand I also saw this on AliExpress. It’s really cheap. Not great to hear those words in combination with flamethrowers. But I bought it… And when I arrived home, it was there. On my coffee table.

# data[].attributes.slidedeck.data[].slides[].desc.html
To control it we need a protocol called DMX… not this DMX…

# data[].attributes.slidedeck.data[].slides[].desc.html
This one.

# data[].attributes.slidedeck.data[].slides[].desc.html
And it is used by stage lights, smoke machines… and flame throwers.

# data[].attributes.slidedeck.data[].slides[].desc.html
A CSS controlled flamethrower… and this isn’t just theory. This is a real web app that anybody could use. And that is just the start.

# data[].attributes.slidedeck.data[].slides[].desc.html
And that brings us back to the theme of this conference. The web I want is weird, personal and sometimes broken. With lasers, flamethrowers and clocks.