<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title><![CDATA[5013.es]]></title>
        <description><![CDATA[5013.es]]></description>
        <link>https://5013.es/</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Tue, 18 Mar 2025 16:23:38 GMT</lastBuildDate>
        <atom:link href="https://5013.es/feed" rel="self" type="application/rss+xml"/>
        <author><![CDATA[sole]]></author>
        <item>
            <title><![CDATA[4'33" (as performed by your browser)]]></title>
            <description><![CDATA[<p>This is a collection of various browser-based players that can perform John Cage&#39;s <a href="https://en.wikipedia.org/wiki/4%E2%80%B233%E2%80%B3">4&#39;33&quot;</a> composition.</p>
<p>True to the original spirit, each player might cause an slightly different performance to take place, as each player slightly differs from the rest of players, but the end result is similar: you hear an interpretation of 4&#39;33&quot;.</p>
<p>Some players do very little overall. Some do a bit more of upfront work and then act as if the metaphorical piano lid had been closed at the beginning of the performance. Some of the upfront work briefly blocks the UI thread (not that you would notice... generally); others actively generate no sound, others do generate sound, albeit in an optimised, but equally quiet, manner.</p>
<p>Any fan or hard drive noises emitted by the device the player is running on, any increment in temperature, and any other external noises that might occur during a performance are all part of the performance.</p>
<h3>Configuration</h3>
<p>Not that a member of the audience <em>should</em> tell the players what to do... but there is a small configuration section that can be opened and allows to modify the length of the performance, and whether to actively emit sound.</p>
<p>These options are there for debugging purposes and you are encouraged to not tinker with them as they will cause a different piece to be performed, but you can tinker with them if you want to, because it&#39;s your device and you decide what to listen to.</p>
<p>Just make sure your device&#39;s volume is not very loud, as you might get a lot of noise blasted through the speakers otherwise!</p>
<h2>A little bit more about the players</h2>
<p>A classic Object Oriented Programming (OOP) hierarchy is observed as the code was written aiming to reuse as much as possible.</p>
<p>We start with a <code>Base</code> player, which is in turn extended by two categories of players: those that use an <code>AudioContext</code> based solution, and those who generate audio data directly and output it to an <code>&lt;audio&gt;</code> element; both categories contain multiple players, some building upon other types of players.</p>
<p>The UI is a web component which is instantiated per player. The UI interacts with the players by calling their <code>play</code> and <code>pause</code> methods. OOP makes this part very straightforward to implement as it defines a &quot;shared API&quot; for the players.</p>
<h3>The hierarchy of players</h3>
<ul>
<li>Base<ul>
<li>No OP</li>
<li><code>AudioContext</code> (and nothing else)<ul>
<li><code>AudioContext</code> with <code>AudioWorklet</code></li>
<li><code>OfflineAudioContext</code></li>
</ul>
</li>
<li>Generate WAV<ul>
<li>Generate WAV with Web Worker</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3>The players, in detail</h3>
<h4>0. Base</h4>
<p>Keeps track of time, provides pausing, resuming and detecting end of performance functionalities.</p>
<p>It can also attach to an UI element, and update the element with the current playing time and status.</p>
<h4>1. No OP</h4>
<p>Does nothing apart from what the base player does.</p>
<h4>2. <code>AudioContext</code></h4>
<p>An <code>AudioContext</code> is created, but no nodes are connected to it.</p>
<h4>3. <code>AudioContext</code> with <code>AudioWorklet</code></h4>
<p>An <code>AudioWorklet</code> node is used to generate audio data with an instance of <code>SilenceProcessor</code>, which extends <code>AudioWorkletProcessor</code>.</p>
<h4>4. <code>AudioContext</code> with <code>OfflineAudioContext</code></h4>
<p>Audio is rendered upfront using an <code>OfflineAudioContext</code>, then played through an <code>AudioBufferSourceNode</code> in the <code>AudioContext</code> created by the parent class.</p>
<h4>5. Generate WAV</h4>
<p>The audio data is generated upfront, then played through an <code>&lt;audio&gt;</code> element.</p>
<p>Depending on the configured length of the performance, this could considerably block the UI thread, making the website unresponsive.</p>
<h4>6. Generate WAV (with Web Worker)</h4>
<p>The audio data is generated in a web worker rather than in the UI thread.</p>
<p>This takes slightly longer to initialise, but it won&#39;t block the UI thread.</p>
<h3>Discarded options</h3>
<p>These are players I initially came up with but did not implement.</p>
<h4><code>AudioContext</code> with <code>ScriptProcessorNode</code></h4>
<p>My initial list of ideas included a player implemented with <code>ScriptProcessorNode</code> but since then a better implementation option has been standardised and shipped in browsers, so I never wrote that player. Instead, the <code>AudioWorklet</code> version exists. </p>
<h4>MediaRecorder</h4>
<p>I was not deeply familiar with the MediaRecorder API at the time I sketched out my ideas, so I wasn&#39;t super sure of how it would work in practice.</p>
<p>When I started implementing the various players it became evident to me that it would be a bit futile to implement a <code>MediaRecorder</code> based version as I don&#39;t think you can render streams offline, just as you can render audio files with <code>OfflineAudioContext</code>: we would need to first spend the performance time generating the stream so the recorder would record it, and only then when finished recording and the audio file was generated we would use this file with an <code>&lt;audio&gt;</code> element or another <code>AudioContext</code>, which would enable the user to <em>play</em> the generated stream. That sounded a little bit too performative, so I decided not to pursue this version.</p>
<h4>Using other APIs or combination of APIs</h4>
<p>I could have also built players that did things such as <em>create oscillator nodes</em> but also play them with a <em>gain value of 0</em>. This would be like having a drummer bang a drum outside an anechoic chamber, and record the performance from <em>inside</em> the chamber. It could be done, but I didn&#39;t, because although the end result is on the surface similar, I felt that this line of players veers off from the initial spirit as they would be <em>actively</em> generating sound that we then mute.</p>
<p>There might also be other ways that don&#39;t directly involve <code>&lt;audio&gt;</code> elements or Web Audio APIs and which I have not explored, like for example generating an image in a canvas, extracting the colour values out of the canvas element and converting those into an array of data which could be used to create an audio file or <code>ArrayBuffer</code>... but I felt that the point has been proved already, as this was very similar to the existing players, and it just added extra layers of complexity around them without adding a lot of interest.</p>
<p>There might also be other APIs that I don&#39;t know of yet or that do not exist yet that could enable new interpretations of this piece in the browser. I might revisit the project in the future.</p>
<h2>Why build this?</h2>
<p>One morning almost ten years ago, I was having breakfast over a reconverted sewing machine table (sans machine, that is) in the former Black Sheep Coffee shop in Charlotte Street in London—a narrow, dark ground floor unit with mismatched floor tiles—.</p>
<p>As usual, I was scanning Twitter to see if there was anything relevant that had happened overnight and that needed replying to (something that I did as part of my devrel job!). Then I spotted an interesting Twitter discussion about 4&#39;33&quot; and JavaScript that sparked the lightbulb in my brain and caused me to get my notebook out and start writing down all the ways in which the piece could be implemented in JavaScript.</p>
<p>I had been working a lot with audio and Web Audio stuff at that moment, so I&#39;m not surprised in the slightest that my brain was keen on coming up with all sorts of solutions.</p>
<p>And then... I didn&#39;t do anything about it.</p>
<p>But the thought of the project would come back to me from time to time. And I still didn&#39;t do anything about it.</p>
<p>Until now!</p>
<p>In which I have built it because I am tired of thinking about building it 😆</p>
<h2>Who?</h2>
<p>But <em>who</em> prompted the idea? I hate it when I don&#39;t remember these things!</p>
<p>I consulted my Twitter archive to locate the thread. I more or less knew this happened in 2015 or maybe 2016... Thankfully, I didn&#39;t need to read all the tweets of that period because I still have that notebook and I found the notes!</p>
<p>The notes weren&#39;t dated as I just seem to have written them down <em>so quickly</em>, no time for formalities, but there was a date on the <em>next</em> page, so that helped me narrow the timeline down: no later than November 2015.</p>
<p>With that, I could find my side of the conversation in my archive, and who was I tweeting to, but as this is only an archive of <em>my</em> tweets, the full exchange is incomplete, and the tweets from the other participants, including the initial tweet that started the thread, are missing.</p>
<p>However this was a short interaction so I can reconstruct the context (at least from my point of view):</p>
<p><a href="https://tinysubversions.com/">Darius Kazemi</a> started the original thread, and <a href="https://jennschiffer.com/">Jenn Schiffer</a> retweeted it. And then I read it, and enjoyed the idea, and excitedly responded with a Web Audio based version:</p>
<pre><code>simplified to:
`new AudioContext();`
for performance 😜
</code></pre>
<p>And you know the rest!</p>
<p><em>Belated thanks to Darius and Jenn for the initial prompt</em> 😃</p>
]]></description>
            <link>https://5013.es/p/10/</link>
            <guid isPermaLink="true">https://5013.es/p/10/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Tue, 18 Mar 2025 14:40:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[store store cards]]></title>
            <description><![CDATA[<p><code>store store cards</code> is a website that allows you to <em>store</em> loyalty or membership cards to your device (usually a mobile phone).</p>
<p>These cards have barcodes or QR codes of some sort which represent your membership number. You can use your device&#39;s camera to scan the barcode and create a &#39;virtual&#39; card quickly.</p>
<p><em>Please note:</em> this is <strong>not</strong> a wallet app, and it does <strong>not</strong> deal with financial information of any kind.</p>
<p><img src="./card-cocos.jpg" alt="image of phone screen showing a card barcode being rendered, it says coco&#39;s cafe"></p>
<p>You can &quot;install&quot; the website to your device, in which case it effectively acts like an app, or what is also known as a <a href="https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps"><em>Progressive Web App</em></a>.</p>
<p>Once installed, it should work offline. That is, you don&#39;t need any data service to access the cards you stored. This allows you to use the website even when there&#39;s no mobile reception and the shop doesn&#39;t offer free wifi. For example, when you reach the till of the grocery shop in the basement of the department store. Also, since <code>store store cards</code> does not try to find your location to recommend you &quot;offers&quot;, it is as private and fast as it can be, and it won&#39;t make you waste your precious battery charge or time when it you&#39;re trying to scan the card and a queue of people is forming behind you...</p>
<p>Oh, and it is also <em>really small</em> (compared to a native app): the final code is less than 2 megabytes (yes, <em>mega</em> bytes).</p>
<h2>Privacy</h2>
<p>This works entirely client side. The data stays in your device. I do not know what you scan, and I do not want to know!</p>
<p>If you want to make a copy of your cards or want to see what is stored, inspect the website with your favourite developer tools, and look in <code>localStorage</code>.</p>
<p>I run lightweight statistics to get a sense of how many people use the website, and detect crashes or bugs. Individual visitors aren&#39;t identifiable, as I don&#39;t store any personal user data, only the fact that you visited, the type of operating system you use, etc (this is information that you provide already by browsing the internet). If your device has any sort of tracker-blocking functionality, it is likely to block my statistics code, so if the app exhibits bugs when you visit I will never know, and it&#39;s OK.</p>
<p>The statistics service is hosted in Europe. The data is not made available to anyone. There are no ads or any other third-party script delivered with this website.</p>
<h2>How to install or add to your home screen</h2>
<p>This depends on the operating system and browser you&#39;re using.</p>
<h3>iOS</h3>
<p>Visit the <a href="https://storestorecards.apps.5013.es/">website</a> in your iOS device, then select &quot;Share&quot;, then scroll down to &quot;Add to Home Screen&quot;.</p>
<h3>Android and other non-iOS</h3>
<p>I don&#39;t know! I don&#39;t have access to recent Android or non iOS devices. But if you figure that out, please let me know and I can update this page. Thank you 💝</p>
<h2>How to share this app with friends and family</h2>
<p>Send them the URL: <a href="https://storestorecards.apps.5013.es/">https://storestorecards.apps.5013.es/</a></p>
<h2>Help! Something does not work</h2>
<h3>My camera is broken or I don&#39;t want to / can&#39;t use it</h3>
<p>You can enter card details by hand.</p>
<h3>The card won&#39;t scan, I can&#39;t add it to my app!</h3>
<p>We have tested this with UK and Spanish cards. I don&#39;t know what type of obscure configurations manifest in other countries.</p>
<p>You can try adding the number by hand, and playing with the different barcode types, until you get something that resembles the original card.</p>
<h3>The scanned card looks different from the physical card</h3>
<p>Some cards only show a subset of numbers vs what the barcode actually contains. In that case, it tends to be that the first digits are not shown in the card, but the last digits are, and tend to coincide with &quot;your membership number&quot;.</p>
<p>I don&#39;t really know why—I suppose to make it easier for cashiers that have to visually verify or enter card numbers with their naked eye. If you&#39;re unsure, bring both cards with you (the &#39;virtual&#39; and the physical) so you can have a backup option. Once you verify that the virtual card works, you can stop carrying the physical card with you.</p>
<p>Some retailers will give you a big card and &quot;portable&quot; cards that you can add to your keyring. I&#39;ve seen they sometimes differ only by a digit, but the last x digits, which are displayed on the card, are the same. My hunch is they do it to track which format is more popular, but I haven&#39;t investigated any further.</p>
<h3>There are no icons, logotypes or colour customisation per card</h3>
<p>This is by design. I wanted a simple app. I don&#39;t need those.</p>
<h3>Something <em>else</em> doesn&#39;t work</h3>
<p>I only have access to not very old but not very new iOS devices. I have tested this in various computers and operating systems (macOS and Linux) and it simply worked, but who knows!</p>
<p>If you genuinely want to help and have an idea of what is wrong, get in touch.</p>
<p>If you&#39;re unhappy and want to rant, maybe just find another app or service instead—I have no time or energy to help you debug weird configurations for free. No bad blood here! You&#39;re free to use whatever you want.</p>
<h2>Why?</h2>
<p>Libraries, coffee shops, museums, supermarkets, grocery stores, you name it: they have membership programmes, that you prove you belong to by scanning a card when you enter (or when you leave, in the case of a store).</p>
<p>I was tired of carrying lots of loyalty and membership cards in my wallet, so I started using an app that allowed me to scan the cards and have a &quot;virtual&quot; version of the card instead.</p>
<p>This was convenient, but the rest was really tiresome: it wanted me to give it all sorts of permissions; it often failed to render a card that would be successfully scanned... and on top of that, it was releasing almost weekly 155+ megabyte updates for no good reason, other than &quot;Bug fixes and feature improvements&quot;. But nothing ever seemed to change or improve!</p>
<p>When the app we were using &quot;warned&quot; my partner that it would stop working unless it were updated to the latest version, I decided that we had had enough, and I set on the task of building an alternative that would be considerate with their users, and also nimbler and much faster to use. <strong>Thus, it is my gift to both of us, and now my gift for you too!</strong> 💝🎁</p>
<p>As of today we both use this almost daily, often several times in a row.</p>
<p>It has never crashed or stalled. We find it is much faster to scan, even with some barcode scanners which are quite temperamental, thanks to our <em>secret trick</em>: making the barcode as big as possible (actually, this is the same trick that LiDL use to speed up checkouts!).</p>
<h2>Technology</h2>
<p>Since this is a website, it is built using browser technologies: HTML, CSS and JavaScript. The camera is accessed using <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia">MediaDevices.getUserMedia</a>, as I also do in <a href="/tags/media-streams">a few of my other projects</a> already.</p>
<p>In addition, I am using a few libraries to plug-in gaps in implementation or just to keep my sanity:</p>
<ul>
<li>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API">Barcode Detection API</a>, if available, or a <a href="https://www.npmjs.com/package/barcode-detector">polyfill</a> in browsers that do not implement the API yet</li>
<li><a href="https://www.npmjs.com/package/bwip-js">BWIP</a> to render the barcodes</li>
<li><a href="">Vite</a> for handling the build, packaging, etc, with some plug-ins:<ul>
<li><a href="https://github.com/vite-pwa/vite-plugin-pwa">vite-plugin-pwa</a> to help providing offlining and PWA functionalities</li>
<li><a href="https://github.com/darkobits/vite-plugin-favicons">vite-plugin-favicons</a> for handling the myriad versions of icons you have to provide in order to have ONE icon placed in the user&#39;s home screen 😂</li>
</ul>
</li>
</ul>
<p>I&#39;m extremely grateful for those libraries!</p>
<p>The underneath libraries and polyfills support more barcode formats than the Barcode Detection API does, but in the interest of future compatibility I have decided to only expose the same formats as the real Web API would expose. These are listed here: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API#supported_barcode_formats">supported barcode formats</a>.</p>
<p>I have optimised the way the libraries are delivered to the users, by deliberately splitting code into dependency vs non dependency chunks. That way you only have to download what has changed, which is normally just my code, not libraries. This is a matter of <em>kilobytes</em>, so &quot;app updates&quot; are almost seamless: you access the app, close it and reopen it and you get a new version. This is much more considerate than native apps that will ship the whole list of dependencies over and over to users, without any respect for their time or bandwidth.</p>
<h3>Some things I wish were possible</h3>
<p>Although I&#39;m very satisfied that the same code base works everywhere, regardless of the operating system or browser flavour, I find the following aspects frustrating. They put websites at a disadvantage compared to native apps:</p>
<ul>
<li>I can&#39;t control the brightness of the screen. This would help ensure that the barcode scans even if the user has very low brightness in their device,  by temporarily increasing it (and thus, increasing the contrast between black and white in the barcodes). But there&#39;s no such API for the web. We had something like that in Firefox OS, but...</li>
<li>It would also be nice to be able to control the focusing of the camera somehow. E.g. if I could for example set it to &quot;macro&quot; it would focus on closer distance objects, and make scanning faster. But it seems like the barcode API (and the polyfill) do a good job of detecting shapes even when slightly blurry, so not a big deal.</li>
<li>I also don&#39;t seem to be able to allow camera permissions <em>forever</em> with iOS. It seems to ask periodically if I want to allow camera usage, even if the app is installed. I don&#39;t know if I&#39;m missing something in the manifest. It is mildly irritating, but I can live with it.</li>
<li>Finally, if you store some cards locally, while accessing the website through the browser, and then &quot;install&quot; the website as an app, you have to re-add the cards, as there&#39;s no way to have access to the same &#39;storage area&#39;. This makes it harder to &#39;try before you buy&#39;, which would be a great advantage of websites vs native apps.</li>
</ul>
<h2>Is my phone screen cracked?</h2>
<p>It is actually the <em>screen protector</em> that is cracked!</p>
<p>My phone fell off my hands the very same week that I bought it, as it was bigger than my previous phone, and I still hadn&#39;t developed the &quot;grip&quot; to hold it safely in place. We had just finished a run on a hot and humid July morning, I wanted to document the triumphal moment, and my sweaty hands just lost it...</p>
<p>It then landed, of all the places, on a particularly pointy piece of gravel, which chipped the edge of the <em>screen protector</em>, and created a long thin crack along the protector. The screen is fine, no pixels were harmed.</p>
<p>I often don&#39;t even notice the crack anymore—except now that I took these pictures!</p>
]]></description>
            <link>https://5013.es/p/z/</link>
            <guid isPermaLink="true">https://5013.es/p/z/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Wed, 15 Jan 2025 17:40:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[colour to sound]]></title>
            <description><![CDATA[<p>This project simulates hardware devices that allow colour blind people to perceive colours by using their sense of hearing instead.</p>
<p>It uses the device&#39;s camera to find the colour at the center of the image, and turns it into a music note, which is then played through the device speakers.</p>
<p>This is all achieved by using Web technologies such as Web Audio and the Media Streams APIs; the data processing is also done entirely locally, so no camera data is ever sent to a remote server for processing.</p>
<h2>Inspiration</h2>
<p>The idea to build this came after I saw there is <a href="https://www.bbc.co.uk/news/articles/cg58r70yj43o">a new documentary about Neil Harbisson</a> coming up.</p>
<p>He has famously declared himself to be a cyborg, as he has a light sensor mounted on an antenna attached to his skull. The light sensor is connected to a brain implant on the back of his head, and the implant turns the colours captured by the sensor into sound.</p>
<p>In other words, <strong>the implant allows him to hear sound</strong>, as he has achromatopsia, a type of color blindness which means &#39;no colour&#39; i.e. he sees everything in a greyscale.</p>
<p>The set of antenna, sensor and implant also seem to be known as an &quot;Eyeborgs&quot; or &quot;Cyborg antennas&quot;. I saw mentions to other versions of this device in existence in some websites, but since I couldn&#39;t find much detail about their specifics I did not take them into account when building this experiment.</p>
<h2>Simulation, not reproduction</h2>
<p>Given the scarcity of technical information available, the output from this experiment is at best an approximation, but it grossly aims to produce the same sonochromatic scale that is discussed in <a href="https://en.wikipedia.org/wiki/Sonochromatism#Harbisson's_Sonochromatic_Scales">the Wikipedia page for Sonochromatism</a>, where the red in the colour spectrum starts at F, orange is F#, yellow is G and etc all the way to magenta which is E (for the next octave).</p>
<p>A small settings panel can be opened to adjust several parameters, such as the amount of transposed semitones (so the note where the scale starts can be selected), how many notes in an octave and how many micronotes to use, the gain (to alter the output volume), etc.</p>
<p>The generated scales are slightly different from the <a href="https://en.wikipedia.org/wiki/Chromatic_scale">chromatic</a> scales which are the type of scales we tend to think of when we talk about Western music. While &quot;normal&quot; music uses octaves with 12 notes (semitones) each, the Eyeborg admittedly uses 360 notes, which I interpreted as &quot;each octave contains 36 notes&quot;, i.e. each note can be either the same value as the note in a chromatic scale, or it can be slightly off in either direction - like a third off the value of the interval between &quot;normal&quot; notes. I chose this option as it still was close enough to the standard note name convention and so I could display the approximate note names so that people can have an idea of which note each colour is (i.e. is it an A, or is it a C? etc)</p>
<p>Then, to achieve the final 360 notes they say the Eyeborg can play, the tool can detect up to 10 levels of lightness for each pure base color. This results in actually more than the stated 360 notes, as we have 36 initial values + 36 x 10 variations = 396 notes.</p>
<h3>Potential follow up ideas</h3>
<p>I reached a lot of dead ends and made a lot of false starts, and I also wrote a lot of exploratory code to test ideas, either because I wasn&#39;t sure they would work for what I wanted to accomplish, and at points, I wasn&#39;t even sure of what it was that I was trying to accomplish!</p>
<p>However, because I wanted to keep as close to the original as possible, I kept leaving many of these ideas aside, which makes the end result a touch &quot;bare&quot;, but hopefully represents quite accurately what it is to use one of these Eyeborgs, without getting access to the original hardware or having seen it in person.</p>
<p>A happy outcome is that now I have a well of fresh ideas and concepts to keep digging into for further projects.</p>
<p>Some examples:</p>
<ul>
<li>it is not too noticeable because this experiment only outputs monophonic sound, but one follow up idea I had was to play more than one note at once with this type if scale and see if I encounter any interesting wave overlap effect.</li>
<li>play the x common colours in an image (this is actually what I started with, when I realised that actually, the eyeborg is monophonic). This was quite spooky...</li>
<li>allow to listen to colours from an image selected / uploaded by the user, or from a video. Could be useful if there is no camera in the device or if permission can&#39;t be granted!</li>
<li>use different types of oscillator waves</li>
<li>use colour properties to alter parameters in the output such as filter cut off frequencies (I am not using a filter yet but it could be something to experiment with)</li>
</ul>
<p>I also found a lot of things to write about including, but not limited, small bugs and Web Audio rendering differences between engines, processing colours, and much more, which I will be writing about <a href="https://soledadpenades.com/">in my blog</a> and linking to from here.</p>
<p>In the meantime, you can look at the other references below or any of my other experiments!</p>
<h2>References</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Neil_Harbisson">Neil Harbisson in Wikipedia</a>.</li>
<li>the <a href="https://www.cyborgfoundation.com/">Cyborg Foundation</a> dedicated to promoting cyborg rights.</li>
</ul>
]]></description>
            <link>https://5013.es/p/y/</link>
            <guid isPermaLink="true">https://5013.es/p/y/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Mon, 28 Oct 2024 17:15:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[eurobingo]]></title>
            <description><![CDATA[<p>An interactive, generative and infinitely enjoyable bingo card experience for playing along when watching Eurovision.</p>
<p><a href="https://soledadpenades.com/posts/2024/eurobingo/">More info</a>.</p>
]]></description>
            <link>https://5013.es/p/x/</link>
            <guid isPermaLink="true">https://5013.es/p/x/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Wed, 15 May 2024 17:31:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[gl1tch]]></title>
            <description><![CDATA[<p>An experiment in glitching JPG files in real time.</p>
<p>A base image is corrupted randomly at regular intervals and the results displayed on screen.</p>
]]></description>
            <link>https://5013.es/p/w/</link>
            <guid isPermaLink="true">https://5013.es/p/w/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Thu, 28 Jan 2016 23:22:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[GIFwall]]></title>
            <description><![CDATA[<p>Use it in your parties. To keep your lap warm. Or just because what can be funnier than little loops of your face?</p>
<p>Simple demo of WebRTC + getUserMedia + <a href="https://github.com/sole/Animated_GIF">Animated_GIF.js</a>.</p>
<p>---</p>
<p>Here's <a href="https://github.com/sole/gifwall">the source code</a>.</p>
]]></description>
            <link>https://5013.es/p/v/</link>
            <guid isPermaLink="true">https://5013.es/p/v/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Thu, 09 Oct 2014 21:24:26 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[raining rainbows]]></title>
            <description><![CDATA[<p>It came from a casual conversation: "each time I look at your avatar, I imagine it animated".</p>
<p>Of course it didn't take long to convert <a href="https://github.com/harthur">Heather's avatar</a> into an animated thingie...</p>
<p>Here's <a href="https://github.com/sole/raining-rainbows">the source code</a>, just in case you want to check it out. It's basically Canvas + <a href="https://github.com/sole/tween.js">Tween.js</a>.</p>
]]></description>
            <link>https://5013.es/p/u/</link>
            <guid isPermaLink="true">https://5013.es/p/u/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Thu, 09 Oct 2014 20:58:06 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[to_the_beat // js]]></title>
            <description><![CDATA[<p>Synchronising WebGL visuals to the output generated by <a href="https://github.com/sole/sorollet.js">sorollet.js</a>, my JavaScript-based music synth.</p>

<p>Made for <a href="http://demojs.org/">DemoJS 2013</a> / Paris 28-30 June.</p>
<p>~~~</p>
This is a port of an early 64K intro that I built in 2008 using the first version of Sorollet, which was written in C (you can <a href="https://soledadpenades.com/projects/demoscene/to_the_beat/">read about that version here</a>).

<p>I wanted to watch it again but the binary version was for Mac G4&#39;s. I didn&#39;t have a Rosetta environment and I didn&#39;t want to set up a compiler or any of that either, so I decided to liberally port this to JavaScript, using the work-in-progress Sorollet.js port that I had already started.</p>
<p>The <strong>source code</strong> is on <a href="https://github.com/sole/to_the_beat">github</a>.</p>
<p>It also uses Three.js and <a href="https://github.com/sole/tween.js">Tween.js</a></p>
<p><em>HINT: Try pressing 'd' during playback for getting access to the debug panel and the synthetiser configuration dashboard. Alternatively, view the source!</em></p>
<p><a href="https://5013.es/toys/to_the_beat_js/"><img src="108.png" alt="to_the_beat // js" /></a></p>
]]></description>
            <link>https://5013.es/p/t/</link>
            <guid isPermaLink="true">https://5013.es/p/t/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Sat, 29 Jun 2013 17:49:59 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Webcam dithering]]></title>
            <description><![CDATA[<p>A <em>for-fun</em> and <em>for-learning</em> port of a GLSL dithering <a href="http://devlog-martinsh.blogspot.com.es/2011/03/glsl-dithering.html">shader</a> to WebGL, plus adding support for reading webcam images thanks to WebRTC.</p>
<p><a href="http://5013.es/b/p/2012/f/">More info</a>.</p>
]]></description>
            <link>https://5013.es/p/s/</link>
            <guid isPermaLink="true">https://5013.es/p/s/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Thu, 17 Jan 2013 10:57:48 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[animated_gif.js]]></title>
            <description><![CDATA[<p>You can never have enough of animated GIFs. Specially if you can create them right in your browser thanks to the power of JavaScript and HTML5.</p>
<p><a href="http://lab.soledadpenades.com/js/animated_gif/">GO ON</a>, try it!</p>
<p><a href="http://soledadpenades.com/2012/04/02/animated_gif-js/">More info</a>.</p>
]]></description>
            <link>https://5013.es/p/r/</link>
            <guid isPermaLink="true">https://5013.es/p/r/</guid>
            <dc:creator><![CDATA[sole]]></dc:creator>
            <pubDate>Wed, 16 Jan 2013 23:45:14 GMT</pubDate>
        </item>
    </channel>
</rss>