<?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[Szymon Kaliski]]></title>
        <description><![CDATA[I'm an independent consultant, designing and developing computational interfaces.]]></description>
        <link>https://szymonkaliski.com</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Sun, 09 Aug 2026 23:00:48 GMT</lastBuildDate>
        <atom:link href="https://szymonkaliski.com/feed.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Q2 2026]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>A couple of side-project updates: <a href="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/#archivist-updates">keeping my archival tool alive</a>, <a href="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/#telegraphist">ssh-over-web-browser tailored to my needs</a>, and a <a href="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/#tinyparakeet">slightly better dictation CLI</a>.</p>
<h2>Archivist Updates</h2>
<p>I continue to use, and get a lot of value out of, <a href="https://szymonkaliski.com/projects/archivist/">Archivist</a>.</p>
<p>Since the original post about the project, six years ago (sic!), the tool got extended with collecting screenshots, finding similar items across all sources, and recently moved to my new <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#home-server-on-nixos">Home Server</a>, hosted as a permanent web app.</p>
<p>For collecting screenshots, I use a two-tier system:</p>
<ol>
<li>I have <a href="https://github.com/szymonkaliski/home-configuration/blob/c4ed0beb84930a7e7df587df55b729cd6b1108c6/dotfiles/hammerspoon/bindings/screenshot-with-meta.lua#L112-L137">a couple of Hammerspoon shortcuts</a> overriding the default macOS ones, that take the screenshot, place it in <code>Dropbox/Screenshots/</code> folder, and inject OCR text into the files through a combination of <a href="https://github.com/jackrusher/tinyocr"><code>tinyocr</code></a> and <a href="https://en.wikipedia.org/wiki/Extended_file_attributes"><code>xattr</code></a>.
Dropbox only supports a subset of <code>xattr</code>, so this took some figuring-out, but I managed to find a way to sync them with the Home Server, with the OCR data surviving in the file.
I could do OCR purely in Archivist and save some headaches, but the nice side-effect of having it in <code>xattr</code> is that Spotlight indexes that data, so I can do a quick search for image content directly from Spotlight.</li>
<li>Archivist does a refresh of all its sources hourly, and as part of that, picks up any changes to the Dropbox folder, and updates its local DB.</li>
</ol>
<p>Similarity search was a fun recent addition.
As part of the hourly refresh, all images are processed on-device with <code>DINOv2-base</code> for embeddings (after some extra post-processing to make them square, without alpha channel, etc.).
The resulting vector is stored in the SQLite as a blob of numbers.</p>
<p>Together with this, textual values (like the OCR info, metadata, etc.) are embedded with <code>MiniLM-L6-v2</code>, and stored into another table.</p>
<p>The final search uses <a href="https://en.wikipedia.org/wiki/Hierarchical_navigable_small_world">HNSW index</a> for super fast fetches (under 16ms for my ~10k items), and combines results from image and text similarity searches.</p>
<p>All together, we get this:</p>
<video autoplay muted loop><source src="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/archivist.mp4"></video>
<h2>Telegraphist</h2>
<p>On the topic of always-on custom services, I couldn't find any app that would tick all the boxes for my <code>ssh</code>-from-iPhone needs:</p>
<ul>
<li>I continue to stubbornly use <a href="https://github.com/chriskempson/base16-shell"><code>base16-shell</code></a> for terminal theming, so I can very easily set colors with a simple command, even though I rarely use it.</li>
<li>I wanted something that works with terminal graphics, as I — also rarely — use <a href="https://github.com/hzeller/timg"><code>timg</code></a> to poke at images inline.</li>
<li>Finally, on the Home Server, I'm always in a <code>tmux</code> session, so a native support for that would be nice.</li>
</ul>
<p>I poked around AppStore, but couldn't find anything ticking at least some of these boxes.
I also tested a handful of "web TTY" kinds of things, but nothing sparked joy.
So, I made my own TTY-in-a-browser: Telegraphist.</p>
<p>It didn't take much prompting to combine a PTY library, a WebSocket connection, and <code>xterm.js</code> and get something tailor-made for me.</p>
<p>The <code>base16-shell</code> colors not only work in the terminal, but also impact the minimal UI:</p>
<div class="measure-wide">
<video controls><source src="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/telegraphist-colors.mp4"></video>
</div>
<p>I can look at images:</p>
<div class="measure-wide">
<video controls><source src="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/telegraphist-images.mp4"></video>
</div>
<p>And there's a native <code>tmux</code> integration:</p>
<div class="measure-wide">
<video controls><source src="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/telegraphist-tmux.mp4"></video>
</div>
<p>The most fun part of this project was cutting corners to get to a rough first working version, and then working on improvements from within itself.</p>
<h2>Tinyparakeet</h2>
<p>Exactly a year ago I wrote about a <a href="https://szymonkaliski.com/newsletter/2025-06-30-q2-2025/#:~:text=A%20friend%20recently,15%2Dminute%20version%3A">small Whisper wrapper that I used to use for dictation</a>.</p>
<p>Since then I discovered <code>parakeet</code> family of models, and made <code>tinyparakeet</code> — a small CLI tool for speech-to-text, fully on-device:</p>
<div class="measure-wide">
<video controls><source src="https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/tinyparakeet.mp4"></video>
</div>
<p>It's open source if you, like me, rarely have a need for dictating things, and mostly live in CLI: <a href="https://github.com/szymonkaliski/tinyparakeet"><code>szymonkaliski/tinyparakeet</code></a>.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li><a href="https://mitpress.mit.edu/9780262537445/the-charisma-machine/">The Charisma Machine</a>, recommended by <a href="https://www.geoffreylitt.com/">a friend</a>, a great "<a href="https://szymonkaliski.com/notes/look-for-opposite-views-instead-of-confirming-ones/">Look for Opposite Views Instead of Confirming Ones</a>" kind of book on <a href="https://szymonkaliski.com/notes/constructionism/">Constructionism</a>.</li>
<li><a href="https://press.uchicago.edu/ucp/books/book/chicago/T/bo37447570.html">Theory and Reality</a>, a great meta-overview of philosophy of science themes. I was already familiar with most of the original works, but it was still fun to go through a refresher, and see them contrasted against each other.</li>
<li><a href="https://www.amazon.com/Theoretical-Minimum-Start-Doing-Physics/dp/0465075681">The Theoretical Minimum</a>, the second half of which was a bit too dense for me right now. Physics has never been my strong suit, and I want to get a bit better at it.</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=ycyCGCtScdc">a great talk from Andy Matuschak</a> on LLMs and <a href="https://szymonkaliski.com/notes/malleable-software/">Malleable Software</a>
<ul>
<li>and on that topic, <a href="https://www.youtube.com/watch?v=A2lwxhFPPDI">Deadmau5 vibe-coding his own music production tool</a></li>
</ul>
</li>
<li><a href="https://observablehq.com/d/3c8b082818efd7c9">lovely morphing visualizations</a></li>
<li><a href="https://dynamicland.org/archived-emails/2015/02/email-DL2015-02-c8e10c.html">Bret Victor on "Time and Possibility"</a> — the <a href="https://dynamicland.org/archive/">Dynamicland Archive</a> remains a treasure trove</li>
<li><a href="https://x.com/v2ga/status/2041561709907673191">visualizing p5.js execution</a></li>
<li><a href="https://ergosphere.blog/posts/the-machines-are-fine/">"I'm not worried about the machines. The machines are fine. I'm worried about us."</a></li>
</ul>]]></description>
            <link>https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2026-06-29-q2-2026/</guid>
            <pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q1 2026]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>A pretty nerdy update this time around — <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#home-server-on-nixos">I replaced my Raspberry Pi 4 with a Mini PC running NixOS</a>, <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#microvms">I started using MicroVMs for sandboxing on said Mini PC</a>, <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#feedback-loops-for-llms">I have some thoughts about feedback loops for LLMs</a>, and a couple of <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#smaller-explorations">side-project updates</a>.</p>
<hr>
<p>If you missed the <a href="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/">last issue</a>, I'm an independent consultant now, currently exploring at <a href="https://labs.google">Google Creative Lab</a>.</p>
<p>I currently have some capacity for advising, and I'm always happy to discuss future projects!</p>
<p><strong>Reach out if you're interested in working together: <a href="mailto:hi@szymonkaliski.com">hi@szymonkaliski.com</a></strong></p>
<hr>
<h2>Home Server on NixOS</h2>
<p>I've written about my <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#smart-home-setup">smart home setup</a> before.
Back then, the whole thing was controlled by a Raspberry Pi 4, which recently started to feel a bit constraining — on one hand I had an always-on server in my home, on the other, I couldn't really do much with it.</p>
<p>The issues started with a slowly degrading SD card — this isn't that big of a deal in itself — I could just clone my stuff onto a new one, but I haven't updated Raspbian since I flashed it originally, so by now I couldn't really install anything new.</p>
<p>At the same time I was afraid of how problematic it would be to set everything back up from scratch if I update.
I also got somewhat spoiled by <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#setting-up-nix-on-macos">running Nix on my Macbook</a>, it's just way too nice to go back to a normal way of doing things, and while I could put NixOS on my Raspberry Pi, it felt like asking for extra troubleshooting.</p>
<p>I was on the fence about upgrading for weeks, but the rising RAM prices (and conversations with a <a href="https://www.kylephillips.net/">friend</a>) pushed me over the edge.
I got myself a <a href="https://www.minix.com.hk/products/minix-neo-z350-0db-fanless-mini-pc-eu">N350 in a chunky passively-cooled aluminium case</a>:</p>
<img src="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/minix.png" alt="Minix photo" width="1600" height="900">
<p>At first I thought this would be overkill, but once I started thinking about all the things I could do there, I was pretty happy I went with the beefy option.</p>
<p>NixOS installation was surprisingly easy.
I went with the <a href="https://nixos.org/download/#nixos-iso">graphical installer</a> booted from a USB stick, clicked through a couple of screens, selected "no thank you" for the final graphical environment, and was ready to go.</p>
<p>The first step of the setup was a fun bootstrapping problem.
I already have <a href="https://github.com/szymonkaliski/home-configuration">my dotfiles online</a>, with a simple script which — in theory — sets everything up, but then it turned out <code>git</code> is not in the NixOS shell by default.
I ended up having to write this fun command:</p>
<pre><code class="language-bash">nix --extra-experimental-features "nix-command flakes" \
  run nixpkgs#git -- clone https://github.com/szymonkaliski/home-configuration.git
</code></pre>
<p>...and then went through a cycle of running <code>./setup.sh</code>, failing, fixing what's failing, and doing it again.
This took a couple of attempts, but now I can be sure I can stand up a new machine in a single bash script, which makes me much less worried about upgrading the hardware at some point in the future.</p>
<p>The declarative and git-tracked configuration of the whole machine is really great.
There's no need to <code>sudoedit</code> random files in <code>/etc/</code>, and note down (or fail to do so) what I did.
Every change can be easily rolled back, and the system is, in a sense, stateless — which makes experimentation super "cheap" — I can try out a new service for a while, and if I don't like it, remove a couple of lines of <code>nix</code> and rebuild the system.
LLMs are pretty good at writing these configs too, so most of my interaction with the machine is now like "hey LLM can you make sure this script runs every hour?"</p>
<h2>MicroVMs</h2>
<p>NixOS enables another cool trick — <a href="https://github.com/microvm-nix/microvm.nix"><code>microvm.nix</code></a> — a way to easily manage high-performance VMs (which are much better at isolation from the host OS than Docker).</p>
<p>My config creates four small ephemeral VMs with bare-bones user environment — just enough so <code>direnv</code> can automatically evaluate <code>flake.nix</code>, and I can safely <code>--dangerously-skip-permissions</code>.
This allows me to let the Agents run free, even when my laptop is closed, and not worry about anything breaking.</p>
<p>I can also run the same project multiple times in parallel!
There's no messing around with ports, setting up multiple DB instances, etc. — the same configuration with the same <code>npm run dev</code>, just in a full-on separate virtual machine.</p>
<img src="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/microvms.png" alt="microvm script" width="1600" height="900">
<p>I use a small <code>microvm</code> script which allows me to do things like <code>cd some-project &#x26;&#x26; microvm start</code> which picks up the first free VM, mounts the current directory into <code>/workspace</code>, starts and <code>ssh</code>-es into the machine, and enters <code>/workspace</code> so I'm ready to go (in about 15s).</p>
<p>Thanks to <a href="https://tailscale.com/">Tailscale</a>, I can open <code>http://vm-1:3000</code> wherever I am, and that will get me not only into my Mini PC, but also into the VM running inside of it.</p>
<h2>Feedback Loops for LLMs</h2>
<p>The <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#:~:text=This%20allows%20me%20to%20let%20the%20Agents%20run%20free%2C%20even%20when%20my%20laptop%20is%20closed%2C%20and%20not%20worry%20about%20anything%20breaking.">"Agents running free"</a> leads me to a game I started playing recently: what kind of <em>ad-hoc tools</em> and <em>feedback loops</em> can I build for the task-at-hand, so the model has a very concrete thing to iterate against, easy visibility into its state, and a clear success criteria. Some examples below.</p>
<p><a href="https://szymonkaliski.com/projects/mirrorstate/">MirrorState</a> has been effective at letting the models reason about the application state — any sort of complex Chrome/Playwright MCP calls are replaced with reading from a single JSON blob (this assumes you have the page open in a browser, so it's a more hands-on workflow).
It takes a bit of <code>AGENT.md</code> massaging to explain that the state is bi-directionally synced with a file, but then I have a pretty good time with the model using it as a way to "see" and "act," especially if I get myself into a convoluted state while using the app we're working on.</p>
<p>Another spin on this idea is making a separate <code>/playground</code> page with random bits of debug UI, and letting the model see it, and modify as it goes.
Usually it takes a bit of extra encouragement to also put in <code>JSON.stringify</code>-ied blobs of data in there, but once a correct "point of view" on the problem is created, the model usually has everything it needs to figure it out.</p>
<p>For example here I was iterating on some tooltip positioning, where it has to take into account its own size, the selection (dashed line), and the size of the viewport:</p>
<img src="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/positioning-feedback-loop.png" alt="Feedback loop for popup positioning" width="1602" height="901">
<p>I'm somewhat confident I could figure out the conditions myself while the model was getting stuck, but it was fun to figure out how just seeing all the possible states at once made it work through the issues.
This is interestingly related to <a href="https://szymonkaliski.com/notes/solving-things-visually/">Solving Things Visually</a> — seeing the problem correctly can make it way easier to solve, and sometimes the <em>seeing</em> is as simple as throwing in some extra debug UI (which with LLMs is basically "free").</p>
<p>Similarly, figuring out how to "partition" the application into smaller chunks of functionality can be very useful.
For example, I sometimes create a separate sub-project where we develop a library with a stable API which the main project then imports, so the model on the main one doesn't get bogged down in the details of some complex but well-known thing.</p>
<p>When building my own Agents for various things, I had very good results by creating a small CLI where each of the sub-tools could be executed by the model that's helping me.
This way I can judge the quality of the responses, and iterate on them with the model, without having to go through the whole application loop, which sped up the work on, say, a "summarization" or "data extraction" tool.
I let the model run the CLI wrapper, we both look at the responses, I say I'd prefer them to be a bit different, and we continue.</p>
<p>Finally, creating ad-hoc MCP tools for the thing we're working on is always an option.
For web-based things this usually makes no sense with MirrorState/Chrome/Playwright MCP already existing, but as I was working on React-Native code, it was useful to let the model click around and take screenshots of the application to test and debug it.</p>
<h2>Smaller Explorations</h2>
<p>I continued exploring some of the <a href="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/#codegen-environments">"Codegen Environments" ideas</a>, mainly, adding a way to combine smaller tools into larger wholes.</p>
<p>A box can be drawn around multiple elements, which hides the arrows (treated as "implementation details"), and optionally any extra interface elements created to solve a given problem:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/frame-1.mp4"></video>
<p>The "boxed" tools can still be connected with each-other using arrows — which can point to either the box as a whole, or a single interface element:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/frame-2.mp4"></video>
<p>This reminds me of some thoughts from <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a> on <a href="https://www.inkandswitch.com/crosscut/#encapsulation-without-lamination">"Encapsulation without lamination"</a>.
Combining things and exposing only a subset of the internals is incredibly powerful, but seems to always be done in a way where "the whole" becomes the only thing you can interact with.</p>
<p>This also opens up an interesting philosophical question — the act of "boxing" could easily be fractal, so what then is <em>interface</em> and what is <em>implementation</em>?
The tools seem to morph from one to the other, or maybe hold a superposition of both, depending on which context they are in...</p>
<p>I also experimented with a pen-based interface, inspired by <a href="https://x.com/alexanderchen/status/1993447909069819972">explorations from Alex Chen</a>:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/ipad-gemini.mp4"></video>
<p>(<a href="https://bsky.app/profile/szymonkaliski.com/post/3mca43vptnk2x">check out the Bluesky thread for more videos</a>)</p>
<p>My version, instead of Nano Banana, uses the Flash 3 model with no thinking budget so it responds very quickly, even if often "weirdly".
I send the model a composite of my scribbles and the model's previous outputs.
As a response, the model generates javascript canvas code, which is added on top of the canvas, and we continue.</p>
<p>The <em>feeling</em> of using this is quite interesting, the combination of human input, machine-styled responses (<a href="https://www.inkandswitch.com/inkbase/#:~:text=Inkbase%20programs%20are,opinion%20on%20this.">"Computer Voice"</a>), and quick generation is something I have not seen before in this space.
This, of course, smells of <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> — it's also very fun, but of unclear usefulness at the moment — let me know if you have any ideas where to take this further!</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li><a href="http://www.evolocus.com/Textbooks/Koonin2011.pdf">The Logic of Chance</a> — was amazing, a style of book I now wish existed for any topic I'm interested in!</li>
<li><a href="https://www.amazon.com/Mind-Motion-Action-Shapes-Thought/dp/046509306X">Mind in Motion</a> — more on <a href="https://szymonkaliski.com/notes/embodied-cognition/">Embodied Cognition</a>, this time how thought could come up from movement</li>
<li><a href="https://mitpress.mit.edu/9780262550963/frame-innovation/">Frame Innovation</a> — more <a href="https://szymonkaliski.com/notes/design-science-research/">Design Science Research</a> and related ideas; basically pitching "re-framing" the problem as the most important part of the design process</li>
<li><a href="https://press.stripe.com/maintenance-part-one">Maintenance: Of Everything, Part One</a> — Stewart Brand and Stripe Press, what more can I say</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://breandan.net/2020/06/30/graph-computation/">Computation graphs and graph computation</a></li>
<li><a href="https://x.com/tldraw/status/2028120822414549332">code by diagrams</a>, also <a href="https://paper.design/downloads">Paper Desktop app is out with MCP support</a>!</li>
<li>a <a href="https://haskellforall.com/2026/02/browse-code-by-meaning">semantic project navigator</a>, <a href="https://cognition.ai/blog/codemaps">"just-in-time" code mapping</a> (via Steve Krouse), and <a href="https://githubnext.com/projects/copernicus/">Project Copernicus</a></li>
<li><a href="https://bsky.app/profile/disconcision.com/post/3mcn7xtvmys2q">Live-Coding (the music kind) in Hazel</a></li>
<li><a href="https://www.youtube.com/watch?v=5PJRCz0t7yY">Gyms, Zoos, and Museums: Your documentation should be in-game</a> which seems super related to the <a href="https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/#feedback-loops-for-llms">Feedback Loops for LLMs</a> above</li>
<li><a href="https://www.youtube.com/watch?v=hUFDF62e37s">talk on "Automat" from Marek Rogalski</a> for the most skeuomorphic <a href="https://szymonkaliski.com/notes/vpl/">VPL</a> you've ever seen</li>
<li><a href="https://www.youtube.com/watch?v=qS20Z0RXr28">a new talk from Alan Kay!</a></li>
</ul>]]></description>
            <link>https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2026-03-30-q1-2026/</guid>
            <pubDate>Mon, 30 Mar 2026 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q4 2025]]></title>
            <description><![CDATA[<p>Hi,</p>
<p>the biggest news of this quarter is that I'm an independent consultant now!</p>
<p>I left <a href="https://replit.com">Replit</a> in October, after 2.5 years.
While there, I oscillated between exploring and prototyping, and designing and developing production features.
It definitely was a valuable experience to be a part of rapid two-orders-of-magnitude ARR growth.
Some of my notable projects are documented on Replit's blog: <a href="https://blog.replit.com/new-and-improved-console">1</a>, <a href="https://blog.replit.com/shell2">2</a>, <a href="https://blog.replit.com/introducing-workflows">3</a>, <a href="https://blog.replit.com/ports">4</a>, and the <a href="https://szymonkaliski.com/projects/replit-agent/">Agent</a> itself.</p>
<p>The company is now focused on creating production applications by prompting, and I've been itching for a while to explore some of the other <a href="https://szymonkaliski.com/notes/open-questions-around-llm-interfaces/">Open Questions Around LLM Interfaces</a>.
Going independent seemed like the best way to do so, and I'm excited to share that I'm currently working with <a href="https://labs.google/">Google Creative Lab</a>, where I'm exploring some of these ideas!</p>
<p><strong>Reach out if you're interested in working together: <a href="mailto:hi@szymonkaliski.com">hi@szymonkaliski.com</a></strong></p>
<hr>
<p>In the meantime, I've been making small <em>vignettes</em> around interacting with the language models.
I believe that <em>chatting</em> is not going to work for everything, and that there's still a lot to figure out in how to do things with these new <em>fuzzy functions</em>.</p>
<p>Below is a small sampling of these explorations, some of them done on my own time, some at Google.</p>
<h2>Codegen Environments</h2>
<p>One of the directions I'm excited about is how can a <em>little codegen</em> fit within a <a href="https://szymonkaliski.com/notes/programming-system/">Programming System</a> — instead of generating whole applications, can we, by the nature of the <em>environment</em>, get compartmentalization, interoperability, and other interesting properties automatically?</p>
<p>Below is a canvas-based environment where each node is generated by the model from a short piece of text, and the way you use it is a mix of natural canvas interactions: duplicating, resizing, moving around... — with the added communication channel of being able to react to other nodes:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/shaders.mp4"></video>
<p>A <a href="http://joshuahhh.com">friend</a> made a <a href="https://bsky.app/profile/joshuahhh.com/post/3m2obrtpgkc2l">good point</a> that instead of asking "to the left of" we could have draggable whiskers coming out of the nodes, and that evolved into a full on <em>operating system</em> of sorts, where every tool is generated on the fly, and I can combine them together by roughly describing what I want:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/microapps.mp4"></video>
<p>I also looked a bit into the <em>meta</em> direction of making the <em>process of making</em> visible — which was inspired by earlier experiments with <a href="https://szymonkaliski.com/projects/liunon/">Liunon</a>:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/history.mp4"></video>
<p>Here, instead of changing the prompt inline, you create modifications on top of the things you already made.
I quite like this linear history of progress, but this clearly starts lacking when you want to explore multiple possible directions (which is where something like <a href="http://spellburstllm.github.io">Spellburst</a> comes in).</p>
<p>Finally, I poked around combining some of these ideas with <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a>, but I didn't get very far:</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/ink-1.mp4"></video>
  </div>
  <div class="w-100 ml1">
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/ink-2.mp4"></video>
  </div>
</div>
<p>The main issues were that bounding box detection for detecting similar hand-drawn items remained finicky, and I hit a wall with my vibe-coding skill and would have to get into the code to debug some of the performance issues, which really didn't seem like a fun way to spend a couple of evenings of my time.</p>
<h2>Improving Chat</h2>
<p>I also played around with expanding the chat interface itself.</p>
<p>Often when I try to learn with the help of an LLM, I want to start follow-up questions from specific passages in the reply:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/branching.mp4"></video>
<p>While this is a complete prototype, I don't really use it — I think partly because I'd have to go to some directory and run <code>npm start</code>, and partly because often I'm already a couple of questions deep in an LLM session, and it's very hard to move that over somewhere else.
I'm not sure what to do about this!
I could host this tool somewhere, and that would solve the first problem, but the second one is a larger issue — I'd either have to move all my conversations there, or know up-front when something will turn into more of an exploratory session.</p>
<p>If only we had <a href="http://inkandswitch.com/malleable-software/">Malleable Software</a> so I could jam this into some existing tool that I already use...</p>
<p>On the topic of learning with LLMs, another idea that I explored was prompting the model to generate explanations together with interactive demos, with an extra twist — these demos have to store their state in a way that's inspectable, and attached as a part of conversation.
What that allows for, is exploring some behavior in an interactive way, and then asking follow-up questions about this specific state you're seeing:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/visible-state.mp4"></video>
<p>I know you could always take a screenshot and paste it back into the chat, but I do wonder why none of the AI providers do this automatically.
We can create an artifact, a canvas, or what-have-you, but its run state remains invisible to the model.</p>
<h2>Little Tools</h2>
<p>A completely different direction that I'm interested in, is exploring small situated "fuzzy" tools:</p>
<p><a href="https://github.com/szymonkaliski/name-pdfs"><code>name-pdfs</code></a> renames PDF files by their content. I use it a couple of times a week after downloading a bunch of articles.</p>
<p><a href="https://github.com/szymonkaliski/ai-grep"><code>ai-grep</code></a> finds things "fuzzily" matching the search term.
It nicely complements something like <code>rg</code> (even the output format is the same), and can be useful when I forget the exact wording I used.
I use it a couple of times a month, most often when searching through my wiki, or an unfamiliar codebase</p>
<p><a href="https://github.com/szymonkaliski/ai-translate"><code>ai-translate</code></a> was an experiment in bi-directional text-to-text translation, it sounded interesting on paper, but I don't use it at all.
Still, the idea of translating between code and pseudo-code has stuck with me:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/translate.mp4"></video>
<hr>
<p>I'm hopeful about the possibilities LLMs open for <a href="https://szymonkaliski.com/notes/end-user-programming/">End-User Programming</a> and creative tools — it's been exciting to revisit the ideas I wrote about seven years ago in this <a href="https://www.inkandswitch.com/end-user-programming/">Ink&#x26;Switch essay</a>.
One of the hard parts is now (at least partly) solved, but <a href="https://bsky.app/profile/szymonkaliski.com/post/3maqzhxe25c2b">a lot of the other ones</a> still remain!</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li><a href="https://www.amazon.com/Languages-Art-Nelson-Goodman/dp/0915144344">Languages of Art</a></li>
<li>I went on a little side-quest on education:
<ul>
<li><a href="https://www.amazon.com/Theories-Childhood-Second-Introduction-Montessori-dp-1605541389/dp/1605541389/ref=dp_ob_title_bk">Theories of Childhood</a> — a very brief high-level overview of the <a href="https://szymonkaliski.com/notes/constructionism/">Constructionism</a>/<a href="https://szymonkaliski.com/notes/constructivism/">Constructivism</a> thread, I don't think it's really that valuable on its own, but was a nice quick refresher on the general ideas, and how they build up on each-other</li>
<li><a href="https://www.jstor.org/stable/j.ctvjf9vz4">Mind in Society</a> — highly recommended</li>
<li><a href="https://mitpress.mit.edu/9780262541328/changing-minds/">Changing Minds</a> — also highly recommended, both for the ideas, and for the closer look at Boxer</li>
<li><a href="https://worrydream.com/refs/Kay_2007_-_Children_Learning_by_Doing.pdf">Children Learning by Doing</a>, a paper, not a book, but still fits nicely into this thread, and still highly recommended</li>
<li>I also attempted <a href="https://en.wikipedia.org/wiki/Democracy_and_Education">Democracy and Education</a> but I gave up quickly, it was just too hard to read</li>
</ul>
</li>
<li>I also went through <a href="https://mitpress.mit.edu/9780262525503/interface/">Interface</a> which was a very philosophical and broad look at, well, interfaces, and I've been making very slow progress on <a href="https://global.oup.com/academic/product/wolperts-principles-of-development-9780192896612">Principles of Development</a> — I'm skimming most of it, but I find the ideas fascinating — both the processes happening during the development of the embryo, and how we came to understand them through various (sometimes gross) experiments</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://github.com/tneukom/topolang">an experimental programming language based on topological pattern matching in images</a></li>
<li>I love <a href="https://x.com/praveenisomer/status/1978442271289651405">this visual explainer</a>, the arrows pointing directly from the "abstract" to the "concrete" have heavy <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a> vibes — sadly this is just a static diagram, not an executable one</li>
<li><a href="https://spidermonkey.dev/blog/2025/10/28/iongraph-web.html">Who needs Graphviz when you can build it yourself?</a></li>
<li><a href="https://www.raphkoster.com/2025/11/03/game-design-is-simple-actually/">Game design is simple, actually</a></li>
<li><a href="https://fun-and-awe.io/operator">Spatial music-making experience</a></li>
<li>some pretty pictures:
<ul>
<li><a href="https://bsky.app/profile/disconcision.com/post/3m55gjuoyl22c">https://bsky.app/profile/disconcision.com/post/3m55gjuoyl22c</a></li>
<li><a href="https://www.artstation.com/artwork/Nqw4Nb">https://www.artstation.com/artwork/Nqw4Nb</a></li>
<li><a href="https://x.com/colindmg/status/1978847115779440989">https://x.com/colindmg/status/1978847115779440989</a></li>
</ul>
</li>
<li>some videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=9HIy5dJE-zQ">Mystery of the Quintic</a></li>
<li><a href="https://www.youtube.com/watch?v=eOrdwyW28uc">Overhauling a 15-year-old Max patch for Oneohtrix Point Never</a></li>
<li><a href="https://www.youtube.com/watch?v=OESXpxUH_jI">The Curious Case of Zoomable User Interfaces and AI</a></li>
<li><a href="https://www.youtube.com/watch?v=-lHXZk5M6cI">The Actual Reason Semiconductors Are Different From Conductors and Insulators</a></li>
</ul>
</li>
</ul>]]></description>
            <link>https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2026-01-05-q4-2025/</guid>
            <pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q3 2025]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>Our daughter just turned one!</p>
<p>The days really are long, and the years really are short.
She seems to be learning something new every day now, from crawling to standing up, to making sounds, to waving at us — it's been amazing.</p>
<h2>MirrorState</h2>
<p><a href="https://szymonkaliski.com/projects/mirrorstate/">MirrorState</a> is a React library and a Vite plugin which handles bi-directional state synchronization through JSON state files.
This way the changes made through UI end up on disk in human-readable form, and changes made to these files propagate live to the UI.</p>
<p>MirrorState was almost fully build with LLMs, in, I think, somewhat interesting way:</p>
<ul>
<li>I have an <code>AGENT.md</code>/<code>CLAUDE.md</code> file which holds a simple instruction on how to use <code>PROJECT.md</code></li>
<li>the <code>PROJECT.md</code> is a mix of high-level "PRD", and a task list subdivided into "features"</li>
<li>as I was working, I would prompt the LLM to expand what I'm thinking about into a feature, I would then both chat with it some more, and manually edit the file, and once I was done, I'd ask to implement and check off the items
<ul>
<li>I'm honestly not sure if this approach helps with LLM grounding into the state of things, or pollutes its context, but it definitely helps me stay on the right track, and makes sure that we're - at least partially - are "talking" about the same thing - especially when coming back to the project and starting a new chat session</li>
</ul>
</li>
</ul>
<p>You can try out MirrorState here: <a href="http://github.com/szymonkaliski/mirrorstate">szymonkaliski/mirrorstate</a></p>
<h2>What if Iannis Xenakis had Figma?</h2>
<p>Iannis Xenakis remains a huge inspiration, I was poking around his graphical notation and made a silly demo to "play" them from Figma:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2025-09-29-q3-2025/fignakis.mp4"></video>
<p>I learned the hard way that Figma plugins have no support for WebMIDI, which is disappointing.
WebSockets do work though, so I just piped the values through a localhost server, but I really don't understand the limitation (I also do understand how some could argue that there's no use for MIDI in Figma).</p>
<h2>Pulling Myself Out of the Computer</h2>
<p>Over the summer I also managed to discover (yet again) that spending too much time in the computer (or maybe not having anything to balance it with?) is not good for me.</p>
<p>I decided to pick up sketching, and I'm slowly moving through <a href="https://www.amazon.com/How-Draw-sketching-environments-imagination/dp/1933492732">How to Draw</a>, aiming for just a couple of minutes of exercises as often as I can.
It's been really fun to spend time with a pencil and a piece of paper, and to move my body in a way that neither barbell nor keyboard forces it to.</p>
<p>I've also been noodling on some music again, which I missed a lot.
Optimizing my studio for having a single switch to power on all the gear and be ready to play immediately has really helped with getting just a few minutes in here and there.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li>I skimmed through <a href="https://pi.math.cornell.edu/~hatcher/AT/ATpage.html">Algebraic Topology</a> and <a href="https://www.cambridge.org/core/books/topology-for-computing/1171035B570105A57865CEA390BA5E74">Topology for Computing</a> — most of it is over my head at the moment, but I do like the pictures, and I have some intuition around what homotopy is, which is nice</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://github.com/prathyvsh/semantic-zoom/">Catalogue of semantic zoom patterns</a></li>
<li><a href="https://www.youtube.com/watch?v=Hju0H3NHxVI">This is what computers are for</a></li>
<li><a href="https://www.evsc.net/posts/fiber-play.html">Fiber optics sculptures</a></li>
<li><a href="https://arxiv.org/pdf/2502.03719">Code Shaping: Iterative Code Editing with Free-form AI-Interpreted Sketching</a></li>
<li><a href="https://mastodon.gamedev.place/@bvisness/115052133879820415">A cool compiler visualizer</a></li>
<li><a href="https://tomasp.net/architecture/">Critical Architecture/Software Theory</a></li>
</ul>
<p>Self:</p>
<ul>
<li>I published some early unstructured thoughts on <a href="https://szymonkaliski.com/notes/open-questions-around-llm-interfaces/">Open Questions Around LLM Interfaces</a>, <a href="https://szymonkaliski.com/notes/vpls-and-llms/">VPLs and LLMs</a>, and <a href="https://szymonkaliski.com/notes/learning-to-program-and-llms/">"Learning to Program" and LLMs</a></li>
</ul>]]></description>
            <link>https://szymonkaliski.com/newsletter/2025-09-29-q3-2025/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2025-09-29-q3-2025/</guid>
            <pubDate>Mon, 29 Sep 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[MirrorState]]></title>
            <description><![CDATA[<p><a href="http://github.com/szymonkaliski/mirrorstate">MirrorState</a> is a Vite plugin and a React library, which in tandem allow for bi-directional state synchronization through JSON files.</p>
<p>Edits made through the React state update the file content, and edits to the file update the UI:</p>
<video loop autoplay muted>
  <source src="https://szymonkaliski.com/projects/mirrorstate/mirrorstate-demo.mp4" type="video/mp4">
</video>
<p>MirrorState grew out of a few ad-hoc iterations spread across various side-projects.
The main motivation comes from the approach of building prototypes with a single source of truth, which gets hardcoded with initial values.</p>
<p>What often happens further into the project is that I'll take a couple of actions in the UI, and I want to preserve that specific state back into the file — at which point I have to either manually recreate it, or make it available in the console, <code>JSON.stringify</code>, and copy-paste back into the code.</p>
<hr>
<p>In development, the Vite plugin file-watches all <code>*.mirror.json</code> files for changes, and beams them up through a websocket.
The React library connects to that websocket, swaps state on new values from the file, and beams back down the edits made in the UI.
In production build, the content of the <code>*.mirror.json</code> file is hardcoded into the build artifact.</p>
<p>Go try it out: <a href="http://github.com/szymonkaliski/mirrorstate">szymonkaliski/mirrorstate</a></p>
<hr>
<p>While MirrorState grew organically out of my own needs, there are some interesting parallels to:</p>
<ol>
<li><a href="https://dl.acm.org/doi/10.1145/3586183.3606801">Riffle: Reactive Relational State for Local-First Applications</a> — at some point during its development <a href="https://www.geoffreylitt.com">Geoffrey</a> showed me a demo of opening up the application state in a database editing tool, and being able to inspect and change it as the application runs, which really resonated</li>
<li><a href="https://jamesbvaughan.com/bidirectional-editing/">Code⇄GUI bidirectional editing via LSP</a> — which (obviously) relies on LSP to achieve similar results (<a href="https://github.com/jasonjmcghee/livelove">livelove</a> is another, more developed, take at this idea)</li>
<li><a href="https://www.scattered-thoughts.net/writing/the-program-is-the-database-is-the-interface">The program is the database is the interface</a> — which is at best an "aspirational" connection, and extends this idea of bi-directionally editable data structure with being able to ... edit itself</li>
</ol>]]></description>
            <link>https://szymonkaliski.com/projects/mirrorstate/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/mirrorstate/</guid>
            <pubDate>Fri, 01 Aug 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q2 2025]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>In the last issue I <a href="https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/#:~:text=I&#x27;m%20back%20to%20tinkering%20on%20some%20interface%2Dy%20side%2Dprojects%2C%20but%20I%20need%20more%20time%20to%20make%20things%20legible%2C%20and%20time%20is%20hard%20to%20find%20right%20now.">mentioned</a> I've been working on some more computer-y side-projects, and here's the first one: <a href="https://szymonkaliski.com/projects/vineyard/">Vineyard</a> — an exploration of prototype-based component re-use.</p>
<img src="https://szymonkaliski.com/newsletter/2025-06-30-q2-2025/vineyard.png" alt="Vineyard Screenshot" width="2636" height="1794">
<p>This idea was brewing in the back of my mind for years now — at the moment it still feels undercooked, but I'm curious to get some feedback and hear your thoughts.
Go <a href="https://szymonkaliski.com/projects/vineyard/">check it out</a>, there's a bit of a longer write-up and a <a href="https://szymonkaliski.github.io/vineyard/">live version to play with</a>.</p>
<hr>
<p>A friend recently made a <a href="https://kevinlynagh.com/newsletter/2024_10_transcription_app_art_wall/#making-a-dictation-app-in-a-weekend">dictation app in a weekend</a>.</p>
<p>Here's my 15-minute version:</p>
<pre><code>#!/usr/bin/env bash

set -euo pipefail

export OPENAI_API_KEY="$(cat ~/.openai-key)"

tmp=$(mktemp /tmp/whisper.XXXXXX.wav)
trap 'rm -f "$tmp"' EXIT

echo "Recording... (press Ctrl-C to stop)"
rec --no-show-progress -c 1 -b 16 -r 16000 "$tmp"

[ "$(soxi -r "$tmp")" != "16000" ] &#x26;&#x26; sox "$tmp" -q -r 16000 "${tmp%.wav}_16k.wav" &#x26;&#x26; mv "${tmp%.wav}_16k.wav" "$tmp"

text=$(openai api audio.transcriptions.create -m whisper-1 -f "$tmp" --response-format text)

echo $text | pbcopy
printf "\nTranscript:\n%s\n" "$text"
</code></pre>
<p>Adding a <a href="https://github.com/szymonkaliski/home-configuration/blob/c8b7bd7301118537a6267221d0cad99c960698a0/dotfiles/hammerspoon/bindings/whisper.lua">global shortcut in Hammerspoon</a> was another 5 minutes on top of that.</p>
<p>Yes, it sends the audio files to OpenAI and requires a network connection — I don't care, for my limited use it's more than ok.</p>
<p>It would be easy to <a href="https://george.mand.is/2025/06/openai-charges-by-the-minute-so-make-the-minutes-shorter/">speed up the recorded audio before beaming up to OpenAI to save on some of the cost</a>.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li><a href="https://www.amazon.com/Annotated-Flatland-Romance-Many-Dimensions/dp/0465011233">The Annotated Flatland</a> (and now I wish every book had a <a href="https://gwern.net/red#:~:text=First%20page%20of%20Tractate%20Pesahim%E2%81%A0%20from%20the%20Babylonian%20Talmud%E2%81%A0;%20rubrication%20annotations%20by%20%E2%81%A0Thomas%20Shoemaker%20(2015?);%20a%20%E2%81%A0similar%20annotation%E2%81%A0%20appears%20on%20%E2%81%A0Tufte%E2%80%99s%20website%E2%81%A0%20(redrawn%20by%20Tufte?);%20%E2%81%A0non%2Drubricated%20annotated%20example%E2%81%A0">Talmudic <em>rubrication</em></a>)</li>
<li><a href="https://www.amazon.com/Logic-Design-Revised-Science-Mathematics/dp/1592288499">Logic and Design In Art, Science, And Mathematics</a></li>
<li><a href="https://github.com/hmemcpy/milewski-ctfp-pdf">Category Theory for Programmers</a></li>
</ul>
<p>On the web:</p>
<ul>
<li>Ink&#x26;Switch has a new essay on <a href="https://www.inkandswitch.com/essay/malleable-software/">Malleable Software</a></li>
<li><a href="https://arxiv.org/abs/2503.06911">Beyond Code Generation: LLM-supported Exploration of the Program Design Space</a></li>
<li><a href="https://newsletter.rhizomerd.com/p/what-i-learned-building-whole-earth">What I Learned Building Whole Earth AI</a></li>
<li><a href="https://blog.rahix.de/design-for-3d-printing/">Design for 3D-Printing</a></li>
<li><a href="https://ryanyen2.github.io/publications/semi-formal-programming/">Semi-Formal Programming</a></li>
<li><a href="https://scrappy.jrcpl.us">Scrappy</a> from John Chang and Pontus Granström (with a <a href="https://pontus.granstrom.me/scrappy/">nice write-up</a>)</li>
<li><a href="https://www.youtube.com/watch?v=XyQ4ZTS5dGw">Agentic Engineering in Action with Mitchell Hashimoto</a></li>
</ul>]]></description>
            <link>https://szymonkaliski.com/newsletter/2025-06-30-q2-2025/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2025-06-30-q2-2025/</guid>
            <pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Vineyard]]></title>
            <description><![CDATA[<p>An exploration of a <a href="https://en.wikipedia.org/wiki/Prototype-based_programming">prototype-inspired</a> component re-use.</p>
<img src="https://szymonkaliski.com/projects/vineyard/vineyard-bg.png" alt="Vineyard screenshot" width="2636" height="1794">
<h2>Motivation</h2>
<p>Creating reusable components for building applications is a standard industry practice.
You don't re-implement a button for every screen of your application, you have a single button component, that's re-used across the code.
Maybe all of your buttons are a specific shade of blue, and that's fine, until on one of the pages, you suddenly need a red one, as the on-click handler does something destructive.</p>
<p>A <code>isDangerous</code> property could be introduced, and now all the dangerous buttons are the same shade of red.
But what if you also have "warning" buttons, "inline" ones, a "hidden" one just for screen-readers, etc?
Maybe it's fine to keep adding properties, or maybe you create a component for each of these uses.</p>
<p>The actual example that motivated this work was when I had a specific well-designed, and well-behaving modal component, used across some project.
In one specific place, that modal needed three buttons instead of two, for various reasons.
The standard practice would be to decompose the modal into a wrapper that handles some functionality (like displaying as an overlay), some generic body wrapper, and a modal-button section, etc.
That's a lot of refactoring to just get a single-use variation to work.</p>
<p>Vineyard is a prototype that explores what it would feel like to be able to override arbitrary properties of any component without extra work.</p>
<h2>Project Walkthrough</h2>
<p>The leftmost sidebar is a tree of components, organized by ancestry.
In this case Blank is the general starting point (a <code>div</code>), then we have a Button component, and Primary is a Button with additional custom styling.</p>
<p>When I make edits to the Button, for example adding an extra border, that propagates to Primary, and all the other children of that component:</p>
<div style="max-width: 760px">
  <video controls muted playsinline>
    <source src="https://szymonkaliski.com/projects/vineyard/extra-border.mp4" type="video/mp4">
  </video>
</div>
<p>I can also make sure that each Button has an icon:</p>
<div style="max-width: 760px">
  <video controls muted playsinline>
    <source src="https://szymonkaliski.com/projects/vineyard/icon-on-buttons.mp4" type="video/mp4">
  </video>
</div>
<p>But, decide that I don't want it in the Secondary and Underline styles:</p>
<div style="max-width: 760px">
  <video controls muted playsinline>
    <source src="https://szymonkaliski.com/projects/vineyard/no-icon-on-secondary-button.mp4" type="video/mp4">
  </video>
</div>
<p>If we come back to the motivating example of building a Modal, here's a general outline of the component:</p>
<div style="max-width: 760px">
  <img src="https://szymonkaliski.com/projects/vineyard/modal-overview.png" alt="Modal component overview" width="1752" height="790">
</div>
<p>I can create a variation with three buttons:</p>
<div style="max-width: 760px">
  <video controls muted playsinline>
    <source src="https://szymonkaliski.com/projects/vineyard/three-button-variation.mp4" type="video/mp4">
  </video>
</div>
<p>Even though I reordered the buttons and modified the subtree of the component, other changes still propagate, like making the default button blue:</p>
<div style="max-width: 760px">
  <video controls muted playsinline>
    <source src="https://szymonkaliski.com/projects/vineyard/edits-still-propagate.mp4" type="video/mp4">
  </video>
</div>
<p>Finally, changes I make are recorded in each component, as a side-effect of how the system is implemented:</p>
<div style="max-width: 760px">
  <video controls muted playsinline>
    <source src="https://szymonkaliski.com/projects/vineyard/scrub.mp4" type="video/mp4">
  </video>
</div>
<p>You can <a href="https://szymonkaliski.github.io/vineyard/">play with Vineyard online</a>.</p>
<h2>Open Questions</h2>
<ul>
<li><strong>It's hard to judge how something like this would feel if used authentically.</strong> The system is hermetically sealed right now, and I think a good next step would be some way to maybe export these components into React. Or maybe even somehow just "use" them, without explicit "exporting"?</li>
<li><strong>It's unclear what should happen when a component is removed.</strong> For example, in the demo above we use Button all over the place, what should happen if I just remove that component?</li>
<li><strong>What about the component functionality?</strong> What it would look like to handle button clicks in this system?</li>
</ul>
<h2>References</h2>
<p>Vineyard was heavily inspired by <a href="https://aprt.us/">Apparatus</a> (a gift that keeps on giving).
Even if we ignore the programming model and the solver, the additional compelling idea is how the component system works:</p>
<ul>
<li>you can add components to other components, and modifying the parent instance, propagates the changes through the tree, which is fairly standard</li>
<li>you can also override every property that the component has, without "ejecting" it into the current canvas — and the properties that were not overridden, still continue to propagate (which is also the case in Vineyard)</li>
<li>even more interestingly, you can do things like reorder the child components, remove some of them, and the property propagation still holds! (which feels fantastic, and is also the case in my prototype)</li>
</ul>
<p><a href="https://en.wikipedia.org/wiki/Self_(programming_language)#Prototype-based_programming_languages">Self</a> is another system that works this way that I know of, though probably feels less <em>familiar</em> than Apparatus' or Vineyard's property trees.</p>]]></description>
            <link>https://szymonkaliski.com/projects/vineyard/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/vineyard/</guid>
            <pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q1 2025]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>I'm back to tinkering on some interface-y side-projects, but I need more time to make things legible, and time is hard to find right now.</p>
<p>Surprisingly, I somehow did manage to motorize external blinds in my studio (well, one of them so far) using a car power window motor, a couple of relays, and a bit of 3D printing, enjoy!</p>
<h2>Motorizing External Blinds</h2>
<p>My <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#moving-to-the-basement">basement studio</a> has become a project in itself — there's always something to improve in between other distractions.</p>
<p>One small annoyance is that due to how deep my desks are, and the fact that the windows are behind them, the tape to roll up the external blinds is hard to reach.
The room is on the ground level, and I do roll them up and down for extra safety (and the rare occasion when the sun shines directly into my eyes).</p>
<p>I could <em>just</em> buy motorized blinds, but where's the fun in that?
Not to mention this being a somewhat larger retrofit, which I didn't want to go through.
Instead, I decided to see if I can motorize the current manual system while maximizing the amount of things I repurpose from it.
In the end, the plastic housing had to go, but I kept the wall mounts and reused the internal spool, but I'm getting ahead of myself.</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/roller-before.png" width="1200" height="1200">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/roller-after.png" width="1200" height="1200">
  </div>
</div>
<p>The project started by figuring out how heavy the blinds even are.
I tied a knot on the tape, attached a portable scale, and pulled until the blinds started rising (~4kg in my case); from this and the radius of the spool I could calculate the torque (~1.2Nm), and from this — find a motor.</p>
<p>Using a wormdrive seemed like a good idea since there's no back-driving — it can stop at any position without supplying any extra power, which is great for this use — the ambition was to be able to not only roll up the blind, but also to keep it up there.
Finding a suitable motor wasn't easy (sadly, there's no <a href="http://mcmaster.com">McMaster</a> in Poland), and the ones I could find with this sort of torque were getting somewhat expensive.
I randomly stumbled upon suggestion online that car window power motors are all three: cheap, worm-driven, and pretty powerful.
I found a 5USD one (sic!) with enough torque to easily roll up the blind when connected to 12V/6A power.</p>
<p>Electronics were pretty simple as well.
Since I wanted to only control the motor direction (or stop it completely) I didn't need any fancy motor drivers, and instead I could use two relays wired like so:</p>
<img src="https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/wiring.png" alt="Wiring of two relays to control a DC motor" width="1600" height="900">
<p>If one is on and the other off, the motor turns; swapping them around makes it turn in the opposite direction; and if both are off, the motor is off too.</p>
<p>I needed some form of feedback on how far the blind has moved, though.
I experimented with using <a href="https://en.wikipedia.org/wiki/Hall_effect_sensor">Hall sensor</a> and some magnets placed on the spool, but couldn't get reliable readings from it.
Part of it is that apparently the ADC on ESP32 is not that great, and part is that I was using a 5V module with 3.3V logic on ESP32, and I was too impatient to play around with a level shifter.
In any case an IR sensor with some simple alternating black-white pattern glued on the spool works great — I went with 10 steps per revolution, which is more than enough for this use.</p>
<p>Controlling the blinds happens through MQTT.
I have a couple of "debug" routes: one where I can manually move the motor forward/backward by a specified number of steps, and another one where I can set the start and stop endpoint based on the current step (these values are stored in flash so they survive device restarts).</p>
<p>With this, it's pretty straight-forward to create the "end-user" routes: one to get the current position (in 0-100%), and one to set the desired position (also in 0-100%).
This is all wired up to a simple Node-RED interface (and HomeKit, through Homebridge), which is what I already use for a bunch of other things.
I also connected this to my <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#:~:text=I%20have%20an%20ESP32%20monitoring%20for%20a%20presence%20of%20a%20specific%20BLE%20beacon%20attached%20to%20my%20keychain%2C%20so%20the%20system%20knows%20if%20I&#x27;m%20in%20the%20studio%20or%20not.">BLE beacon presence detection</a>.
Walking into the room in the morning and the blinds automatically opening never gets old.</p>
<p>Even with everything being <em>simple</em>, this project end-to-end took over two months.
I mainly didn't have much time to tinker, but also:</p>
<ul>
<li>turns out you need proper wire gauge for 6A (I got to see some exciting smoke once!)</li>
<li>you also need properly graded connectors (a random barrel jack lying around is not gonna cut it; smoke again)</li>
<li>ESP32 uses one of the two ADCs for Wi-Fi, which was a fun debugging experience when my sensor was working fine in isolation but not when I wanted to read it through MQTT</li>
<li>a hard-to-see smudge of glue on the black part of the encoder pattern for the IR sensor was tripping it up, which made me waste two days trying to figure out why <em>sometimes</em> I lose a step or two (solved in two minutes: reprint the pattern and glue it again, just more carefully the second time around)</li>
<li>the design of the various parts can look good in CAD, but always need a bunch of iterations to get everything to fit perfectly — and even with 3D printing we are far from the quick feedback loop of programming</li>
</ul>
<img src="https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/wip-prints.jpg" alt="Work-in-progress 3D prints" width="1600" height="900">
<p>I didn't take you on this whole journey for nothing though (I know the window is dirty, in my defence the building façade is being renovated):</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/blind-rolls-up.mp4"></video>
<h2>Misc Stuff</h2>
<p>A filament dry box is a fun quick project to make your 3D prints less stringy, using a 5USD container from IKEA, a PTFE tube with a coupler, and 15 minutes of your time.
I printed <a href="https://www.printables.com/model/34472-knurled-pc4-m6-ptfe-drybox-feeder">this</a>, drilled a small hole in the container, thrown in a bunch of silica gel and a hygrometer, and closed it up.
The hygrometer currently shows a sad face with "too dry" text next to it, so I assume the filament is happy.</p>
<hr>
<p>As I was debugging the hall sensor, I wished for a nice and fast "digital scope" where I could pipe streaming logs of values and get a zoomable and scrollable chart that I could inspect, like one would do with an oscilloscope.
Arduino has a <a href="https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-serial-plotter/">Serial Plotter</a>, but it's a bit oversimplified for what I want — I can't even scroll back to see the history, or set a specific vertical and horizontal scale.</p>
<p>Do you know of any tools that fit this description? Or do I have to Zig and OpenGL on my own?</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li>my <a href="https://szymonkaliski.com/newsletter/2025-01-06-q4-2024/#:~:text=and%20more%20math">recent readings on category theory</a> somehow brought me back to computers again — I syntopically went through: <a href="https://homotopytypetheory.org/book/">Homotopy Type Theory</a>, <a href="https://www.cis.upenn.edu/~bcpierce/tapl/">Types and Programming Languages</a> and <a href="https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/ttfp.pdf">Type Theory &#x26; Functional Programming</a>; I liked the last one the most, maybe because I red it after the first two ones, so things just looked more familiar</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=AziAhVuiU3Q">cool prototype combining UI and logic on the same canvas</a> which reminds me of Yoshiki Schmitz's work (who's sadly not with us anymore), like <a href="https://accidental-friction-435.notion.site/Data-Design-Language-7dcc0f4ef03f4e3db380517eec0e04b4">Data Design Language</a> or <a href="https://accidental-friction-435.notion.site/Dango-b46c07f3dc224f968c768885abe70e70">Dango</a></li>
<li><a href="https://danieldelaney.net/chat/">"You don’t program by chatting. You program by writing documents."</a></li>
<li><a href="https://www.bippy.dev">a nice little tool to hack into React internals</a></li>
<li><a href="https://www.mattkeeter.com">Matt Keeter</a> is at it again (continuously?) with <a href="https://www.mattkeeter.com/projects/fidget/">Fidget</a> (and a <a href="https://www.youtube.com/watch?v=UxGxsGnbyJ4">great talk</a>)</li>
<li>we shipped <a href="https://blog.replit.com/introducing-workflows">Workflows</a> at Replit; I wrote a task runner on top of the previous work of <a href="https://blog.replit.com/shell2">Multiplayer Shell</a>, I'm pretty proud of it — it's used not only by end-users but also by the <a href="https://szymonkaliski.com/projects/replit-agent/#ides-for-llms">LLM</a></li>
</ul>]]></description>
            <link>https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2025-03-31-q1-2025/</guid>
            <pubDate>Mon, 31 Mar 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Workflows at Replit ↗]]></title>
            <description><![CDATA[Workflows at Replit]]></description>
            <link>https://blog.replit.com/introducing-workflows</link>
            <guid isPermaLink="true">https://blog.replit.com/introducing-workflows</guid>
            <pubDate>Wed, 26 Feb 2025 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q4 2024]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>This issue covers the last ~six months to catch up for the (understandably) <a href="https://szymonkaliski.com/newsletter/2024-09-30-q3-2024/">skipped Q3</a>.</p>
<p>It was so great to take time off to fully focus on the family.
I'm grateful that everyone is doing well, grateful for autumn that was warm enough for frequent walks, and grateful for not thinking about anything else for a while.</p>
<hr>
<p>While I was away, we launched two things at Replit that I've been heavily involved in: the Agent — LLM deeply integrated in the platform — and new, orders-of-magnitude faster, and multiplayer-native Shell experience.</p>
<p>I captured some thoughts about why LLMs need IDEs, and how they relate to <a href="https://szymonkaliski.com/notes/end-user-programming/">End-User Programming</a> in <a href="https://szymonkaliski.com/projects/replit-agent/">this short write-up</a>.</p>
<p>Improving the Shell experience was also a fun project.
I built a full vertical slice, from a <a href="https://github.com/replit/ruspty">custom PTY library</a>, up to UI/UX allowing users to run Shell sessions in the background, and collaborate with each other in multiplayer Repls.
There's a ton of technical info in the <a href="https://blog.replit.com/shell2">official launch blog post</a>, if you're interested.</p>
<h2>Less Eager Copilot</h2>
<p>Until recently I've been using LLMs for programming mainly through the <a href="https://github.com/madox2/vim-ai"><code>vim-ai</code></a> extension, <a href="https://github.com/szymonkaliski/vim-ai/tree/sk/role-prefix">slightly adapted to my personal needs</a>, sending relevant text back and forth between <code>vim</code>'s split views.
This meant that I only really used it for bigger "global" tasks — rewriting whole functions, fixing type issues across multiple definitions, etc.</p>
<p><a href="https://github.com/features/copilot">Copilot</a>, as a way for more "surgical" LLM-driven edits, always seemed interesting to try in a <a href="https://notes.andymatuschak.org/Effective_system_design_requires_insights_drawn_from_serious_contexts_of_use">"serious context of use"</a> kind of way.
What was stopping me, was the "ghost text" UX it relies on, which personally feels over-eager and somewhat distracting.</p>
<p>To work around this, I wrote a small extension for <a href="https://github.com/neoclide/coc.nvim"><code>coc.nvim</code></a> (which I use for LSP integrations) that man-in-the-middle's the Copilot LSP inline completions to, instead, add them to the tab-completion menu:</p>
<div style="max-width: 500px">
  <img src="https://szymonkaliski.com/newsletter/2025-01-06-q4-2024/coc-pilot.png" alt="coc-pilot integration screenshot" width="1000" height="840">
</div>
<p>I've been daily driving this for a few weeks now, and quite like it.
Maybe it's useful to some of you too: <a href="https://github.com/szymonkaliski/coc-pilot"><code>coc-pilot</code></a>.</p>
<h2>Organizing with 3D-Printing</h2>
<p>I use an <a href="https://www.ikea.com/us/en/p/bror-utility-cart-black-pine-plywood-60333850/">IKEA BROR utility cart</a> for a workbench in my <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#moving-to-the-basement">basement studio</a>.
It's pretty small and quickly gets messy when I'm doing something, making it hard to access my most-used tools.</p>
<p>A pegboard is an obvious answer for nerdy organization, and <a href="https://www.ikea.com/us/en/p/skadis-pegboard-black-50534378/">the one from IKEA</a> <em>almost</em> fits their BROR system — if only it was a couple of centimeters wider, I could simply connect them directly.</p>
<p>Instead, I had to adapt an adapter I found online to do so.
<br>
My variation is <a href="https://www.printables.com/model/1099094-ikea-skadis-to-bror-cart-attachment">here</a>, again, maybe useful to some of you.</p>
<div class="measure-wide">
  <img src="https://szymonkaliski.com/newsletter/2025-01-06-q4-2024/workbench-pegboard.png" alt="Photo of the workbench and pegboard" width="1200" height="1200">
</div>
<p>I wish IKEA was more like Lego.
There must be a reason why their furniture (especially the "utility" lines) is not a bit more standardized.
I don't think it's "<a href="https://en.wikipedia.org/wiki/Vendor_lock-in">vendor lock-in</a>," since the standardization I wish for is just across the IKEA stuff, which would lock us in even more.
Let me know if you have any ideas?</p>
<p>On the 3D-printing topic, the pegboard attachments from IKEA are not that versatile, but there are (of course) a ton of people making <a href="https://www.printables.com/search/models?q=skadis">custom ones</a>.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li><a href="https://mitpress.mit.edu/9780262546799/simulation-and-its-discontents/">Simulation and Its Discontents</a></li>
<li>and more math:
<ul>
<li><a href="https://www.amazon.com/Mathematics-Its-History-Undergraduate-Texts/dp/144196052X">Mathematics and Its History</a></li>
<li><a href="https://mitpress.mit.edu/9780262660716/basic-category-theory-for-computer-scientists/">Basic Category Theory for Computer Scientists</a></li>
<li><a href="https://www.amazon.com/Category-Theory-Context-Aurora-Originals/dp/048680903X">Category Theory In Context</a></li>
<li><a href="https://www.amazon.com/Topology-Munkres/dp/9332549532/">Topology</a></li>
</ul>
</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://x.com/GopalKRaman/status/1817718930590306747">A collection of talks on UIs and LLMs</a></li>
<li><a href="https://x.com/repalash/status/1816120077915173342">I love how the documentation here is executable, and part of the tool</a></li>
<li><a href="https://calculatingempires.net">"A Genealogy of Technology and Power Since 1500"</a></li>
<li><a href="https://www.reddit.com/r/malelivingspace/comments/1gbmxoi/i_gave_my_partner_the_whole_basement_except_for/">"I built myself an ISO 5 certified positive pressure cleanroom in my basement to pursue independent research"</a></li>
<li><a href="https://mas.to/@jason@clj.social/113558966967585984">Live values in your editor</a></li>
<li><a href="http://alltom.com/pages/ppl-lab-notebook/008.html">Probabilistic spreadsheet UI</a></li>
<li><a href="https://austinhenley.com/blog/mirrorlang.html">Programming-by-example with LLM</a></li>
<li><a href="https://bitfieldconsulting.com/posts/need-money">"If you need the money, don't take the job"</a></li>
<li><a href="https://lcamtuf.coredump.cx/gcnc/full/">"Hobby CAD, CNC machining, and resin casting"</a></li>
<li><a href="https://www.threetom.com/news/a-tutorial-on-make-noise-style-indicator-lights-and-designing-an-illuminated-blind-plate-using-kicad/">How to shine LEDs through PCB</a></li>
<li><a href="https://forkingpaths.dev/posts/24-10-02/wheel_reinvention_jam_writeup.html">"a toy computing system based on (...) Dynamicland’s Realtalk"</a></li>
<li><a href="https://web.mit.edu/slava/space/essays/essay-tiapchenko4.htm">Information Display Systems for Soyuz Spaceships</a></li>
<li><a href="https://denizbicer.com/202408-UnderstandingPhysarum.html">more UIs should incorporate "weird little guys"</a> <a href="https://www.vulture.com/article/miyazaki-weird-little-guys.html">*</a></li>
<li><a href="https://x.com/its_bvisness/status/1815191052065685748?s=12">regex visualizer</a></li>
</ul>
<h2>Fin</h2>
<p>Best wishes for 2025!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2025-01-06-q4-2024/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2025-01-06-q4-2024/</guid>
            <pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[200× Faster, Persisted, Multiplayer-Native Shells at Replit ↗]]></title>
            <description><![CDATA[200× Faster, Persisted, Multiplayer-Native Shells at Replit]]></description>
            <link>https://blog.replit.com/shell2</link>
            <guid isPermaLink="true">https://blog.replit.com/shell2</guid>
            <pubDate>Mon, 14 Oct 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q3 2024]]></title>
            <description><![CDATA[<p>Everyone is healthy and happy, and a bit tired.</p>
<p>I'm taking a break for a couple of months.</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2024-09-30-q3-2024/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2024-09-30-q3-2024/</guid>
            <pubDate>Mon, 30 Sep 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Replit Agent]]></title>
            <description><![CDATA[<p>Throughout most of 2024 I was a part of the team responsible for building the Early Access version of <a href="https://blog.replit.com/introducing-replit-agent">Replit Agent</a>.</p>
<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" width="1280" height="720" src="https://www.youtube.com/embed/IYiVPrxY8-Y" frameborder="0" allowfullscreen>
  </iframe>
</div>
<p><a href="https://replit.com/">Replit</a> is an online software development platform, accessible through the browser, and backed by virtual machines running in the cloud.
This cloud-nativeness provides unique advantages over browser-based IDEs which run the code in the browser itself.
Almost coincidentally, these advantages can be also useful to LLMs, which created a foundation for developing an autonomous Agent, capable of creating software on the platform.</p>
<h2>End-User Programming</h2>
<p>The target user for the Replit Agent is not a professional software engineer, but a <a href="https://mitpress.mit.edu/9780262140539/a-small-matter-of-programming/">"local developer"</a> (after Bonnie Nardi), or a <a href="https://maggieappleton.com/home-cooked-software">"barefoot" one</a> (after Maggie Appleton).
This, in many ways, makes this work a part of the <a href="https://www.inkandswitch.com/end-user-programming/">End-User Programming</a> canon.</p>
<p>For a long time, my personal hope was that we're going to create/discover a magical <a href="https://tomasp.net/techdims/"><em>programming system</em></a> (a <em>system</em>, not a <em>language</em>) with clear heuristics, and an interface that makes programming <a href="https://www.inkandswitch.com/crosscut/#how-it-should-feel:~:text=We%20wanted%20something%20that%20doesn%E2%80%99t%20feel%20like%20programming."><em>not feel like programming</em></a>.</p>
<p>For a while after LLMs started getting better at outputting code, I thought that none of that matters anymore — if the code can be generated based on requests stated in plain English, why would we care about anything other than the results of executing it?</p>
<p>After working on the Agent, I believe that the original learnings are as important as ever.
We still need a <em>programming system</em>, one where humans and LLMs can collaborate on creating software.
The interfaces matter even more so, as there's one more "player" in the mix now — in addition to the user interacting with the environment, there's the LLM which interacts with both.</p>
<h2>IDEs for LLMs</h2>
<p>LLMs are pretty good at generating (<em>specific kinds of</em>) code, and only getting better.
But, maybe unsurprisingly, just throwing code at the problem doesn't lead to the best results — the LLM operates <em>blindly</em>, with no feedback from the environment.
Turns out, LLMs can be more powerful, if given proper tools.</p>
<p>A lot of work on this project was centered around giving the Agent well-designed <em>interfaces</em> to the environment (and to the user), for example:</p>
<ul>
<li>exposing a custom "install packages" tool gave us more control to handle various edge cases, when compared to allowing the LLM to run random packager commands directly in the shell</li>
<li>exposing a "run a command in the background" allowed us to have control about the execution loops of both the Agent and the command in question, so we can keep them in sync, and surface relevant outputs to the LLM</li>
<li>giving the Agent an "ambient awareness" of issues found by LSP, <a href="https://blog.replit.com/new-and-improved-console">outputs from the running commands</a>, screenshots of the webview outputs, etc. allowing it to course-correct as a part of its work, often without needing any additional human assistance</li>
<li>allowing the Agent to "present the results of its work" led to better interactions than trying to rely on heuristics (like opening a webview when detecting a newly opened port, which had a lot of false positives)</li>
</ul>
<p>Interestingly, we didn't build almost any of these tools from scratch — our IDE already had them.
We <em>only</em> had to surface and package them for the Agent.
In many ways this is an UI problem, just that the <em>user</em> in question is an LLM, and the <em>interface</em> has to be synchronous and textual.</p>
<hr>
<p>In this project, I was responsible for early research, design, and prototyping, both for the user-facing interface to the Agent, and for the Agent-facing interfaces to the environment and to the user.</p>
<p>The prototypes had a lot of influence over the final project, where I also contributed production code, ranging from implementing some of Agent's tools to building parts of the user interface. <a href="https://x.com/masadfrost/status/1831775830013583374">*</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/replit-agent/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/replit-agent/</guid>
            <pubDate>Thu, 05 Sep 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building a Static Site Generator]]></title>
            <description><![CDATA[<p>I built my own static site generator to generate this page (and all the other pages on this website) in the first half of 2024.</p>
<p>This is the fourth technology that I've used here, and I finally decided to take the whole thing into my own hands.
The previous version of this site was made on top of <a href="https://www.gatsbyjs.com">Gatsby</a>, and I don't really remember my reasoning for picking it, other than wanting to migrate off of Tumblr, where I migrated to from Wordpress, over a decade ago.
There's nothing wrong with any of those, it's just that I kept on making custom plugins and hacking around what Gatsby exposes, and it got to a point where the whole thing felt both very brittle, and very complicated.
On a somewhat philosophical level, I also don't think I need any frontend JavaScript for some text and an occasional image.</p>
<h2>High-Level</h2>
<p>The way the generator works is the most straight-forward approach I could come up with.
There's an <code>input</code> directory, for example:</p>
<pre><code>├── assets/
│   └── photo.png
├── writings/
│   └── 2024-07-01-static-site-generator/
│       ├── index.md
│       └── miniature.png
├── feed.xml.ts
├── style.css
└── index.tsx
</code></pre>
<p>I recursively traverse it, process every file I find, and output the same structure:</p>
<pre><code>├── assets/
│   └── photo.png
├── writings/
│   └── 2024-07-01-static-site-generator/
│       ├── index.html
│       └── miniature.png
├── feed.xml
├── style.css
└── index.html
</code></pre>
<p>Most of the behavior can be inferred from the difference between the two:</p>
<ul>
<li><code>index.tsx</code> becomes <code>index.html</code> using <a href="https://react.dev/reference/react-dom/server/renderToStaticMarkup">React's <code>renderToStaticMarkup</code></a></li>
<li><code>index.md</code> also becomes <code>index.html</code> by <em>simple process</em> of <a href="https://github.com/remarkjs/remark/tree/main/packages/remark-parse">parsing markdown into <code>mdast</code></a>, <a href="https://github.com/syntax-tree/mdast-util-to-hast">into <code>hast</code></a>, <a href="https://github.com/syntax-tree/hast-util-to-jsx-runtime/blob/main/readme.md">into <code>React</code> tree</a>, and <code>renderToStaticMarkup</code>-ing as well</li>
<li><code>feed.xml.ts</code> becomes <code>feed.xml</code>; it's a <code>.ts</code> file, and in this case I just call the <code>export default</code> from there, and write its result to the output file</li>
<li>images are lightly optimized, with their preview <code>base64</code> representations injected into the relevant <code>html</code> files</li>
<li>everything else (like <code>style.css</code>) is just copied over</li>
</ul>
<p>This way my deploy script is just an <code>rsync</code> to a server.</p>
<hr>
<p>The "fun", as always, is in the details:</p>
<ul>
<li><a href="https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/#normalizing-markdown">Normalizing Markdown</a></li>
<li><a href="https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/#backlinking">Backlinking</a></li>
<li><a href="https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/#transclusions">Transclusions</a></li>
<li><a href="https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/#time-tracking">Time-Tracking</a></li>
</ul>
<h2>Normalizing Markdown</h2>
<p>Most of my content (<a href="https://szymonkaliski.com/projects/">projects</a>, <a href="https://szymonkaliski.com/#articles">articles</a>, <a href="https://szymonkaliski.com/#newsletter">newsletter</a>) is written in markdown.
<a href="https://szymonkaliski.com/notes/">Notes</a> are also in markdown, but with a slightly different syntax, as they are generated from a subset of my <a href="https://szymonkaliski.com/writing/2020-04-19-memex-dreams/">personal wiki</a>.
For example, in the website-first markdown I keep a <code>YAML</code> header with metadata, when I link between things, I use the <code>url</code>'s instead of relative file paths, etc.</p>
<p>Instead of building a generic system to handle these differences, I just have a different code-path for when the markdown file is inside the <code>notes/</code> subdirectory or not.
This is the biggest upside of a totally custom, one-off solution: I don't have to change how I write my personal notes, or figure out how to plug into someone else's plugin system; I just write some custom code when I need it.</p>
<h2>Backlinking</h2>
<p>If you clicked around my website, you probably noticed the backlinks section at the bottom of most pages, <a href="https://szymonkaliski.com/notes/computational-dags/#backlinks">for example here</a>.
To generate this section, when I parse the markdown, I find all of the local links, and store them together with other metadata about that page.
I also grab the AST subtree containing a "meaningful" nearest paragraph containing the link.</p>
<p>When rendering the final pages, which happens after the input directory has been fully scanned, I can find items which mention the page that's currently being processed, by looking for a match between what that other page links to, and what is the current <code>slug</code>.</p>
<p>Because I also keep the "meaningful" paragraph, I can generate the <a href="https://developer.mozilla.org/en-US/docs/Web/Text_fragments">Text Fragments</a> built into modern browsers, and highlight the backlinked sections!
To try it out, <a href="https://szymonkaliski.com/notes/computational-dags/#backlinks">go here</a>, and click on, for example, the "Protoboard" backlink — you'll end up in the middle of that article, with a relevant paragraph highlighted.</p>
<h2>Transclusions</h2>
<p>I often publish smaller demos as a part of my newsletter, and they don't end up on the <a href="https://szymonkaliski.com/projects/">projects</a> page, which feels like where you'd look for, well, projects.</p>
<p>I could <em>just</em> copy-paste the relevant text between these two places, but that would be too simple — instead I've implemented a way to transclude markdown sections using custom markdown directives.</p>
<p>To do this, I use <a href="https://github.com/remarkjs/remark-directive"><code>remark-directive</code></a> to parse custom <code>:::transclusion{slug, header}</code> directive: <code>slug</code> points to the page from which to transclude from, and <code>header</code> to the header of the section to copy over.</p>
<p>When I find that directive in the markdown that I'm parsing, I have to transplant a subtree of the other page's markdown AST, so I have to already have it in memory.
Hence the website generation is done in three passes:</p>
<ol>
<li>Initial scan of the input directory, and reading all the items into memory, including initial markdown parsing, but <em>not</em> replacing the transclusions yet.</li>
<li>Process the transclusions, and grab all the links from markdown files for backlinking. I do this after transcluding, so the links from that material are also included.</li>
<li>Iterate over all the items again, this time generating the final output files.</li>
</ol>
<p>For a demo of transclusions, check out the <a href="https://szymonkaliski.com/projects/liunon/">Liunon</a> project.</p>
<h2>Time-Tracking</h2>
<p>The previous version of this website had a separate page with some public-facing stats, just for fun:</p>
<img src="https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/stats.png" alt="Old time-tracking page screenshot" width="3408" height="3022">
<p>This page was using the data from my <a href="https://szymonkaliski.com/writing/2017-04-30-time-tracking/">time-tracking system</a>, and was implemented in a pretty hacky way — I had a small API server which would collect the Google Calendar events, and post-process them for rendering.
The client code would query that server and render the charts — the <code>JSON</code> blob was huge, and the client had to do the work every time the page was opened.</p>
<p>I decided to make the stats a bit less real-time, instead of updating every 10 minutes or so, I'm updating them when the static site generator runs.
With that, I also reworked this section a bit, which you can now see on the <a href="https://szymonkaliski.com/#stats">main page</a>.</p>
<p>It feels really nice to not have to run any client-side JavaScript to generate this.
Since the code runs "on the server" (on my machine when the website is generated), I can simply import parts of my <a href="https://github.com/szymonkaliski/timav-standalone">time-tracking library</a>, and call whatever functions I want, which ultimately synchronously accesses my filesystem, parses some <code>JSON</code>'s, and calculates values for the charts, which get embedded as static <code>&#x3C;svg></code>'s inside the <code>html</code> file.</p>
<h2>Conclusions</h2>
<p>In most cases it's probably better to grab something off-the-shelf, or even just write HTML manually, and move on with your life.
I'm not sure if this was the uncommon case, but at least I can check another one of the nerdy "achievements" off my list.</p>
<p>The project took more time than I would have liked, mainly because I had to deal with a lot of idiosyncrasies around migrating from the previous system, and at the same time, I was fixing various styling issues that I accumulated over the years, and adding a couple of features.
Did I have to do it all at once?
Probably not, but here we are.</p>
<p>Overall, I'm quite happy with this setup, and I also hope I won't have to do this again.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/</guid>
            <pubDate>Mon, 01 Jul 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q2 2024]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>The only thing I can report on this quarter is that I went down one of the most common <em>computer-person-with-a-website</em> rabbit holes imaginable: I wrote my own static site generator.
At least, I didn't do it to procrastinate actually writing something, but to keep this site in a healthy state.</p>
<p>This website is now just plain HTML &#x26; CSS, just how <a href="https://www.w3.org/People/Berners-Lee/">Tim</a> intended.
It is generated from ~2000 lines of bespoke Typescript code.
<a href="https://szymonkaliski.com/writing/2024-07-01-building-a-static-site-generator/">I documented the details in a little write-up</a> — there are some fun things in there: custom markdown directives, backlinking with highlighted text fragments, and cross-markdown transclusions.
Enjoy!</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li>I'm continuing to progress slowly on the mathematics thread. I finished <a href="https://www.amazon.com/Concepts-Modern-Mathematics-Dover-Books/dp/0486284247">Concepts of Modern Mathematics</a> which I really enjoyed, and I went through <a href="https://www.amazon.com/Math-Missed-Need-Graduate-School-dp-1009009192/dp/1009009192/">All the Math You Missed</a> (well, mostly just skimmed); I think I want to learn a bit more about category theory, so I ordered the classic <a href="https://www.cambridge.org/highereducation/books/conceptual-mathematics/00772F4CC3D4268200C5EC86B39D415A#overview">Conceptual Mathematics</a>.</li>
<li>I also read <a href="https://www.amazon.com/Uncontrolled-Surprising-Trial-Error-Business/dp/046502324X">Uncontrolled</a>, and I mostly enjoyed the first, more philosophical part.</li>
<li>I've been also making my way through <a href="https://www.amazon.com/Innovators-Dilemma-Technologies-Management-Innovation-dp-1633691780/dp/1633691780/">The Innovator's Dilemma</a>, <a href="https://www.amazon.com/Origin-Wealth-Remaking-Economics-Business/dp/1422121038">The Origin of Wealth</a>, and <a href="https://www.amazon.com/How-Be-Idle-Loafers-Manifesto/dp/0060779691">How to Be Idle</a> (<a href="https://www.amazon.com/How-Do-Nothing-Resisting-Attention/dp/1612197493">How to do Nothing</a> resonated more with me though).</li>
</ul>
<p>On the web:</p>
<ul>
<li>Apple held another WWDC and demoed <a href="https://www.apple.com/newsroom/2024/06/ipados-18-introduces-powerful-intelligence-features-and-apps-for-apple-pencil/#:~:text=Calculator%20on%20iPad%20Delivers%20a%20New%20Way%20to%20Solve%20with%20Math%20Notes">Math Notes</a>, which seem at least a bit related to the <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> research at Ink&#x26;Switch, though I think the similarity is fairly superficial — both do have some form of <em>programming</em> and <em>drawing</em> on the same canvas, but in Apple's universe that's all that it is: changing the numbers doesn't impact the drawing, or the other way around. They are as disconnected as having a <a href="https://www.inkandswitch.com/crosscut/#non-inspirations:~:text=Second%2C%20most%20live,by%20Bret%20Victor.">code editor on one side of the screen, and a scanned drawing on the other</a>. I'm also not a fan of a machine trying to imitate your own handwriting, <a href="https://www.inkandswitch.com/untangle/#responses-from-the-computer-are-under-designed">I think it should have its own <em>voice</em></a>.
<ul>
<li>On that topic, <a href="https://www.todepond.com">Lu</a> has been exploring a lot of related ideas at <a href="https://www.tldraw.com">tldraw</a>: <a href="https://x.com/tldraw/status/1801212867061879175">1</a>, <a href="https://x.com/tldraw/status/1800904479451250825">2</a>, <a href="https://x.com/tldraw/status/1800532827672637943">3</a>, etc. All worth having a look (and following!) if you haven't see it yet.</li>
</ul>
</li>
<li><a href="https://x.com/lt0gt/status/1799091596845011046">I'm not sure what this is, but it sure has nice UI</a></li>
<li>You don't know this yet, but you do need this 1h23m YouTube video of someone <a href="https://www.youtube.com/watch?v=AHUUXfB0qHY">overengineering a  DIY oscillating belt sander</a> in your life</li>
<li><a href="https://tree-diffusion.github.io">Diffusion On Syntax Trees For Program Synthesis</a></li>
<li>Tyler is <a href="https://x.com/tylerangert/status/1799308756586836106">iterating on Spellburst</a></li>
<li><a href="https://mattferraro.dev/posts/cadmium">CADmium: A Local-First CAD Program Built for the Browser</a></li>
<li><a href="https://github.com/jmpinit/projected-toolpath-preview">Toolpaths projected on top of CNCs</a></li>
<li><a href="https://github.com/RobertBaruch/lode_runner_reveng#:~:text=main.pdf%20is%20the%20literate%20programming%20document%20for%20this%20project.%20This%20means%20the%20explanatory%20text%20is%20interspersed%20with%20source%20code.%20The%20source%20code%20can%20be%20extracted%20from%20the%20document%20and%20compiled.">"Lode Runner" was written in a ... pdf</a></li>
</ul>
<h2>Fin</h2>
<p>Summer has finally begun, which means that once again, I'm optimizing for swimming in the nearby outdoor pools as often as possible.
Life is also keeping me busy, so I make no promises about any new side-projects for the next issue, but I do have a couple of things in the back of my mind.</p>
<p>In the meantime, if you find any issues with the new website, do let me know!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2024-07-01-q2-2024/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2024-07-01-q2-2024/</guid>
            <pubDate>Mon, 01 Jul 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Advanced Port Configuration at Replit ↗]]></title>
            <description><![CDATA[Advanced Port Configuration at Replit]]></description>
            <link>https://blog.replit.com/ports</link>
            <guid isPermaLink="true">https://blog.replit.com/ports</guid>
            <pubDate>Thu, 04 Apr 2024 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q1 2024]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>A lot has happened this quarter; actually, seems like a lot is happening every quarter.
Maybe three months is just a long time?</p>
<p>This time I write about <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#moving-to-the-basement">moving my studio to the basement</a>, <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#smart-home-setup">our "smart" home setup</a>, and give you <a href="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/#setting-up-nix-on-macos">a short experience report from setting up Nix on macOS</a>.</p>
<h2>Moving To The Basement</h2>
<p>Ever since properly joining the workforce, I've been always working from home, which I acknowledge is a privilege, but not without its downsides.
I've heard multiple people struggling with "the couch is right there", but I had the opposite problem: "the work is right there", and there's always something more to do.
It was always hard to finish my workday, and the timezone shift to the west coast doesn't really help either (all my coworkers are only just starting their day).
Also, home can be distracting sometimes.</p>
<p>For a long while, I dreamed of having my own separate space, one that I can lock up and leave at the end of the day, one that's quiet when I need it, one where I can be noisy when I want to, and one where I can be messy — where I don't have to worry about dropping a screwdriver on the floor, or having to immediately clean up when I drill into an aluminum extrusion.</p>
<p>At the beginning of March, this dream came through.
The building we live in had a small doctor's office, which has been unoccupied for a good couple of years now.
We managed to rent it, and spent the last year renovating: first demolition and clearing up everything we could, and then light polishing pass — new floor, new bathroom — and finally two weekends of running up and down the stairs to move from here:</p>
<img src="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/studio-old.png" alt="Old Studio" width="1600" height="900">
<p>To here:</p>
<img src="https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/studio-new.png" alt="New Studio" width="1600" height="900">
<p>It's only been a month since I've moved, so definitely not enough time for any sort of long-term reflection, but I definitely feel a clearer separation between when I'm "at work" and when I'm not, which is great.</p>
<h2>Smart Home Setup</h2>
<p>Moving to the basement is a good segue into talking a bit about the minimally-smart home setup we have, as the move allowed me to add some fun automations.</p>
<p>My general philosophy here is that the IoT stuff should have no access to the outside world (internet blocked on the router), and that the automations, if any, should be as straight-forward as possible.</p>
<p>The setup consists of:</p>
<ul>
<li>Raspberry Pi (not even one of the new ones) with a <a href="https://www.zigbee2mqtt.io/guide/adapters/">Zigbee adapter</a> for one IKEA led strip that we use for ambient light behind our TV.</li>
<li>DIY <a href="https://www.seeedstudio.com/24GHz-mmWave-Radar-Sensor-Human-Static-Presence-Module-p-5267.html">mmWave</a> presence sensor wired to Raspberry Pi GPIO, also for our living room. These sensors are better than PIR (though more expensive) since they can reliably tell you if someone is there or not, instead of just letting you know when there's movement detected.</li>
<li>A bunch of Wi-Fi sockets flashed with <a href="https://tasmota.github.io/docs/">Tasmota</a>, and with blocked internet access.</li>
<li>A couple of <a href="https://reolink.com">Reolink</a> cameras, dynamically blocked from the internet (more on that below).</li>
<li>DIY BLE beacon detector for the studio made with ESP32 board.</li>
<li><a href="https://github.com/szymonkaliski/lgtv2mqtt2"><code>lgtv2mqtt2</code></a> for control of our TV (which also has blocked access to the internet, but is connected to a local network).</li>
</ul>
<p>Everything is wired with <a href="https://nodered.org">Node-RED</a>, and the state is kept in MQTT, so even if I restart the Node-RED process, the current state stays alive, and I can monitor and access it in multiple ways.
We also have a very basic <a href="https://flows.nodered.org/node/node-red-dashboard">Node-RED Dashboard</a> so we can toggle stuff manually when we're at home (and I can do so while I'm away too, thanks to the magic of <a href="http://tailscale.com">Tailscale</a>; I wasn't so cruel as to force my wife to deal with this though).</p>
<p>The only automations we have set up at home are turning the LED on at dusk if anyone is present in the living room, and turning it off at specified time at night.</p>
<p>The studio automations are bit more fun, since I'm the only one having to deal with them if they misbehave:</p>
<ul>
<li>I have an ESP32 monitoring for a presence of a specific BLE beacon attached to my keychain, so the system knows if I'm in the studio or not. Based on that, the camera and a dehumidifier turn on or off (in anti-phase to my presence, the dehumidifier is noisy).
The ESP32 code is very simple: every 30 seconds it starts a scan looking for that beacon, and once it makes double-sure it's there or not (there are some false negatives), it updates the MQTT state over Wi-Fi, and Node-RED automations take over.
Let me know if you have any other ideas for reliable presence tracking.
I was thinking about using RFID, but seems too finicky to have to place my keys exactly in the right spot every time, and even more finicky to figure out how to detect them in a long-range (which is possible with UHF RFID, and they can even be <a href="https://backoffice.biblio.ugent.be/download/8647440/8651107">positioned in space with additional trickery</a>).</li>
<li>When I turn on my speakers, my audio interface also turns on — but not the other way around (I might want to work in headphones). This is mainly because the speaker switches are not easy to reach.</li>
<li>I also have a script on my laptop that starts my music production / music listening software of choice, and makes sure the speakers and audio interface are on.</li>
</ul>
<p>Going back to our home, the cameras we have in our living room have access to the internet only if we flip a switch in the Node-RED dashboard.
We basically "turn them on" only when we know we'll leave our dog inside for a while, or if we're going on holidays.
It would be great to automate this, but I can't come up with a way that wouldn't be annoying to my wife, so here we are, flipping virtual switches like cavemen.</p>
<p>This is all done just for additional peace-of-mind, we have a proper alarm that has nothing to do with this system (so I don't break it when I'm messing around with things).</p>
<p>The internet access is blocked on a router, by SSH-ing into it from Node-RED, executing some <code>nvram</code> commands, and restarting the firewall service, it's terrible, but it works (SSH is enabled, of course, for LAN access only).
For those of you who are very curious, we have ASUS RT-AX86U (actually two of them, one in our apartment, and one in the studio, hard-wired with an ethernet cable), and the relevant commands are:</p>
<pre><code class="language-bash">nvram set MULTIFILTER_MAC="MAC_1>MAC_2>..." # yes, ">" is the separator
nvram set MULTIFILTER_ENABLE="2>2>..."      # yes, "2" means "blocked"
nvram commit
rc rc_service restart_firewall
</code></pre>
<p>I got these keys by running <code>nvram show</code>, changing some options in the UI, running it again, and diffing the output.</p>
<p>The important part is that everything still works even if our internet connection is not working, and even if the local network drops, the only thing we lose is being able to control the IKEA led, everything else is done through Wi-Fi sockets, which have physical buttons on them (though sometimes hard to reach).</p>
<h2>Setting up Nix on macOS</h2>
<p>Continuing with the nerdiness, working at <a href="https://replit.com">Replit</a> was a forcing function for taking a closer look at <a href="http://nixos.org">Nix</a> (since the Repls, and our repos, both use it for package management), which, turns out, is actually pretty nice.</p>
<p>I got double-encouraged by <a href="https://brew.sh">Homebrew</a> breaking some Python stuff (again), and one weekend I sat down and migrated to Nix on macOS which was surprisingly painless:</p>
<ul>
<li>I started by installing Nix using <a href="https://github.com/DeterminateSystems/nix-installer">The Determinate Nix Installer</a>, which has some nice properties over the stock one (like being able to easily uninstall it if I want to).</li>
<li>Then, I roughly followed <a href="https://juliu.is/tidying-your-home-with-nix/">this tutorial</a>, stopping at <code>home-manager</code> managing my dotfiles — I might get around to adding this at some point, but I just didn't want to change too much at once.</li>
</ul>
<p>The "developer experience" of <code>direnv</code> combined with Nix flakes is great: you just <code>cd</code> into the project, and all of the necessary dependencies are not only auto-installed, but also persisted in a fully reproducible way (well, provided you wrote the <code>flake.nix</code> for them, which really <a href="https://github.com/replit/ruspty/blob/main/flake.nix">doesn't have to be that complicated</a>).</p>
<p>I can now have different pinned Python versions for different projects, which solves my original issue.
I also got rid of <code>nvm</code> since I can get specific Node versions from Nix too, and it just feels nice to have all of that taken care of by a single system.</p>
<p>If you're curious about my pretty straight-forward configuration, you can browse through <a href="https://github.com/szymonkaliski/home-configuration/tree/main/dotfiles/home-manager">my dotfiles repository</a>.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li>I've been slowly continuing my mathematics thread, first going through half of <a href="https://www.amazon.com/Mathematics-Nonmathematician-Morris-Kline/dp/0486248232">Mathematics for the Nonmathematician</a> which just wasn't picking up enough speed for what I was looking for, so I switched to <a href="https://www.amazon.com/Concepts-Modern-Mathematics-Dover-Books/dp/0486284247">Concepts of Modern Mathematics</a>, which has been great so far!</li>
<li>I also made it a personal mission to finish all the remaining books I had with the phrase "The Mind" in the title: <a href="https://www.amazon.com/Frames-Mind-Theory-Multiple-Intelligences/dp/0465024335">Frames of Mind</a> (a classic on "multiple intelligences"), <a href="https://www.amazon.com/Models-Mind-Engineering-Mathematics-Understanding/dp/1472966422">Models of the Mind</a> (which was a bit too "pop-science-y" for my taste, but could be a good resource to pull some threads from), and <a href="https://www.amazon.com/Infinity-Mind-Philosophy-Infinite-Princeton/dp/0691121273">Infinity and The Mind</a>, which, as the title suggests, takes a look at the concept of infinity from a ton of different points of view.</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://www.palladiummag.com/2023/06/06/school-is-not-enough/">School Is Not Enough</a></li>
<li>Ink&#x26;Switch has been publishing regular, shorter write-ups on their work on <a href="https://www.inkandswitch.com/patchwork/notebook/">Patchwork</a>.
For more "productized" approaches to improving version control experience, check out <a href="https://gitbutler.com">GitButler</a>, and <a href="https://notes.billmill.org/blog/2024/03/How_I_use_git_worktrees.html">a nice write-up of how one person uses <code>git</code> worktrees</a>. For more "huh that's interesting", check out <a href="https://github.com/Ableton/maxdevtools/tree/main/maxdiff">how Ableton diffs Max/MSP patches</a>.</li>
<li>More cool concepts for <a href="https://arcan-fe.com/2022/04/02/the-day-of-a-new-command-line-interface-shell/">improving the shell experience</a>.
On that topic I shipped <a href="https://twitter.com/amasad/status/1743405482612777389">inline AI generation for shell commands</a>, and have more shell-related things coming relatively soon, <a href="https://twitter.com/amasad/status/1768734193029161064">like this two-orders-of-magnitude performance improvement</a>.</li>
<li>Francois has been working on bringing tldraw to VS Code, <a href="https://twitter.com/seflless/status/1765052929172549721">which looks pretty cool</a>.</li>
<li>In-depth guide to <a href="https://jacquesmattheij.com/cnc-lasers/">CNC Lasers</a>.</li>
<li><a href="https://gerotakke.de/ottopot/">Another cute DIY MIDI controller</a>, this one with endless knobs and LED rings.</li>
<li>There's recently been a bunch of chatting around what a "design engineer" is/does on Twitter (<a href="https://twitter.com/ryanlucas/status/1757831644520853613">1</a>, <a href="https://twitter.com/davidhoang/status/1766157173774782858">2</a>, etc.), and I somehow even ended up on a <a href="http://maggieappleton.com/design-engineers">list made by Maggie</a>, which felt nice. Thank you, Maggie!
I have some thoughts about this, but not that many — on some level, I feel like all the "is <code>X</code>(hamburger / Pluto / ...) a <code>Y</code>(sandwich / planet / ...)?" sorts of questions are exercises in trying to find a <em>single all-encompassing ontology</em> to fit everything, and <a href="https://metarationality.com/remodeling#:~:text=There%20is%20no%20correct,is%20%E2%80%9Creally%E2%80%9D%20a%20planet.">I'm not alone in believing that there isn't one</a>.
Additionally, the only time when defining what I do mattered, was when I was <a href="https://szymonkaliski.com/newsletter/2023-04-03-q1-2023/#musings-from-the-job-hunt">looking for a new job last year</a>, and even then, it was more of a <em>negotiation</em> with whomever was on the other side, trying to build a definition that was useful in that specific context.
At Replit (and before that too), I just do what I believe is important, and it doesn't matter much to me if that means writing a proposal, recording a video, designing something in Figma, or implementing it on the "frontend" or "backend" (oftentimes it's <em>all of these</em>).</li>
</ul>
<h2>Fin</h2>
<p>As always, let me know if you have any thoughts about anything.
You can reply to this email directly, or reach out to <a href="mailto:hi@szymonkaliski.com">hi@szymonkaliski.com</a></p>
<p>And in the meantime, have a great spring, and see you in three months!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2024-04-01-q1-2024/</guid>
            <pubDate>Mon, 01 Apr 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q4 2023]]></title>
            <description><![CDATA[<p>Hi, happy New Year!</p>
<p><a href="http://tinyletter.com">Tinyletter</a> had an "<a href="https://ourincrediblejourney.tumblr.com">incredible journey</a>" moment recently, so if you're <a href="https://buttondown.email/szymonkaliski">subscribed</a>, you're receiving this through <a href="https://buttondown.email">Buttondown</a> — more expensive than the free Tinyletter was, which hopefully is a good thing for not having to migrate any time soon again.
If you relied on the archive, you can always read the <a href="https://szymonkaliski.com/#newsletter">past editions on my website</a>.</p>
<p>I spent the last quarter working on improving <a href="http://replit.com/">Replit</a>'s Console, and noodling on a toy database-y creative coding environment, more below!</p>
<h2>Improving Replit's Console</h2>
<p>I redesigned and rebuilt Replit's Console (almost) from scratch.
A single terminal view was replaced with a <a href="https://blog.replit.com/new-and-improved-console#:~:text=Our%20internal%20scrollback,virtualized%20scrolling%3A"><em>virtually scrolling</em></a> list of terminals, where each execution happens in its own context, is reliably cleaned up, even if the process misbehaves (thanks to <a href="https://docs.kernel.org/admin-guide/cgroup-v2.html">the magic of <code>cgroups</code></a>), and which is already starting to <a href="https://blog.replit.com/new-and-improved-console#:~:text=We%20are%20already%20exploring%20running%20multiple%20blocks%20at%20the%20same%20time">integrate more elements of the IDE into this single pane</a>.</p>
<p>Check out <a href="https://blog.replit.com/new-and-improved-console">this blog post</a> for the reasoning behind the project, and various implementation details.</p>
<p>Throughout this work, two things were often on my mind:</p>
<ul>
<li>One, how the line between <em>frontend</em> and <em>backend</em> doesn't really make sense, and how the only line that matters is between <em>the user</em> and <em>the machine</em>. A lot of "UI" and "UX" in this project stem from <a href="https://blog.replit.com/new-and-improved-console#:~:text=a%20running%20state.-,Reliable%20stopping,-We%20believe%20that">deep <em>backend</em> work</a>, and wouldn't be possible to achieve by only redesigning the <em>frontend</em> bits.</li>
<li>Two, how so many details are important to get right (and how often a <em>detail</em> actually ends up being a big engineering effort) for the tool to "disappear in your hand". For example, the behavior of blocks growing with their content up to the point where they take over the whole pane, and the gesture of scrolling up "just works" where in reality, the logic is pretty complex — which reminds me a bit of <a href="https://slack.engineering/reducing-slacks-memory-footprint/#:~:text=Workflow%20diagram%20encompassing%20all%20the%20considerations%20that%20go%20into%20whether%20to%20notify%20a%20user%20about%20a%C2%A0message.">the infamous "how Slack decides to send you a notification" diagram</a>.</li>
</ul>
<h2>Database-y Creative Coding Environment</h2>
<p>Outside of work, I've been noodling on a new creative coding environment, in which you generate images by querying the existing state, and asserting a new one, in a sort of <a href="https://en.wikipedia.org/wiki/Database_transaction">transactional</a> way, with the hope that each of these transactions will also have a meaningful representation, so <a href="https://szymonkaliski.com/notes/solving-things-visually/"><em>seeing</em></a> the intermediate steps requires no additional work, it <a href="https://www.aip.org/history-programs/niels-bohr-library/oral-histories/5020-5#:~:text=You%20have%20to%20work%20on%20paper%20and%20this%20is%20the%20paper"><em>is the work</em></a>.</p>
<p>Let's see how we could create something resembling the <a href="https://medium.com/@jason.webb/space-colonization-algorithm-in-javascript-6f683b743dc5">Space Colonization</a> algorithm in the tool.</p>
<p>First, we assert that there's a page to draw on, place a bunch of attractors, and a single node in the middle:</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-1.png" alt="Step 1" width="2536" height="830">
<p>Second, we give each of the nodes two "zones" — one which "growth" is directed by, and another, smaller one, where the attractors are "consumed".
So far so good:</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-2.png" alt="Step 2" width="2536" height="830">
<p>Third, we have to grow towards the attractors by creating new nodes, and consume them if they are in the consumption zones:</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-3.png" alt="Step 3" width="2536" height="830">
<p>This big step does a lot, all at once, which doesn't really help much with understanding what's going on.
There's iteration, there's a lot of state, and a lot of <a href="https://szymonkaliski.com/notes/simulator/">playing computer in your head</a>.</p>
<p>To make it worse, we also loop this step 20 times, to let the structure grow out a bit (with a simple number picker out of the frame), and you can only see the last step of that process.</p>
<p>Finally, we can drop all the circles, leaving just the lines...</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-4.png" alt="Step 4" width="2536" height="830">
<p>...which we can export, convert to <a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#g-code">G-code</a> and plot on the <a href="https://szymonkaliski.com/projects/diy-pen-plotter/">DIY Pen Plotter</a>, which was my plan all along:</p>
<div class="measure-wide">
  <img src="https://szymonkaliski.com/liunon-pen-plotted.png" width="1200" height="1200">
</div>
<p>Let's go back to the middle step — as you probably realize, it is the one that I'm pretty unhappy with.
It feels as if I've been struggling with some version of this problem for a while now — representing and visualizing single values is not that hard, but as soon as collections come into play, the simple solutions fall apart.</p>
<p>We hit this earlier on in <a href="https://www.inkandswitch.com/inkbase/">Inkbase</a> where interacting with a single item was nicely visualized with inspector panes, but groups of objects were not.
We tried to explicitly solve this in <a href="https://www.inkandswitch.com/crosscut/#repetition-of-things-in-space">Crosscut</a>, but the solutions were far from ideal.
I also hit this in my <a href="https://www.glideapps.com/research/code-components#how-to-work-with-collections-in-user-space">research at Glide</a> where displaying lists of values is the main thing you do.</p>
<p>So far, I've seen two interesting approaches to solving this:</p>
<ul>
<li>The <code>spread</code> operator in <a href="http://aprt.us">Apparatus</a>, which is well illustrated by the <a href="http://aprt.us/editor/?load=doc/examples/Bar%20Chart.json">Bar Chart example</a> — notice how the <code>X</code> property spreads between <code>0</code> and <code>10</code>. It is a single property, but represents a collection, and each of the other operations "just work" (you can <code>sin(X)</code> and get back a spread of values — I've heard that this is pretty much a "List Monad").</li>
<li><a href="https://engraft.dev">Engraft</a> by <a href="https://joshuahhh.com">Josh</a> (and earlier <a href="https://joshuahhh.com/projects/pane/">Pane</a>) both have <code>map</code> behavior as part of the core interaction, with each step being visible and represented on the screen. Engraft is especially promising — an attempt at building an <em>environment</em> where various live, visual, domain-specific tools can coexist and communicate with each other.</li>
</ul>
<p>One more random thought — the idea of "<a href="https://www.hytradboi.com">rubbing a database</a>" on a creative coding library could be an interesting tangent to explore on its own.
For example, imagine having <em>computed facts</em> that could be queried too, like intersections, nearness, etc. — which feels similar to how Realtalk works (a database-OS powering <a href="http://dynamicland.org">Dynamicland</a>).</p>
<p><a href="https://inconvergent.net">Anders Hoff a.k.a. Inconvergent</a> has also been exploring <a href="https://inconvergent.net/2022/graph-data-structure-with-datalog-ql/">home-grown Datalog for making computer art</a>, which is worth checking out (both for the computing, and the art).</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li>I circled back to some readings on <a href="https://szymonkaliski.com/notes/embodied-cognition/">Embodied Cognition</a> (all great!):
<ul>
<li><a href="https://mitpress.mit.edu/9780262531566/being-there/">Being There</a></li>
<li><a href="https://www.amazon.com/Supersizing-Mind-Embodiment-Cognitive-Philosophy/dp/0199773688">Supersizing the Mind</a></li>
<li><a href="https://mitpress.mit.edu/9780262581462/cognition-in-the-wild/">Cognition in the Wild</a></li>
</ul>
</li>
<li>I started a thread on properly (re-)learning mathematics with <a href="https://pimbook.org">A Programmer's Introduction to Mathematics</a> — I felt for a long time that I might not have paid enough attention in school to some important connections, and while I do know some things here and there, I don't have a proper "structure" on which to hang them; I accept that this will be a longer learning project, and so far it actually feels quite nice to be going through proofs and exercises.</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://twitter.com/RustyVermeer/status/1729388459561980216">A cool live multimedia spreadsheet for programming</a></li>
<li><a href="https://www.dataisnature.com/?p=2041">Origami crease patterns</a></li>
<li><a href="http://apm.bplaced.net/w/index.php?title=Annotated_lambda_diagram">Annotated lambda diagrams</a></li>
<li><a href="https://elliot.website">Elliot</a> is <a href="https://twitter.com/elliotokay/status/1707853328393097435">at it again</a></li>
<li><a href="https://designsystems.international/ideas/the-gulf-between-design-and-engineering/">The Gulf Between Design And Engineering</a></li>
<li><a href="https://youtu.be/P5fWPBOdrY8">a bunch of great UI ideas in this new DAW</a> — especially around <em>spatial queries</em>, and the mechanics that allow one to <a href="https://szymonkaliski.com/notes/second-order-tool-building/">derive</a> a delay effect from interactions between <code>send</code> and <code>return</code> blocks</li>
<li><a href="https://blog.replit.com/spellburst">a really nice write-up on Spellburst and UIST 2023</a></li>
</ul>
<h2>Fin</h2>
<p>Let me know if you have any thoughts about making loops <a href="https://arxiv.org/abs/2303.06777">Live, Rich, and Composable</a>, or about the intersection of databases and creative coding.</p>
<p>Best wishes for 2024!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/</guid>
            <pubDate>Mon, 01 Jan 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[New and Improved Console at Replit ↗]]></title>
            <description><![CDATA[New and Improved Console at Replit]]></description>
            <link>https://blog.replit.com/new-and-improved-console</link>
            <guid isPermaLink="true">https://blog.replit.com/new-and-improved-console</guid>
            <pubDate>Wed, 06 Dec 2023 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Liunon]]></title>
            <description><![CDATA[<p>Liunon was first documented in my <a href="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/">Q4 2023</a> newsletter — an experiment in building a tool where seeing every step of the graphical thinking does not require additional effort, but is a part of how the tool works.</p>

<h2 is-transclusion-title="" class="f5 lh-copy mt5 mb2 near-black">Transcluded from <a href="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/#database-y-creative-coding-environment">Database-y Creative Coding Environment</a></h2>
          
<p>Outside of work, I've been noodling on a new creative coding environment, in which you generate images by querying the existing state, and asserting a new one, in a sort of <a href="https://en.wikipedia.org/wiki/Database_transaction">transactional</a> way, with the hope that each of these transactions will also have a meaningful representation, so <a href="https://szymonkaliski.com/notes/solving-things-visually/"><em>seeing</em></a> the intermediate steps requires no additional work, it <a href="https://www.aip.org/history-programs/niels-bohr-library/oral-histories/5020-5#:~:text=You%20have%20to%20work%20on%20paper%20and%20this%20is%20the%20paper"><em>is the work</em></a>.</p>
<p>Let's see how we could create something resembling the <a href="https://medium.com/@jason.webb/space-colonization-algorithm-in-javascript-6f683b743dc5">Space Colonization</a> algorithm in the tool.</p>
<p>First, we assert that there's a page to draw on, place a bunch of attractors, and a single node in the middle:</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-1.png" alt="Step 1" width="2536" height="830">
<p>Second, we give each of the nodes two "zones" — one which "growth" is directed by, and another, smaller one, where the attractors are "consumed".
So far so good:</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-2.png" alt="Step 2" width="2536" height="830">
<p>Third, we have to grow towards the attractors by creating new nodes, and consume them if they are in the consumption zones:</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-3.png" alt="Step 3" width="2536" height="830">
<p>This big step does a lot, all at once, which doesn't really help much with understanding what's going on.
There's iteration, there's a lot of state, and a lot of <a href="https://szymonkaliski.com/notes/simulator/">playing computer in your head</a>.</p>
<p>To make it worse, we also loop this step 20 times, to let the structure grow out a bit (with a simple number picker out of the frame), and you can only see the last step of that process.</p>
<p>Finally, we can drop all the circles, leaving just the lines...</p>
<img src="https://szymonkaliski.com/newsletter/2024-01-01-q4-2023/step-4.png" alt="Step 4" width="2536" height="830">
<p>...which we can export, convert to <a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#g-code">G-code</a> and plot on the <a href="https://szymonkaliski.com/projects/diy-pen-plotter/">DIY Pen Plotter</a>, which was my plan all along:</p>
<div class="measure-wide">
  <img src="https://szymonkaliski.com/liunon-pen-plotted.png" width="1200" height="1200">
</div>
<p>Let's go back to the middle step — as you probably realize, it is the one that I'm pretty unhappy with.
It feels as if I've been struggling with some version of this problem for a while now — representing and visualizing single values is not that hard, but as soon as collections come into play, the simple solutions fall apart.</p>
<p>We hit this earlier on in <a href="https://www.inkandswitch.com/inkbase/">Inkbase</a> where interacting with a single item was nicely visualized with inspector panes, but groups of objects were not.
We tried to explicitly solve this in <a href="https://www.inkandswitch.com/crosscut/#repetition-of-things-in-space">Crosscut</a>, but the solutions were far from ideal.
I also hit this in my <a href="https://www.glideapps.com/research/code-components#how-to-work-with-collections-in-user-space">research at Glide</a> where displaying lists of values is the main thing you do.</p>
<p>So far, I've seen two interesting approaches to solving this:</p>
<ul>
<li>The <code>spread</code> operator in <a href="http://aprt.us">Apparatus</a>, which is well illustrated by the <a href="http://aprt.us/editor/?load=doc/examples/Bar%20Chart.json">Bar Chart example</a> — notice how the <code>X</code> property spreads between <code>0</code> and <code>10</code>. It is a single property, but represents a collection, and each of the other operations "just work" (you can <code>sin(X)</code> and get back a spread of values — I've heard that this is pretty much a "List Monad").</li>
<li><a href="https://engraft.dev">Engraft</a> by <a href="https://joshuahhh.com">Josh</a> (and earlier <a href="https://joshuahhh.com/projects/pane/">Pane</a>) both have <code>map</code> behavior as part of the core interaction, with each step being visible and represented on the screen. Engraft is especially promising — an attempt at building an <em>environment</em> where various live, visual, domain-specific tools can coexist and communicate with each other.</li>
</ul>
<p>One more random thought — the idea of "<a href="https://www.hytradboi.com">rubbing a database</a>" on a creative coding library could be an interesting tangent to explore on its own.
For example, imagine having <em>computed facts</em> that could be queried too, like intersections, nearness, etc. — which feels similar to how Realtalk works (a database-OS powering <a href="http://dynamicland.org">Dynamicland</a>).</p>
<p><a href="https://inconvergent.net">Anders Hoff a.k.a. Inconvergent</a> has also been exploring <a href="https://inconvergent.net/2022/graph-data-structure-with-datalog-ql/">home-grown Datalog for making computer art</a>, which is worth checking out (both for the computing, and the art).</p>]]></description>
            <link>https://szymonkaliski.com/projects/liunon/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/liunon/</guid>
            <pubDate>Sun, 03 Dec 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building a DIY Pen Plotter]]></title>
            <description><![CDATA[<p>This article documents my learnings from designing and building a <a href="https://szymonkaliski.com/projects/diy-pen-plotter/">DIY Pen Plotter</a> during the summer of 2023.
My ultimate goal is to build my own CNC machine, and a pen-plotter seemed like a good stepping stone towards this project — this is an important context for how I designed this machine, as if I only wanted a pen-plotter, a lot of things could be simplified.</p>
<img src="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/design.png" alt="Fusion 360 design" width="1920" height="1080">
<p>My hope is that this collection of notes will be useful to you if you ever embark on a similar project:</p>
<ul>
<li><a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#designing">Designing</a></li>
<li><a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#materials">Materials</a></li>
<li><a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#electronics">Electronics</a></li>
<li><a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#grbl"><code>GRBL</code></a></li>
<li><a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/#g-code"><code>G-Code</code></a></li>
</ul>
<h2>Designing</h2>
<p>Up to this point, all my designs for 3D-printed objects were either made in code (using my own tools, of course: <a href="https://szymonkaliski.com/projects/modeler/">Modeler</a> and <a href="https://szymonkaliski.com/projects/hiccup-sdf/">hiccup-sdf</a>) or using <a href="https://solvespace.com/index.pl">SolveSpace</a>.</p>
<p>The code-based approach is great for parametric designs or art projects (like <a href="https://szymonkaliski.com/projects/fabfungus/">FabFungus</a>), while SolveSpace is awesome for quick sketches.
In this project I had to figure out how to combine multiple parts together, and there was just no way around trying a serious tool — I went with <a href="https://www.autodesk.com/products/fusion-360/">Fusion 360</a> just because I had heard about it previously.</p>
<p>You can easily find a ton of "get started with" tutorials for Fusion 360 on YouTube — I can't point to one that was the most helpful.
I just watched a couple of them and started playing around with the tool (which is free for personal use).</p>
<p>When designing 3D-printed parts to connect real-life objects, you'll want to reference these objects in CAD.
You can model them yourself, but usually it's possible to find them in the <a href="https://grabcad.com/library">GrabCAD Library</a>.
For Fusion 360 you want <code>.stp</code> files, which you can add to your project.
<a href="https://www.autodesk.com/products/fusion-360/blog/import-step-file-into-fusion-360/">Here's a tutorial from Autodesk</a>.</p>
<p>3D-printed objects tend to shrink after they are printed.
Nothing in reality fits as perfectly as what you design in CAD.
If you make an exact 20mm by 20mm hole for an aluminum profile, there's a big chance that it just won't fit after the print.
What I did, was print a couple of draft versions of the part with various sizing adjustments to test what fits exactly right, and then used that throughout the design.
For example, in my setup, this meant printing 3.2mm instead of 3mm holes for M3 screws, 8.4mm instead of 8mm for the rotating trapezoidal screw, etc.</p>
<p>For Fusion 360 itself, I recommend adjusting two settings:</p>
<ul>
<li><a href="https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/How-to-improve-trackpad-modelling-for-Fusion-360.html">Turning on native trackpad support</a> for a better trackpad experience.</li>
<li><a href="https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/How-to-optimize-settings-in-Fusion-360-for-performance.html#:~:text=Disable%C2%A0all%20the%20effects%20in%20the%20Display%20Settings">Disabling graphic effects</a> for much better performance.</li>
</ul>
<p>As for the design itself, I wouldn't recommend going for wheels for the Y-axis, as you can see in the picture above.
It's very hard to get the tolerances just right, and my Z-axis is very wobbly.
This is fine for a pen-plotter, but a no-go for CNC.
I'm planning on redesigning this to use two linear rods with linear bearings, which should create a much more rigid structure than the one I have for the Z-axis.</p>
<h2>Materials</h2>
<p>The way most DIY 3D-printers, pen-plotters, and CNC's are built is by combining widely available prefabricates with 3D-printed objects.</p>
<p>I designed the body of my pen-plotter using:</p>
<ul>
<li>20x20mm aluminum extrusions (often called just <code>2020</code>)</li>
<li>10mm linear rods and matching 10mm linear bearings (<code>LM10UU</code>)</li>
<li>8mm ACME lead screws with matching lead screw nuts</li>
<li><code>NEMA17</code>-clones for motors</li>
<li>aluminum couplings for connecting the motors with the lead screws</li>
</ul>
<p>Another option for transforming the motor's rotation into linear motion is by using belts, but I decided that the lead screws would be better for the CNC, as intuitively, it feels like more force can be transferred this way.
Also, I don't have to worry about tightening the belts.</p>
<p>For getting these parts, 3D-printer shops are your best bet.
Motors can get quite expensive, and I just went with the cheapest ones I could find.
The aluminum extrusions, rods and lead screws you can get cut to size (or cut on your own if you have the proper tools), but I managed to just find ones that fit my build (and sometimes I designed around what I could find).</p>
<p>For connecting the extrusions to 3D-printed parts, I used the standard approach of adding T-nuts in the profiles, leaving holes in the design where the T-nut should be, and screwing them together.
If you've ever assembled a 3D-printer, you know what I'm talking about, if not, just search YouTube for T-nuts, I guess.</p>
<div class="measure-wide">
  <img src="https://szymonkaliski.com/linear-bearing-sandwich.png" width="1600" height="1600">
</div>
<p>The linear bearings are sandwiched between two 3D-printed parts that I screw together.
This was the part of the design that I had to do the most trial-and-error to fit perfectly.</p>
<h2>Electronics</h2>
<p>To move the motors, you'll need a couple of electronic parts.
I went with what seems to be a standard setup:</p>
<ul>
<li>Arduino CNC Shield</li>
<li>four <code>A4988</code> motor drivers</li>
<li>cheap Arduino UNO clone I had in my drawer</li>
<li>a power supply — I had a 3A 12V one in my drawer too, and it seems to do just fine</li>
<li>end-stops — anything that you'll find in your electronic store of choice should be just fine, I went with the cheapest mechanical ones I could find (two per axis, so six in total)</li>
</ul>
<p>You'll want to set up <code>VRef</code> for your motor drivers — again, there are a ton of tutorials about that on YouTube.
This is mainly so the motors don't overheat.</p>
<p>End-stops are a safety feature, so the machine gets a "hard stop" when it physically hits a certain limit (instead of destroying itself).
They can be "normally opened" (NO) or "normally closed" (NC).
I went with "normally closed", as they are safer — if a wire connection breaks for whatever reason, the result will be the same as if the end-stop was triggered.
With "normally opened" ones, we don't get that safety.</p>
<p>Properly wiring two "normally closed" end-stops per axis wasn't immediately obvious to me, especially going through the CNC Shield.
What seems to work is wiring them in sequence, connecting one end to the axis end-stop pin and the other to the ground, like so:</p>
<img src="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/end-stop-diagram.png" alt="End-stop wiring diagram" width="1920" height="1080">
<p>To debug the motors and end-switches wiring with the CNC Shield, it's best to use simple ad-hoc Arduino code instead of going for a full GRBL install, as it introduces another layer of indirection and makes it harder to pinpoint where the issue might be coming from.</p>
<p>Below is the code I used to see if I could move one motor.
To test different motors, adjust the <code>dirPin</code> and <code>stepPin</code> which you can find by looking for the CNC Shield pinout.</p>
<pre><code class="language-arduino">#define dirPin 5
#define stepPin 2
#define enablePin 8

// adjust these based on the motor spec
#define stepsPerRevolution 200
#define microsPulseWidth 250
#define microsBetweenSteps 1000

void setup() {
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, LOW);
}

void stepMotor() {
  digitalWrite(stepPin, HIGH);
  delayMicroseconds(microsPulseWidth);
  digitalWrite(stepPin, LOW);
  delayMicroseconds(microsBetweenSteps);
}

void loop() {
  // rotate clockwise
  digitalWrite(dirPin, HIGH);
  for (int i = 0; i &#x3C; 5 * stepsPerRevolution; i++) {
    stepMotor();
  }

  delay(1000);

  // rotate counterclockwise
  digitalWrite(dirPin, LOW);
  for (int i = 0; i &#x3C; 5 * stepsPerRevolution; i++) {
    stepMotor();
  }

  delay(1000);
}
</code></pre>
<p>And here's what I used to debug the end-stops:</p>
<pre><code class="language-arduino">#define xLimitPin 9
#define yLimitPin 10
#define zLimitPin 11

void setup() {
  Serial.begin(115200);
  pinMode(xLimitPin, INPUT_PULLUP);
  pinMode(yLimitPin, INPUT_PULLUP);
  pinMode(zLimitPin, INPUT_PULLUP);
}

void loop() {
  Serial.print("x = ");
  Serial.print(digitalRead(xLimitPin));
  Serial.print("y = ");
  Serial.print(digitalRead(yLimitPin));
  Serial.print("z = ");
  Serial.println(digitalRead(zLimitPin));

  delay(200);
}
</code></pre>
<h2>GRBL</h2>
<p>Once all the axes move and the end-stops are wired properly, it's time to start controlling the machine with G-code, the standard for 3D-printers and CNC machines.</p>
<p>Luckily, there's an open-source G-code interpreter for Arduino UNO and the CNC Shield called <a href="https://github.com/gnea/grbl"><code>grbl</code></a>.
The installation is pretty straight-forward, and described <a href="https://github.com/gnea/grbl/wiki/Compiling-Grbl">here</a> — you basically add <code>grbl</code> as an Arduino library and then upload the only sketch that it provides: <code>GrblUpload</code>.</p>
<p>There's one adjustment I had to make in <code>config.h</code>, the configuration for the controller — I commented out <code>#define VARIABLE_SPINDLE</code> which conflicts with Z-axis end-stops.</p>
<p>Once <code>grbl</code> is running on the Arduino, the real fun starts — configuring all of its settings.
You can do this directly through the Arduino serial console, but I decided to switch to a GUI, so it's easier to test and control the machine.
I went with <a href="https://cnc.js.org"><code>cncjs</code></a>, after testing a couple of other apps that didn't seem to work correctly for whatever reason.</p>
<p>For the configuration, there's a lengthy documentation on the <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration"><code>grbl</code> wiki</a>; here are the things that I did:</p>
<ul>
<li>calculated steps per mm for the motor movement, as described <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#100-101-and-102--xyz-stepsmm">here</a></li>
<li>adjusted maximum rate for the motor's, as described <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#110-111-and-112--xyz-max-rate-mmmin">here</a></li>
<li><a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#3--direction-port-invert-mask">inverted</a> some of the motors axes to move in a predictable way</li>
<li>enabled end-stops:
<ul>
<li>they had to be <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#5----limit-pins-invert-boolean">inverted</a> since they are "normally closed"</li>
<li>they had to be <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#21---hard-limits-boolean">enabled</a></li>
<li>and with this, the homing cycle (automatic corner finding) can be <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#22---homing-cycle-boolean">enabled</a> too</li>
</ul>
</li>
<li>finally, I homed the machine (using the button in the GUI), and stepped it manually to the other end-stop to figure out the <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#130-131-132--xyz-max-travel-mm">soft limits</a> (which also have to be <a href="https://github.com/gnea/grbl/wiki/Grbl-v1.1-Configuration#20---soft-limits-boolean">enabled</a>)</li>
</ul>
<h2>G-code</h2>
<p>To plot anything, the machine needs G-code describing the sequence of motor moves.
There are many ways of generating it, the one I went with was <a href="https://github.com/abey79/vpype"><code>vpype</code></a> and <a href="https://github.com/plottertools/vpype-gcode"><code>vpype-gcode</code></a> — a powerful command-line tool for everything SVG and plotters.</p>
<p>Since this is a completely custom pen-plotter, I had to create my own configuration for <code>vpype-gcode</code>, which looks like this:</p>
<pre><code class="language-toml">[gwrite.plotter]

document_start = '''
G90       ; absolute coordinates
G21       ; mm units
G17       ; xy plane
G00 Z-15  ; pen up
'''

segment_first = '''
G00 Z-20  ; pen down
G00 X{x:.4f} Y{y:.4f}
'''
segment = '''
G00 X{x:.4f} Y{y:.4f}
'''
segment_last = '''
G00 X{x:.4f} Y{y:.4f}
G00 Z-15  ; pen up
'''

document_end = '''
M2        ; program end
'''

unit = "mm"

# scale is (1 / (1/96 inch to mm))
# making 1px in SVG == 1mm in real world
scale_x = 3.779527559
scale_y = 3.779527559

</code></pre>
<p>This configuration scales the resulting G-code so <code>1px</code> in SVG equals <code>1mm</code>.
To plot an SVG file I first convert it to G-code:</p>
<pre><code class="language-bash">vpype --config vpype-config.toml read image.svg gwrite -p plotter image.gcode
</code></pre>
<p>Then I start the machine, home it (<code>$H</code> command into <code>grbl</code>), and manually jog the X/Y axis if I want to start the drawing somewhere else rather than in the lower-left corner.
Finally I zero-out the axes to where they are <code>G10 L20 P1 X0 Y0 Z0</code> (so the <code>0/0/0</code> is where the tool is), and I'm ready to load up the resulting <code>image.gcode</code> and hit "run".</p>
<h2>Useful Links</h2>
<p><a href="https://mattferraro.dev/posts/cnc-router">Anatomy of a CNC Router</a> covers materials and software in way more detail than I did here.
<a href="https://wiki.printnc.info/en/home">PrintNC</a> is the recommended route if you want a DIY project, but not one made completely from scratch.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/</guid>
            <pubDate>Mon, 02 Oct 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[DIY Pen Plotter]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/diy-pen-plotter/miniature.png" alt="Photo" width="1920" height="1080">
<p>I've spent about three months lazily noodling on the first iteration of a DIY Pen Plotter.
It actually plots:</p>
<video controls muted>
<source src="https://szymonkaliski.com/projects/diy-pen-plotter/pen-plotter-plotting.mp4" type="video/mp4">
</video>
<p>I collected some learnings and resources from the process here: <a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/">Building a DIY Pen Plotter</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/diy-pen-plotter/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/diy-pen-plotter/</guid>
            <pubDate>Mon, 02 Oct 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q3 2023]]></title>
            <description><![CDATA[<p>Hi, hope you had a great summer!</p>
<p>At Replit, we just released a <a href="https://replit.com/desktop">Desktop App</a> which I helped build.
Go check it out and ping me with any issues or feature requests.
I also have a couple of other things in the pipeline, if you want to have access to them early, turn on the "explorer" setting in your account.</p>
<p>Other than that, I've spent this quarter lazily working on a <a href="https://szymonkaliski.com/projects/diy-pen-plotter/">DIY Pen Plotter</a>, and treating it as a stepping stone towards making a CNC.
The plotter was designed and built completely from scratch, and I'm quite pleased with myself that it, in fact, does plot with a pen:</p>
<div class="measure-wide">
  <img src="https://szymonkaliski.com/pen-plotter-plotted.png" width="2326" height="2326">
</div>
<p><a href="https://adamwiggins.com">Adam Wiggins</a> once told me that the best explanations are made by people who just learned something, as they haven't yet internalized that thing and forgotten what was hard about learning it.
So, keeping that in mind, I wrote a <a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/">blog post on building this project</a>.</p>
<p>I also went to the last Strange Loop edition, it was amazing to see so many friends in one place, I had a ton of inspiring conversations, and the talks were great as well.
I'm obviously sad that the conference is going away but grateful that we had it for a while.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li><a href="https://www.amazon.com/Bringing-Design-Software-Terry-Winograd/dp/0201854910/">Bringing Design to Software</a> — a great collection of essays edited by Terry Winograd; the book is a bit dated, but still a very interesting read</li>
<li><a href="https://www.amazon.com/Human-Machine-Reconfigurations-Learning-Doing-Computational/dp/052167588X">Human-Machine Reconfigurations</a></li>
<li><a href="https://www.amazon.com/How-Solve-Mathematical-Princeton-Science/dp/069111966X">How to Solve It</a>, a classic</li>
<li><a href="https://www.amazon.com/Where-Mathematics-Come-Embodied-Brings/dp/0465037712">Where Mathematics Comes From</a> — Lakoff's take on mathematics origins in metaphors</li>
<li><a href="https://www.amazon.com/Educating-Reflective-Practitioner-Teaching-Professions/dp/1555422209">Educating The Reflective Practitioner</a> — second part to "The Reflective Practitioner"</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://vezwork.github.io/polylab/dist/demo/bidirectionalParse/">Bidirectional Language Note</a> from <a href="https://elliot.website">Elliot</a></li>
<li>more <a href="https://twitter.com/antimatter15/status/1698138582513553835">typography in code editors</a></li>
<li><a href="https://twitter.com/jimmyhmiller">Jimmy</a> is making a <a href="https://twitter.com/jimmyhmiller/status/1693685501796945984">text editor</a></li>
<li><a href="https://tiarkrompf.github.io/notes/?/differentiable-graphics/">Differentiable Programming for Interactive Graphics</a></li>
<li><a href="https://www.linusakesson.net/programming/tty/">The TTY demystified</a>, and while we're on the topic of shells and terminals, <a href="https://www.youtube.com/watch?v=l_qY2p0OH9A">a talk on a new terminal emulator written in Zig</a> and <a href="https://terminal.click/posts/2023/07/bringing-dead-text-to-life/">another terminal emulator trying out some new interactions</a></li>
<li><a href="https://www.youtube.com/watch?v=lvvzolKHt2E">a talk on Unit</a> — a cool visual programming language with very interesting semantics</li>
<li><a href="https://arxiv.org/abs/2308.03921">A Node-based Interface for Exploratory Creative Coding with Natural Language Prompts</a> from <a href="https://tyler.cafe">Tyler</a></li>
<li>this <a href="https://genart.social/@guidoschmidt/110754321790658925">generative art project</a> inspired by Calder's sculptures</li>
<li><a href="https://www.youtube.com/watch?v=LPYEd50j3s0">Building a String Art Machine</a></li>
</ul>
<h2>Fin</h2>
<p>I'm going to <a href="https://2023.splashcon.org">SPLASH</a> in Cascais at the end of October — let me know if you'll be there too, and if not — catch you in a couple of months!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2023-10-02-q3-2023/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2023-10-02-q3-2023/</guid>
            <pubDate>Mon, 02 Oct 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q2 2023]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>Today marks my three-month anniversary at <a href="http://replit.com">Replit</a>!</p>
<p>Going from 10-ish person research lab to 100-ish person startup definitely is an adjustment.
For one, it's impossible to know about everything that's going on.
Two, small details matter in addition to the "big vision".
With exploratory research, it's often a good idea to hand-wave at things that would be solvable with additional engineering time, here, you have to do the "additional engineering" too, which changes the pace (and focus) of the work quite a bit.
And three: you actually have feedback from real users and the outside world, and while sometimes emotionally difficult, it dictates a real goalpost to go after.</p>
<p>Working at Replit sometimes feels like building an IDE, and sometimes like iterating on a new operating system.
I'm excited about how integrated the product can become, about blurring the line between working alone and collaborating, and between developing an app, deploying, and debugging production issues.</p>
<p>We're growing and <a href="https://replit.com/site/careers">hiring actively across the board</a>, feel free ping me if you have any questions!</p>
<h2>Smaller Projects</h2>
<p>I managed to publish two projects since the <a href="https://szymonkaliski.com/newsletter/2023-04-03-q1-2023/">last newsletter issue</a> that you might have missed:</p>
<ul>
<li><a href="https://szymonkaliski.com/projects/live-coding-livebook/">Live Coding Livebook</a> — an exploratory work into enhancing <a href="https://elixir-lang.org">Elixir</a>'s <a href="https://livebook.dev">Livebook</a> with probing, tracing, and live test feedback</li>
<li><a href="https://szymonkaliski.com/projects/sdfsheets/">SDFSheets</a> — a nerd-snipe from <a href="https://cosocial.ca/@avi">Avi Bryant</a>, an experiment in combining spreadsheets and signed distance functions for 2D modeling</li>
</ul>
<p>For both, there's more info in the linked write-ups, and SDFSheets even has a <a href="http://sdfsheets.vercel.app">live demo</a> that you can play with!</p>
<h2>DIY Plotting</h2>
<p>I've also been very slowly noodling on an extremely over-engineered pen plotter, with a hope to later turn it into a CNC (hence the overkill of motors and supports).</p>
<img src="https://szymonkaliski.com/newsletter/2023-07-03-q2-2023/plotter.png" alt="Plotter design" width="1000" height="1000">
<p>I don't really have a need for a pen plotter, or a CNC for that matter, but I missed making things with my hands (again), and this project is a good excuse to do that.</p>
<p>I'm also doing this completely from scratch, and it's a good excuse to learn about designing more complex machines, and how to use a grown-up CAD software in the process (previously I only used <a href="http://solvespace.com">SolveSpace</a>, which is great, but not enough for a project like this one).</p>
<p>So far I'm almost done with the first pass at the design, and starting to print initial test parts to see if they actually fit (nothing ever does on the first try).
I'm hopeful that this thing will be able to draw something with an actual pen by the end of the year.</p>
<h2>Worth Checking Out</h2>
<p>What I've been reading lately:</p>
<ul>
<li>two different perspectives on early computing history:
<ul>
<li><a href="https://www.amazon.com/What-Dormouse-Said-Counterculture-ComputerIndustry-ebook/dp/B000OCXFYM">What the Dormouse Said</a></li>
<li><a href="https://www.hup.harvard.edu/catalog.php?isbn=9780674970977">A People's History of Computing in the United States</a></li>
</ul>
</li>
<li><a href="https://en.wikipedia.org/wiki/Activity_theory">activity theory</a> and its overlaps with HCI:
<ul>
<li><a href="https://www.hup.harvard.edu/catalog.php?isbn=9780674576292">Mind in Society</a></li>
<li><a href="https://direct.mit.edu/books/book/3274/Context-and-ConsciousnessActivity-Theory-and-Human">Context and Consciousness</a></li>
</ul>
</li>
<li>and a bit on media theory: <a href="https://www.amazon.com/Amusing-Ourselves-Death-Discourse-Business/dp/014303653X">Amusing Ourselves to Death</a>, and I'm in the middle of <a href="https://www.amazon.com/Conscientious-Objections-Stirring-Technology-Education/dp/067973421X">Conscientious Objections</a></li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://jpl.design/papers/b5.pdf">Positional Control in Node-Based Programming</a></li>
<li>a great (as always) in-depth tutorial from Amit on <a href="https://www.redblobgames.com/making-of/draggable/">making objects draggable</a></li>
<li><a href="https://www.lesswrong.com/posts/epgCXiv3Yy3qgcsys/you-can-t-predict-a-game-of-pinball">You Can’t Predict a Game of Pinball</a></li>
<li><a href="https://tyler.cafe">Tyler</a> has a cool paper coming up, <a href="https://twitter.com/tylerangert/status/1638530463093477378">here's a preview</a></li>
<li>a cool exploration of <a href="https://box.henryzoo.com">movement in visual programming</a> — some <a href="https://pod.link/1559446316">Hest</a> and <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a> vibes</li>
<li><a href="https://www.youtube.com/watch?v=apqF8_7dgbY">Supporting Programming with Interactive, Contextual, Structured, and Visual Logs</a> and <a href="https://www.youtube.com/watch?v=vItfhC-5fvs">Multi-level Visualization of Program Execution</a> from the same group</li>
</ul>
<h2>Fin</h2>
<p>Have a great summer (touch some grass!), and catch you in a couple of months.</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2023-07-03-q2-2023/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2023-07-03-q2-2023/</guid>
            <pubDate>Mon, 03 Jul 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Live Coding Livebook]]></title>
            <description><![CDATA[<p><a href="http://livebook.dev">Livebook</a> is an interactive notebook for <a href="https://elixir-lang.org">Elixir</a>, enabling everything from exploratory coding, through visualizing data, to building production applications.
It's also multiplayer, can be self-hosted, backed by actual files on your hard-drive (a superset of Markdown) — definitely worth <a href="https://livebook.dev/#install">checking out</a>!</p>
<p>I collaborated with <a href="https://twitter.com/josevalim">José</a> on a set of research prototypes that show a direction towards expanding Livebook with additional live-coding concepts: <a href="https://szymonkaliski.com/projects/live-coding-livebook/#probing">probing</a>, <a href="https://szymonkaliski.com/projects/live-coding-livebook/#tracing">tracing</a>, and <a href="https://szymonkaliski.com/projects/live-coding-livebook/#testing">live test feedback</a>.</p>
<p>None of these ideas are necessarily "new", but then again, what is.
For prior art, make sure to check out:</p>
<ul>
<li><a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/onward011-mcdirmid.pdf">Usable Live Programming</a></li>
<li><a href="https://dl.acm.org/doi/pdf/10.1145/3426428.3426919">Example-Based Live Programming for Everyone</a></li>
<li><a href="https://arxiv.org/pdf/1902.00549.pdf">Babylonian-style Programming</a></li>
<li><a href="https://dl.acm.org/doi/pdf/10.1145/3313831.3376494">Projection Boxes</a></li>
<li><a href="https://www.geoffreylitt.com/margin-notes/">Margin Notes</a></li>
</ul>
<p>Finally, some of the ideas were prototyped in JavaScript and not Elixir, mainly to optimize for research velocity (as in, I'm just faster in that world); there's nothing conceptually stopping these ideas from being applied to Elixir, and some of the prototypes are already being implemented in Livebook which is exciting to see!</p>
<h2>Probing</h2>
<p>Elixir already has a concept of a <code>dbg()</code> which logs the value out, and passes it through (which already is an improvement over something like <code>print()</code> that requires restructuring your code around it).
Since we have control over both the editing environment and the runtime, we can easily extend the editor with live value display:</p>
<img src="https://szymonkaliski.com/projects/live-coding-livebook/probing.png" alt="Example of probing" width="550" height="164">
<p>A couple of things to notice in the screenshot above:</p>
<ol>
<li>adding <code>dbg()</code> calls doesn't change any logic about your program, and can be injected anywhere without having to restructure anything</li>
<li>we support inline logging not only for plain values, but also objects and arrays — these can grow huge, so we truncate them after a couple of characters, and you can always get to full view by hovering over them (both with mouse and a cursor)</li>
<li>having this sort of always-on visualizations of relevant parts of the code makes it very easy to spot issues — it's easy to see that I forgot to <code>rest.join()</code> to get back to a string from an array of letters</li>
</ol>
<h2>Tracing</h2>
<p>Probing described above provides a view into a static "snapshot" of the execution — notice how the <code>dbg()</code> inside <code>map</code> callback only logs out <code>l</code> and we don't see the <code>e</code> from the first loop.
Tracing is a way to display probed values over time and see the history of their execution.</p>
<p>Here's an example trace output from processing an array of todos and grouping them by attached tag:</p>
<img src="https://szymonkaliski.com/projects/live-coding-livebook/trace.png" alt="Example trace output" width="1940" height="200">
<p>To condense the view, but still keep the system generic, we're displaying "semantic miniatures" of the values.
Basic plain values can be easily displayed inline, but complex ones (like objects and arrays), are condensed to display how much they have changed between successive calls — for example <code>+2 ~1 -0</code> means that two new fields have been added, one was modified, and none were removed.
Custom data types can be also provided by the users of the system, building up on the <a href="https://github.com/livebook-dev/kino">Kino</a> system for defining interactive widgets, already used widely in Livebook.</p>
<p>The programmer can construct a more detailed ad-hoc view by clicking on these values to toggle their full display on/off:</p>
<video muted controls>
  <source src="https://szymonkaliski.com/projects/live-coding-livebook/trace-full-view.mp4" type="video/mp4">
</video>
<p>Tracing could be implemented within Livebook as an additional output tab below a cell:</p>
<img src="https://szymonkaliski.com/projects/live-coding-livebook/trace-livebook-integration.png" alt="Integrating tracing with Livebook" width="400" height="274">
<h2>Testing</h2>
<p>Elixir provides a way to inline tests inside the documentation strings: <a href="https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#doctests">doctests</a>.
This feature is widely used by both Elixir core and libraries, and Livebook also has basic support for handling them.</p>
<p>As a part of this research project, we explored augmenting them more with live status updates, and integration with the probing and tracing described above.</p>
<img src="https://szymonkaliski.com/projects/live-coding-livebook/doctests.png" alt="Doctests prototype" width="530" height="447">
<p>Each test is enhanced with a traffic light-like status and a random emoji, which acts as an identifier.
The tabs below a cell, in addition to output and main trace, also include tracing-per-test, so the programmer can focus on a specific issue one at-a-time.</p>
<h2>What feels alive?</h2>
<p>Finally, even though it might be obvious, it's important to mention how much better probing and tracing mechanisms work, when they evaluate on every keystroke, compared to being an action you have to take explicitly.</p>
<p>As a programmer, I can stay at my keyboard and just type, and get inline live feedback of how my code behaves. If something is not quite right, it's easy to "wiggle" some structures/values, and see the rest of the code respond ("wobble"), I believe that this is crucial for building such a system that <em>feels good!</em></p>
<video muted controls>
  <source src="https://szymonkaliski.com/projects/live-coding-livebook/wiggling.mp4" type="video/mp4">
</video>
<p>This is something that was also an important realization in the <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> research at Ink&#x26;Switch, I think <a href="https://www.inkandswitch.com/untangle/#:~:text=You%20should%20be%20able%20to%20intuit%20connections%20between%20various%20rules%20and%20constraints%20by%20wiggling%20them%20and%20seeing%20other%20things%20wobble.">best verbalized here</a> — immediate feedback makes it feel as if you are directly <a href="https://szymonkaliski.com/notes/working-with-the-material/">Working With The Material</a>, helps build intuition and leverages <a href="https://szymonkaliski.com/notes/peripheral-vision-in-software/">Peripheral Vision</a> for spotting patterns and issues.</p>]]></description>
            <link>https://szymonkaliski.com/projects/live-coding-livebook/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/live-coding-livebook/</guid>
            <pubDate>Mon, 19 Jun 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[SDFSheets]]></title>
            <description><![CDATA[<p>SDFSheets is an experimental spreadsheet interface for working with <a href="https://en.wikipedia.org/wiki/Signed_distance_function">Signed Distance Functions</a>.
It's a continuation of exploring my interests in SDFs (<a href="https://szymonkaliski.com/projects/sdf-ui/">SDF-UI</a>, <a href="https://szymonkaliski.com/projects/hiccup-sdf/">hiccup-sdf</a>), spreadsheet-like interfaces (<a href="https://szymonkaliski.com/projects/protoboard/">Protoboard</a>) and <a href="https://szymonkaliski.com/notes/computational-dags/">Computational DAGs</a>.</p>
<p>This project was a result of a <a href="https://xkcd.com/356/">nerd snipe</a> from <a href="https://cosocial.ca/@avi">Avi Bryant</a> who worked on a pretty similar exploration called <a href="https://loglo.app">Loglo</a>.</p>
<p>If you want to play around with SDFSheets, check out the <a href="http://sdfsheets.vercel.app">live demo</a>.</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/sdfsheets/sdfsheets.mp4" type="video/mp4">
</video>
<p>This prototype provides a couple of very basic tools — a <code>circle</code> and a <code>box</code>, a way to <code>translate</code> and <code>rotate</code> the SDF, and CSG-like operations: <code>union</code>, <code>subtract</code>, and <code>intersect</code>:</p>
<img src="https://szymonkaliski.com/projects/sdfsheets/csg.png" alt="CSG operations" width="800" height="660">
<p>You can also build your own SDFs from scratch by calling <code>sdf()</code> with a custom callback:</p>
<img src="https://szymonkaliski.com/projects/sdfsheets/donut.png" alt="Custom donut SDF" width="400" height="400">
<p>As usual, this is just a prototype, and there's a bunch of obvious improvements that could be made:</p>
<ul>
<li>the usual spreadsheet niceties:
<ul>
<li>click on another cell to insert a reference</li>
<li>smart references that work with copy-paste</li>
<li>referencing other cells by <code>B2</code> instead of <code>$("B2")</code></li>
</ul>
</li>
<li>support for ranges, so we can <code>sdf.union(B2:B5)</code></li>
<li>autocomplete for the code input</li>
</ul>]]></description>
            <link>https://szymonkaliski.com/projects/sdfsheets/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/sdfsheets/</guid>
            <pubDate>Sat, 20 May 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q1 2023]]></title>
            <description><![CDATA[<p>Hi!</p>
<p>As you might remember from <a href="https://szymonkaliski.com/newsletter/2023-01-02-q4-2022/">my last newsletter</a>, I started looking for the next thing after Ink&#x26;Switch at the beginning of the year.
I'm happy to report that I'm going to continue working on <a href="https://szymonkaliski.com/notes/future-of-coding/">Future Of Coding</a> efforts as a Design Engineer at <a href="http://replit.com">Replit</a>.
I'm excited about the opportunity to work on these sorts of problems, and at the same time be so much closer to authentic users, the industry, and work on a great product — exactly what I was looking for!</p>
<p>Because January and February were dominated by the interview calls, and in March, I took some time off to recharge, I don't have anything else to share other than notes from the process itself, which you'll find below.
I managed to squeeze in a couple of hours here and there on a consulting project for <a href="http://livebook.dev">Livebook</a>, but I'll leave that for another time.</p>
<h2>Musings from the Job Hunt</h2>
<p>Firstly, a huge <em>thank you!</em> to everyone who chatted with me, to friends who connected me to other friends, and to my partner's support through the whole process.</p>
<p>Secondly, this is not a generic guide on how to find a job, but rather observations from my personal experiences.
As with every advice, a lot of it only applies to the person who gives it — so here are some unusual aspects to take into account:</p>
<ul>
<li>This was my first time explicitly looking to join a company, and be a part of a bigger team. Previously, I was mostly independent, and I joined Ink&#x26;Switch through a set of opportunistic coincidences (words which could describe my whole career really) — not through a process like this one.</li>
<li>I have an unusual set of experiences (and over a decade of them under my belt), and I'm also pretty weirdly specialized — a mix of researcher/designer/developer in the field of complex/computational interfaces is a quite uncommon thing.</li>
<li>I also built up some online presence over the years, with a lot of public projects and writings, which definitely helped with getting my foot in the door. About half of the interviews I've gotten were inbound, and the other half came from reaching out through my network.</li>
<li>I'm in central/eastern Europe, which adds an additional dimension to navigate through the process: is the company thinking about me in terms of "cheap outsourcing" or actually needs my skill-set and doesn't care where I am? (the red flag was someone mentioning that I'm in Poland one time too many — fortunately this happened only once)</li>
</ul>
<p>Thirdly, I chose one of the worst possible times to look for a job, as most of the tech companies were <a href="https://layoffs.fyi">laying off huge percentages of their workforce</a>.
Luckily, I only felt this once in my whole interview journey, when a company that I was getting excited about had frozen all their hiring during the process.
Also, the phrase "in the current economy" had an appearance on a couple of calls.
Overall, I'm very grateful for not having to think about this too much.</p>
<p>With all that out of the way: through January and February I've spent 63 hours on 75 calls (not including the preparation time that easily doubles this), decided to go through seven interview loops, resulting in six overlapping offers.
This was probably excessive, but: I wanted to be thorough, get a full overview of my situation, and I used these calls to dial-in what it is exactly that I'm looking for (though having some <em>vague sense</em> of that beforehand was very important).
For example, I very quickly learned that the sets of problems that people deal with in the <em>tools for thought</em> community (which often means note-taking), are not something that resonates with me a lot, or that there actually is a difference in a role at a Pre-Seed startup compared to a Series C one (who would have thought?).
Generally, "<a href="https://www.proofofconcept.pub/p/on-meaningful-conversations">have a lot of conversations</a>" is great advice.</p>
<p>Having alternatives as I interviewed was also very helpful for my anxiety — no single call was infinitely important, which made it easier to stay in the flow of conversation, and not feel pressure that things have to work out.
Again, a <em>mutual fit</em> was what I looked for, it wasn't always there, and that's ok.</p>
<p>During the first calls, the whole point was to figure out if there's a space for someone like me.
Usually, I hit one of three approaches:</p>
<ul>
<li>A company hiring only for very compartmentalized roles, or</li>
<li>a company <em>accepting</em> an unusual/mixed role, or</li>
<li>a company really looking for someone like me.</li>
</ul>
<p>The whole high-level theme here was about leaning into, and <em>capitalizing on</em>, the weirdness (<a href="https://szymonkaliski.com/notes/play-your-own-games/">Play Your Own Games</a>), so obviously the latter was my preference, and this is where I spent the bulk of my time.</p>
<p>I generally took "we don't really have an interview loop for this specific position" as a good sign, and tried to work with the company to figure out what's the best way to evaluate the potential fit (and again, the evaluation was bidirectional).
When describing myself, I leaned into a "designer with strong technical background" rather than "engineer with some design skills".
I also discovered that some companies now have a <em>Design Engineer</em> role, which usually was a pretty good fit (and where I ended up in the end).</p>
<p>Most (but not all) of the interview loops I went through included a portfolio review and a design exercise, sometimes also a deep dive into one of my past projects, including a code walkthrough.
All of the companies I interviewed with, had me work on a design-engineering problem, and I've got to play around with designing a VPL, a projectional editor, and tightly integrating code deployments with an IDE. The idea wasn't to <em>solve</em> these problems completely, but to show how I work and think about things.</p>
<p>I drew the line at a coding exercise — at this point I tried to <a href="https://staffeng.com/guides/interviewing-staff-plus-roles/#:~:text=decide%20for%20yourself.-,Debug%20the%20process,-After%20you%E2%80%99ve%20drawn">debug the process</a> a bit with the company.
My thinking was that with my specialization, the other side wouldn't learn anything seeing me write a binary search or parse some <code>JSON</code> from an API, and that this was not the measuring stick to use for what I'm after.</p>
<p>I spent the most time preparing for the behavioral interviews.
I grabbed a ton of questions I could find online, from "why are you looking for a new job?" to "describe a conflict with your manager", and tried to really ruminate on them, and write down my thoughts (some of them were great reflection prompts actually).
I didn't memorize the answers, but having a couple of points I knew I wanted to talk about in advance was very helpful, instead of coming up with things on the spot.</p>
<p>The only technical preparation I went through was creating a slide deck for the portfolio reviews.
A ton of my projects are <a href="https://szymonkaliski.com/projects/">online</a>, but I wanted to also walk through the process, give additional context, etc.
I strategically picked two projects: <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a> which shows the research-y and team-lead-y side of me, and <a href="https://szymonkaliski.com/projects/glide-code-components/">Glide's Code Components</a> which was the most recent, most production-resembling, solo work.</p>
<p>During the calls, I took notes on <em>everything</em>, and then transcribed them into a single document where I had a section for every company, with dated notes for the calls I made, including whom I talked to.
Through this process, I settled on a set of questions that were important to me, and moved towards creating a structure to compare these companies and their offers against each other.
The common set of questions included: company size, runway, funding situation, goals for this year and next five years, and their <em>worries</em> (both about where the company is going, and about the possible role we were discussing).</p>
<p>Coming up with a (somewhat arbitrary) timeline on my side helped move things along.
I was saying that I wanted to go through the interviews and make my decision by the end of February ...and that's pretty much exactly what happened.</p>
<p>Setting up a <a href="https://calendly.com">Calendly</a> account was crucial.
Navigating multiple daily calls during the reasonable overlap I get with PST would be impossible without it.
Also, setting the call duration to 45 minutes, and having a 15-minute break between calls worked out great — there was always space to go over time if necessary, but usually gave me time to make fresh tea, and switch mental contexts before jumping from one call into another.</p>
<p>As for the details of the offers, I don't feel comfortable sharing any specific numbers on the world-wide-web, but I can say two things:</p>
<ul>
<li>one, that the distance from the lowest to the highest offer was over 2×</li>
<li>two, that the offers I were getting rarely were correlated with any of the ranges on the job offers for these companies that I could find online (and still, rarely there were any), or with how well I felt the interview process went, or with how excited the company seemed</li>
</ul>
<p>Doing actual preparation for the process (asking around, and reading up on how to do this properly) paid off, and as cliché as it sounds — it was definitely an important learning experience.
Interviewing and <em>selling yourself</em> is a skill, but as with every skill — it's learnable, and improvable.</p>
<p>I'm extremely happy to have signed with Replit, and very grateful for where I've gotten, and how (somewhat) <em>easy</em> (<em>straight-forward?</em>) this whole thing has been (but don't get me wrong, it was exhausting, and it took me two weeks of doing nothing, to get out of a brain fog that it caused).</p>
<h2>Links I Found Helpful for the Job Hunting Process</h2>
<p>Career advice:</p>
<ul>
<li><a href="https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/">https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/</a> (a classic)</li>
<li><a href="https://lethain.com/forty-year-career/">https://lethain.com/forty-year-career/</a></li>
<li><a href="https://commoncog.com/so-good-they-cant-ignore-you/">https://commoncog.com/so-good-they-cant-ignore-you/</a></li>
</ul>
<p>Preparation, and non-technical interview questions:</p>
<ul>
<li><a href="https://jvns.ca/blog/2014/01/16/what-my-technical-interviews-have-looked-like/">https://jvns.ca/blog/2014/01/16/what-my-technical-interviews-have-looked-like/</a></li>
<li><a href="https://github.com/learn-co-curriculum/bootcamp-prep-research-before-an-interview">https://github.com/learn-co-curriculum/bootcamp-prep-research-before-an-interview</a></li>
<li><a href="https://github.com/learn-co-curriculum/bootcamp-prep-answering-non-technical-interview-questions">https://github.com/learn-co-curriculum/bootcamp-prep-answering-non-technical-interview-questions</a></li>
<li><a href="https://gist.github.com/nonsie/d07ebc343e23e5b5cd544609d1767f93">https://gist.github.com/nonsie/d07ebc343e23e5b5cd544609d1767f93</a></li>
</ul>
<p>Reverse-interview questions:</p>
<ul>
<li><a href="https://github.com/viraptor/reverse-interview">https://github.com/viraptor/reverse-interview</a></li>
<li><a href="https://jvns.ca/blog/2013/12/30/questions-im-asking-in-interviews/">https://jvns.ca/blog/2013/12/30/questions-im-asking-in-interviews/</a></li>
<li><a href="https://twitter.com/jensenharris/status/988967889330819072">https://twitter.com/jensenharris/status/988967889330819072</a></li>
</ul>
<p>Salaries and negotiation:</p>
<ul>
<li><a href="https://www.kalzumeus.com/2012/01/23/salary-negotiation/">https://www.kalzumeus.com/2012/01/23/salary-negotiation/</a> (another classic)</li>
<li><a href="https://jacobian.org/2021/oct/13/tech-salaries-2021/">https://jacobian.org/2021/oct/13/tech-salaries-2021/</a></li>
<li><a href="https://haseebq.com/my-ten-rules-for-negotiating-a-job-offer/">https://haseebq.com/my-ten-rules-for-negotiating-a-job-offer/</a></li>
<li><a href="https://haseebq.com/how-not-to-bomb-your-offer-negotiation/">https://haseebq.com/how-not-to-bomb-your-offer-negotiation/</a></li>
<li><a href="https://candor.co/guides/salary-negotiation">https://candor.co/guides/salary-negotiation</a></li>
<li><a href="https://github.com/petermekhaeil/salary-negotiating">https://github.com/petermekhaeil/salary-negotiating</a></li>
</ul>
<p>What is equity, and how to value it:</p>
<ul>
<li><a href="https://www.benkuhn.net/optopt">https://www.benkuhn.net/optopt</a></li>
<li><a href="https://www.benkuhn.net/options">https://www.benkuhn.net/options</a></li>
<li><a href="https://blog.pragmaticengineer.com/equity-for-software-engineers/">https://blog.pragmaticengineer.com/equity-for-software-engineers/</a></li>
<li><a href="https://stripe.com/en-pl/guides/equity-for-employees">https://stripe.com/en-pl/guides/equity-for-employees</a></li>
<li><a href="https://gist.github.com/yossorion/4965df74fd6da6cdc280ec57e83a202d">https://gist.github.com/yossorion/4965df74fd6da6cdc280ec57e83a202d</a></li>
</ul>
<h2>Worth Checking Out</h2>
<p>As a palate cleanser, I've spent the quarter reading up on (mostly molecular) biology, some highlights below:</p>
<ul>
<li><a href="https://www.amazon.com/Machinery-Life-David-S-Goodsell/dp/0387849246">The Machinery of Life</a> — highly recommended, you should get it even if biology doesn't interest you at all, just for the amazing illustrations!</li>
<li><a href="https://www.amazon.com/Quickstart-Molecular-Biology-Introductory-Mathematicians/dp/1621820343/">Quickstart Molecular Biology</a>, and <a href="https://www.amazon.com/Computer-Scientists-Guide-Cell-Biology/dp/038748275X/">A Computer Scientist's Guide to Cell Biology</a> for a closer look at how cells operate, and how we know how they operate</li>
<li>On Growth and Form — very dense classic; I enjoyed seeing more of the connection between biological forms and physics</li>
<li><a href="https://www.amazon.com/Entangled-Life-Worlds-Change-Futures/dp/0525510311">Entangled Life</a> — a bit pop-science-ish, but very enjoyable</li>
<li><a href="https://www.amazon.com/Evolution-Four-Dimensions-revised-Philosophical-ebook/dp/B08BT5YBHH/">Evolution in Four Dimensions</a> — not an easy read, but I loved the evolutionary lens on culture</li>
</ul>
<p>On the web:</p>
<ul>
<li>we published the <a href="http://inkandswitch.com/untangle/">Untangle essay</a></li>
<li><a href="https://retool.com/visual-basic/">history of Visual Basic</a></li>
<li><a href="https://www.youtube.com/watch?v=72y2EC5fkcE">magic that you can do if you control the whole programming stack</a></li>
<li>you should follow <a href="https://folkcomputer.substack.com/p/february-notes">Folk Computer</a> for a Dynamicland spin-off powered by RFID localization
<ul>
<li>and you should also follow <a href="https://blog.val.town">Val Town</a> for tweet-sized JS cloud scripting</li>
</ul>
</li>
<li><a href="https://codesandbox.io/blog/how-we-clone-a-running-vm-in-2-seconds">how to clone a VM in 2 seconds</a></li>
<li><a href="https://donhopkins.medium.com/designing-user-interfaces-to-simulation-games-bd7a9d81e62d">Will Wright on game interface design</a></li>
<li><a href="https://twitter.com/lhf55472946/status/1615307651013038080">FPGA diagrams in Excel</a>; and while we're on this topic: <a href="https://handmade.network/jam">a visibility jam</a></li>
<li><a href="https://zed.dev/blog/videogame">another code editor that renders like a game</a>; <a href="https://makepad.dev">Makepad</a> also does this, but doesn't have a nice write-up to link to</li>
<li><a href="https://tonsky.me/blog/clojure-sublimed-3/">adventures in writing a Clojure plugin for Sublime Text</a>, including parsing Clojure with Python, and talking to REPLs</li>
<li><a href="https://twitter.com/genmon/status/1636698753007603713">GPT-powered poem-clock</a>; also <a href="https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work/">how does ChatGPT work</a>
<ul>
<li>and you should definitely follow <a href="https://buttondown.email/geoffreylitt">Geoffrey's writings</a> on <a href="https://szymonkaliski.com/notes/end-user-programming/">End-User Programming</a> × LLM — I don't think I fully grasped what's happening yet (at least so far, this newsletter has been artisanally typed out, keystroke by keystroke)</li>
</ul>
</li>
</ul>
<h2>Fin</h2>
<p>Let me know if you got some value out of my job-hunting process write-up, and if you have any questions, feel free to <a href="mailto:hi@szymonkaliski.com">email me</a>.</p>
<p>Have a great spring, and see you in a couple of months!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2023-04-03-q1-2023/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2023-04-03-q1-2023/</guid>
            <pubDate>Mon, 03 Apr 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Untangle]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/untangle/miniature.png" alt="Untangle running on a tablet" width="1500" height="842">
<p>Untangle is a <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> research project done at <a href="https://www.inkandswitch.com/">Ink&#x26;Switch</a>, together with <a href="http://wolkenmachine.nl">Marcel Goethals</a>, and with engineering help from Mike Kluev.</p>
<p>This project was an exploration of a visual language for describing, and solving, constraint satisfaction problems.</p>
<p>As usual, there's a <a href="https://www.inkandswitch.com/untangle/">long essay documenting our goals, decisions, learnings and failures</a>. Enjoy!</p>
<p>Untangle was presented during my <a href="https://www.youtube.com/watch?v=ifYuvgXZ108">2022 Strange Loop talk</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/untangle/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/untangle/</guid>
            <pubDate>Thu, 05 Jan 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Untangle ↗]]></title>
            <description><![CDATA[Solving Problems with Fuzzy Constraints]]></description>
            <link>https://www.inkandswitch.com/untangle/</link>
            <guid isPermaLink="true">https://www.inkandswitch.com/untangle/</guid>
            <pubDate>Wed, 04 Jan 2023 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q4 2022]]></title>
            <description><![CDATA[<p>Hi,</p>
<p>the last quarter flew by — I was mostly working on finishing documentations of various projects (which you'll see below), and recovering from a <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#summer-plans">busy summer</a>.</p>
<p>I didn't have much time or brain-space for any serious side-projects. I noodled a bit more on the shape grammar stuff (putting a pin in it for now), and hacked together a MIDI CC looper for my <a href="https://monome.org/docs/norns/">Norns</a>, so I can record and replay knob movements for more organically sounding modulations.</p>
<p>Also, I guess I'm on Mastodon now: <a href="https://mas.to/@szymon_k">@szymon_k@mas.to</a></p>
<h2>Write-ups, a Talk, and a Podcast</h2>
<p>This quarter has been filled with a lot of <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> things:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=ifYuvgXZ108">My Strange Loop talk is now online</a>. I go over the background of why pen &#x26; paper is important, why we might want a <em>dynamic</em> version of these tools, and what they could look like.</li>
<li>I went on the <a href="https://museapp.com/podcast/71-programmable-ink/">Metamuse podcast</a> together with James Lindenbaum, to talk mainly about <a href="https://szymonkaliski.com/projects/inkbase/">Inkbase</a>, but we also touched on some related topics, including meta-reflections on the research process itself.</li>
<li>We published the <a href="https://www.inkandswitch.com/inkbase/">Inkbase essay</a> which surprisingly <a href="https://news.ycombinator.com/item?id=33799512">hanged around on the first page of Hacker News</a> for a couple of days.</li>
</ul>
<p>Finally, I wrote a <a href="https://www.glideapps.com/research/code-components">long article documenting my research into end-user-programmable UI-builder at Glide</a>, which includes a live version of the prototype — go check it out.
If you want to see it in action with additional commentary, I recorded a short informal demo in the <a href="https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/#research-at-glide">last newsletter issue</a>.</p>
<h2>What's Next?</h2>
<p>After four years at <a href="https://www.inkandswitch.com">Ink&#x26;Switch</a>, two of them as a Principal Investigator, I want to turn the dial from pure research, to more industry-oriented work.</p>
<p>My main interest lays in the space of no/low/future-of coding tools, and <a href="https://www.inkandswitch.com/end-user-programming/">end-user programming</a>.
I believe that there's a ton of untapped potential in <em>computing</em>, and that a lot of it is <a href="https://szymonkaliski.com/notes/the-incredible-power-of-the-right-interface/">limited by (broadly understood) <em>interfaces</em></a>.</p>
<p>I specialize in solving complex design problems, and approaching them from both engineering, and end-user perspectives.
I know how to lead a team, and I'm most interested in an IC role — not looking to become a manager.</p>
<p>The <a href="https://szymonkaliski.com/newsletter/2023-01-02-q4-2022/#write-ups,-a-talk,-and-a-podcast">section above</a> documents most of my recent work.
If you want to see more, you can explore the <a href="https://szymonkaliski.com/projects/">projects page</a>, or browse through some of my <a href="https://szymonkaliski.com/notes/">working notes</a>.</p>
<p>Reach out if you know something that might be a good fit: <a href="mailto:hi@szymonkaliski.com">hi@szymonkaliski.com</a> — I'm looking forward to hearing from you!</p>
<h2>Worth Checking Out</h2>
<p>Books I enjoyed recently:</p>
<ul>
<li><a href="https://www.amazon.com/Cognitive-Science-Introduction-Neil-Stillings/dp/0262691752">Cognitive Science: An Introduction</a> — a pretty good overview of the field of cognitive science</li>
<li><a href="https://www.amazon.com/Being-You-New-Science-Consciousness/dp/1524742872/">Being You</a> — the title sounds cheesy, but the book is not: highly recommended overview of current understanding of biological basis for consciousness</li>
<li><a href="https://www.amazon.com/Draw-Order-See-Cognitive-Architectural/dp/B07Y6D8SN8">Draw in Order to See</a> — very relevant to the <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> thread</li>
<li><a href="https://www.amazon.com/How-World-Really-Works-Science/dp/0593297067/">How The World Really Works</a> — (thanks <a href="https://www.geoffreylitt.com">Geoffrey</a> for the recommendation!) another very interesting book with a pretty cheesy title: this one explores various areas of current developed world through the lens of fundamental physical measures — things like how much human-labour-time is needed to produce a kilogram of wheat (two seconds!)</li>
<li><a href="https://mitpress.mit.edu/9780262240451/rules-of-play/">Rules of Play</a> — (thanks <a href="http://pvh.ca">Peter</a> for the recommendation!) a great study of what games are, and how to design them</li>
</ul>
<p>On the web:</p>
<ul>
<li>I feel obligated to share another Ink&#x26;Switch essay on <a href="https://www.inkandswitch.com/potluck/">Dynamic documents as personal software</a></li>
<li><a href="https://scienceplusplus.org/metascience/">An Engine of Improvement for the Social Processes of Science</a></li>
<li><a href="https://jackrusher.com/strange-loop-2022/">Stop Drawing Dead Programs</a>, and a collection of <a href="https://jackrusher.com/classic-ux/">Classic HCI Demos</a> from Jack Rusher</li>
<li><a href="https://twitter.com/marcinignac/status/1578306656135704576">3D modeling with spatial queries</a></li>
<li><a href="https://twitter.com/_baku89/status/1575866513466175488">Multi-touch number picker explorations</a></li>
<li><a href="https://www.youtube.com/watch?v=U9uZlEqUQw0">Homoiconic spreadsheets</a>, a great talk from <a href="https://elzr.com">Eli Parra</a> featuring a lot of overlaps with <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> track: spatial queries, unfolding time into space, and <a href="https://szymonkaliski.com/notes/working-with-the-material/">Working with the Material</a></li>
</ul>
<h2>Fin</h2>
<p>I hope 2022 was great for you, and as always, wishing you all the best for the upcoming one!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2023-01-02-q4-2022/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2023-01-02-q4-2022/</guid>
            <pubDate>Mon, 02 Jan 2023 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Reusable Code Components for Glide]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/glide-code-components/the-prototype.png" alt="Full prototype screenshot" width="1581" height="997">
<p><a href="https://www.glideapps.com">Glide</a> is a no-code platform which allows end-users to build custom applications from spreadsheets. The users start with providing their data, and then assemble the application from a set of available high-level components. The problem here is, that when the use-case doesn't neatly fit into one of the existing components, there's nothing that can be done — the system is closed, and can't be extended by end-users.</p>
<p>The focus of this research project was prototyping a UI-builder that fits into Glide's aesthetics, and provides a way to edit, and re-use, the visual components available in the system.</p>
<p>The project is document with a long write-up at the <a href="https://www.glideapps.com/research/code-components">Glide research page</a>, and below you'll find some more thoughts (and a demo video!) originally published in <a href="https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/#research-at-glide">Q3 2022</a> newsletter.</p>

<h2 is-transclusion-title="" class="f5 lh-copy mt5 mb2 near-black">Transcluded from <a href="https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/#research-at-glide">Research at Glide</a></h2>
          
<p><a href="https://www.glideapps.com">Glide</a> is a <em>no-code</em> tool for building mobile and web applications from spreadsheets — you provide your own data, choose how to render it from a set of high-fidelity components, and you can get to a working application in minutes.
This incredible convenience comes at a cost, of course — if you need something outside the set of pre-made components, you are pretty much at Glide's mercy to make new one for you.</p>
<p>The main goal of the project was to prototype a possible future in which technical Glide users have more freedom in how their apps look and behave, while still keeping the convenience of easily assembling ready-made parts.
We followed the intuition that at some level, <em>some code</em>, is ok — and the main question is how it's being packaged and composed into bigger wholes, and re-used at different levels of abstraction.</p>
<p>Below you can find a short narrated walkthrough of the prototype that we've built, to give you some sense of what we've made:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/glide-component-research-preview.mp4"></video>
<p>There are a couple of things here that I'm excited about:</p>
<ul>
<li>creating a space for <em>local developers</em> (after Bonnie Nardi) — power-users who are comfortable working with small pieces of HTML/CSS/JS, and/or assembling complex graphs for other users to re-use</li>
<li>using the exact same components through nesting in the layout tree, and inside other graphs</li>
<li>the semantics of multiple inputs and outputs which allow creating components with custom configuration UIs, and packaging related functionalities together</li>
<li>this is already a part of Glide, but worth repeating <em>ad nauseam</em>: working with <em>real data</em> inside a <em>live system</em> — the changes that you make to your data tables, to your logic, or visual components refresh live and are always visible — you never have to <a href="https://szymonkaliski.com/notes/simulator/">simulate</a> a computer in your head to figure out what values flow through the system</li>
</ul>
<p>I know that Glide is actively hiring, and if that sounds interesting, feel free to reach out to them <a href="https://www.glideapps.com/jobs">directly</a> or let me know if you want an intro!</p>]]></description>
            <link>https://szymonkaliski.com/projects/glide-code-components/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/glide-code-components/</guid>
            <pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Reusable Code Components for Glide ↗]]></title>
            <description><![CDATA[Reusable Code Components for Glide]]></description>
            <link>https://www.glideapps.com/research/code-components/</link>
            <guid isPermaLink="true">https://www.glideapps.com/research/code-components/</guid>
            <pubDate>Sun, 11 Dec 2022 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Inkbase]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/inkbase/miniature.png" alt="Inkbase running on a tablet" width="1600" height="900">
<p>Inkbase is another <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> research project done at <a href="https://www.inkandswitch.com/">Ink&#x26;Switch</a>, together with James Lindenbaum and <a href="http://joshuahhh.com/">Joshua Horowitz</a> during summer and autumn of 2020.</p>
<p>With Inkbase we explored what would it mean to have a hand-drawn ink combined with spreadsheet-like reactivity, all in end-user programmable form.</p>
<p>To learn more about the research, head over <a href="https://www.inkandswitch.com/inkbase/">here for a long write-up</a> covering everything from philosophy behind hand-drawn marks, to intricacies of the programming model.</p>
<p>Inkbase was presented during my <a href="https://www.youtube.com/watch?v=ifYuvgXZ108">2022 Strange Loop talk</a>, and at the <a href="https://www.youtube.com/watch?v=z3axx5rZMWI">2021 LIVE conference</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/inkbase/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/inkbase/</guid>
            <pubDate>Sun, 30 Oct 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Inkbase ↗]]></title>
            <description><![CDATA[Programmable Ink]]></description>
            <link>https://www.inkandswitch.com/inkbase/</link>
            <guid isPermaLink="true">https://www.inkandswitch.com/inkbase/</guid>
            <pubDate>Sat, 29 Oct 2022 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q3 2022]]></title>
            <description><![CDATA[<p>Hi,</p>
<p>this is going to be a shorter update.</p>
<p>As you might remember, I spent this quarter doing a research residency at <a href="https://www.glideapps.com">Glide</a>, where I prototyped a programming system for building custom components, focused on composability, re-use, and liveliness.
We're working on a longer write-up, and I'll let you know when it's out.
In the meantime, I recorded a short walkthrough to give you some sense of where we ended up, that you can check out <a href="https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/#research-at-glide">below</a>.</p>
<p>Most of my free time this quarter went into preparing for my <a href="https://thestrangeloop.com/2022/programmable-ink.html">Strange Loop talk</a> about the research I've been doing at <a href="https://www.inkandswitch.com">Ink&#x26;Switch</a>.
From what I heard the talk went pretty well though, and I enjoyed all the hallway conversations that it spawned.
The video will be out sometime in the upcoming weeks on the <a href="https://www.youtube.com/c/StrangeLoopConf/videos">Strange Loop YouTube</a>.</p>
<p>With the little free time that I could find, I continued explorations of some ideas that I first started playing around at <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#summer-plans">Gradient Retreat</a> — using graphs to describe vector shapes, and querying them using Datalog.
This project is nowhere near being demo-able yet.</p>
<h2>Research at Glide</h2>
<p><a href="https://www.glideapps.com">Glide</a> is a <em>no-code</em> tool for building mobile and web applications from spreadsheets — you provide your own data, choose how to render it from a set of high-fidelity components, and you can get to a working application in minutes.
This incredible convenience comes at a cost, of course — if you need something outside the set of pre-made components, you are pretty much at Glide's mercy to make new one for you.</p>
<p>The main goal of the project was to prototype a possible future in which technical Glide users have more freedom in how their apps look and behave, while still keeping the convenience of easily assembling ready-made parts.
We followed the intuition that at some level, <em>some code</em>, is ok — and the main question is how it's being packaged and composed into bigger wholes, and re-used at different levels of abstraction.</p>
<p>Below you can find a short narrated walkthrough of the prototype that we've built, to give you some sense of what we've made:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/glide-component-research-preview.mp4"></video>
<p>There are a couple of things here that I'm excited about:</p>
<ul>
<li>creating a space for <em>local developers</em> (after Bonnie Nardi) — power-users who are comfortable working with small pieces of HTML/CSS/JS, and/or assembling complex graphs for other users to re-use</li>
<li>using the exact same components through nesting in the layout tree, and inside other graphs</li>
<li>the semantics of multiple inputs and outputs which allow creating components with custom configuration UIs, and packaging related functionalities together</li>
<li>this is already a part of Glide, but worth repeating <em>ad nauseam</em>: working with <em>real data</em> inside a <em>live system</em> — the changes that you make to your data tables, to your logic, or visual components refresh live and are always visible — you never have to <a href="https://szymonkaliski.com/notes/simulator/">simulate</a> a computer in your head to figure out what values flow through the system</li>
</ul>
<p>I know that Glide is actively hiring, and if that sounds interesting, feel free to reach out to them <a href="https://www.glideapps.com/jobs">directly</a> or let me know if you want an intro!</p>
<h2>Worth Checking Out</h2>
<p>This quarter wasn't that great for my book-reading. I read a bunch of things, but can recommend only a handful of them:</p>
<ul>
<li><a href="https://www.amazon.com/Art-Illusion-Psychology-Pictorial-Representation/dp/0691070008">Art and Illusion</a></li>
<li><a href="https://press.stripe.com/pieces-of-the-action">Pieces of The Action</a> — memoirs from Vannevar Bush (of radars, Manhattan Project, Memex, etc.) on the importance of individuals and organizations in R&#x26;D</li>
<li>I took a short detour through a couple of management-related books recommended by various friends: <a href="https://www.amazon.com/Radical-Candor-Revised-Kim-Scott/dp/1250235375">Radical Candor</a>, <a href="https://www.amazon.com/Making-Manager-What-Everyone-Looks/dp/0735219567">The Making of a Manager</a>, <a href="https://press.stripe.com/an-elegant-puzzle">An Elegant Puzzle</a></li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://thenumb.at/Autodiff/">Differentiable Programming from Scratch</a> — great overview of various approaches to automatic differentiation with code samples</li>
<li><a href="https://austinhenley.com/blog/myhcitoolbox.html">My HCI toolbox: Methods for designing and evaluating UIs</a></li>
<li><a href="https://www.youtube.com/watch?v=Q4OIcwt8vcE">Screens in Screens in Screens</a> and other fun explorations from <a href="https://twitter.com/TodePond">Lu Wilson</a></li>
<li><a href="https://twitter.com/ancient_james/status/1545559151807692801">Little OLEDs in little Lego bricks</a></li>
<li><a href="https://www.youtube.com/watch?v=PrxhwOC9hLw">Node-based tool for procedural motion design</a></li>
</ul>
<h2>Fin</h2>
<p>I'm writing this from ORD, waiting for a flight back home after Strange Loop and Ink&#x26;Switch get-together.</p>
<p>I'm looking forward to having more free time now that Strange Loop is behind me.
I plan to spend my upcoming evenings making music, and noodling on this datalog-vector-shapes thing I mentioned in the intro — unless something more shiny catches my eye, of course.</p>
<p>In the meantime, wishing you a great autumn, and see you around in December (if not sooner)!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2022-10-03-q3-2022/</guid>
            <pubDate>Mon, 03 Oct 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q2 2022]]></title>
            <description><![CDATA[<p>Hi,</p>
<p>thanks everyone for great feedback and discussions on <a href="https://szymonkaliski.com/newsletter/2022-04-04-q1-2022/#sketching-and-programming">Inkbase</a> and <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a> — I really enjoy hearing your perspectives on this work, and it's also helpful since chatting with you all forces me to get better at articulating my intuitions.</p>
<p>I spent the last three months at <a href="https://inkandswitch.com">Ink&#x26;Switch</a> working on applying the ideas of <em>sketchiness</em> and <em>conversation with some form of other</em> to a stylus-driven logic solver.
We're only just starting to write the essay, so expect it sometime later this year.
As always, if this sounds up your alley, I'm happy to give you a demo sooner than that.
If you're reading this in your inbox, you can reply directly to this email, otherwise you can always reach me at <a href="mailto:hi@szymonkaliski.com">hi@szymonkaliski.com</a>.</p>
<p>I also managed to work on a couple of smaller side-projects: bothering <a href="https://bypaulshen.com">Paul Shen</a> to <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#use-natto">expose some of Natto internals</a>, building a simple <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#diy-document-camera">perspective-transforming document camera</a>, and playing around with a <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#3d-printing">new 3D printer</a>.</p>
<h2><code>use-natto</code></h2>
<p>I've been chatting with Paul about how <a href="https://natto.dev">Natto</a> could become useful in existing contexts.
One idea we played around with, is embedding Natto canvases into existing web applications, inspired by "<a href="https://www.youtube.com/watch?v=TqFuZLzLZfc">Long-awaited live programming</a>" talk from <a href="http://joshuahhh.com">Joshua Horowitz</a>.
Different parts of the application could be (and sometimes already are!) made of smaller DSLs, and these DSLs, in turn, could have their own development interfaces.
You shouldn't have to adopt a whole new toolchain or an experimental code editor to get some nice directly-manipulatable dev UIs.</p>
<p>Paul quickly put together <a href="https://github.com/paulshen/natto-lib/tree/main/packages/eval"><code>@nattojs/eval</code></a> which allows you to execute Natto flows outside of the web interface.
Below is a quick narrated demo of working with an external API in Natto, and bringing it into a simple React application:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/use-natto.mp4"></video>
<p>Natto recently gained <a href="https://twitter.com/_paulshen/status/1500987059581841408">multiplayer cursors</a>, and it's fun to imagine collaboratively live-coding parts of your application, and then including them in the main codebase as an asset file (these canvases are just JSON files that could be easily included in a <code>git</code> repo).
You can also imagine having a <code>DEBUG</code> flag which swaps parts of your application to be live-Natto-modifiable.</p>
<h2>DIY Document Camera</h2>
<p>As you probably know, most of the work I've been doing for a while, has been tablet-oriented.
The thing that we're constantly experimenting with are the touch-and-stylus interactions.
To visualize what's going on, we usually add an overlay showing fingers and stylus positions, but that is just a proxy for actually seeing how the application is used.</p>
<p>To mitigate this, I've built a very simple DIY document camera using:</p>
<ul>
<li>a cutting mat with four <code>ArUco</code> markers glued to the corners</li>
<li>Logitech C920 webcam</li>
<li>some old lamp arm I had lying around</li>
<li>a couple of <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#3d-printing">3D-printed pieces</a> to attach the webcam to the arm</li>
</ul>
<p>I use the <code>ArUco</code> markers for perspective transformation to fake the camera floating directly above the table.
The code itself is just about 300 lines of Python and OpenCV.
At first, I tried to prototype this in a browser using <a href="https://docs.opencv.org/3.4/d0/d84/tutorial_js_usage.html"><code>OpenCV.js</code></a> but the performance was pretty bad — which is unsurprising, as the official build is <code>emscripten</code>, not <code>wasm</code>.
I've never really tried the unofficial <code>wasm</code> build, and I just defaulted to what everyone recommends: "just use Python".</p>
<p>Here's a short demo (and a sneak peek at the "sketchy logic solver" project I mentioned in the intro):</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/document-camera-demoing.mp4"></video>
<p>And since I know the exact <code>ArUco</code> marker sizes, one additional fun experiment was adding measuring capabilities to the tool:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/document-camera-measuring.mp4"></video>
<p>Of course, this is something that <a href="https://kevinlynagh.com/cncv/">Kevin already explored in detail</a>, concluding that the accuracy is not good enough for use in a CAD context — which I agree with (forget being 1MM accurate with 1080P webcam).
I'd be curious to try this with a better camera (anyone knows of any inexpensive 4K ones that are not terrible?), but ultimately good calipers probably win here anyway.</p>
<p>While we're on the topic of webcams, I was so happy to stumble upon <a href="https://github.com/joelpurra/uvcc"><code>uvcc</code></a> which allows you to configure the Logitech-family webcams without using their clunky app.</p>
<p>Finally, I spent an afternoon trying to package this as an <code>.app</code> and failing with both <a href="http://py2app.readthedocs.io"><code>py2app</code></a> and <a href="https://pyinstaller.org/en/stable/"><code>pyinstaller</code></a>.
In the end, I made an Automator wrapper around a CLI one-liner which works great for my usecase — starting the app directly from Spotlight search.</p>
<h2>3D Printing</h2>
<p>My <a href="https://szymonkaliski.com/writing/2017-12-04-flsun-i3-3d-printer/">cheap 3D printer</a> didn't survive moving apartments — not to mention that it was incredibly fiddly, and required a lot of hand-holding to do anything.
Which is ok if you want to play around with a 3D printer, but not so great if you actually want to 3D print things.</p>
<p>My needs for printing various little designs were piling up, and I finally had enough brain-space to pick a new one.
I went with <a href="https://www.prusa3d.com/product/original-prusa-mini-kit-2/">Prusa MINI+</a>, partly because I never really print bigger things, and partly because it fits perfectly between my shelves:</p>
<img src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/prusa-mini.png" alt="Prusa MINI+ on a shelf" width="1600" height="900">
<p>I was half-expecting Prusa to be only marginally better than my old printer, but I was pleasantly surprised — after a couple of hours of assembly the only adjusting I had to do was making sure the Z-axis is correctly distanced from the heatbed.
After that I don't have to do anything other than hit "print" and wait, which is awesome.</p>
<h2>Summer Plans</h2>
<p>I'm writing this from a middle of a vacation road-trip from San Francisco to Galiano Island, where I'll spend a week at <a href="https://www.gradientretreat.com">Gradient Retreat</a>, most probably tinkering with various things.</p>
<img src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/ocean.png" alt="Ocean" width="1565" height="880">
<p>Once I'm back, I'm going to spend most of my summer as a "Researcher in Residence" at <a href="http://glideapps.com">Glide</a>, prototyping a programming environment for building custom UI components that fit with the Glide's aesthetics.
<br>Just a quick reminder — I do consulting, specializing in <em>digital tools</em> and <em>no-/low-/feature-of- computing</em> research, design &#x26; development.
<br><a href="mailto:szymon@flow-control.io">Reach out</a> if that sounds interesting.</p>
<p>I'm going back to the US in late September, this time to give a  <a href="https://thestrangeloop.com/2022/programmable-ink.html">Programmable Ink</a> talk at <a href="https://thestrangeloop.com/">Strange Loop</a> (which I'm both excited, and nervous about; not sure in which order).
<br>Hope to see some of you there!</p>
<h2>Worth Checking Out</h2>
<p>Books I enjoyed recently:</p>
<ul>
<li>computers, design, <a href="https://szymonkaliski.com/notes/cybernetics/">Cybernetic</a> conversation with the material:
<ul>
<li><a href="https://link.springer.com/book/10.1007/978-3-030-18557-2">Design Cybernetics</a></li>
<li><a href="https://www.amazon.com/Reflective-Practitioner-Professionals-Think-Action/dp/0465068782/">The Reflective Practitioner</a></li>
<li><a href="https://www.amazon.com/Sciences-Artificial-MIT-Press/dp/0262537532/">The Sciences of the Artificial</a></li>
<li><a href="https://www.amazon.com/Where-Action-MIT-Press-Foundations/dp/0262541785/">Where the Action Is</a> — some tangible computing, a bit of phenomenology and ethnomethodology, what else do you need?</li>
</ul>
</li>
<li><a href="https://www.amazon.com/Metaphors-We-Live-George-Lakoff/dp/0226468011/">Metaphors We Live By</a> and <a href="https://www.amazon.com/Women-Fire-Dangerous-Things-Categories/dp/0226468046">Women, Fire, and Dangerous Things</a> for the impact of language on thinking</li>
<li><a href="https://www.amazon.com/Peak-Secrets-New-Science-Expertise/dp/0544947223/">Peak</a> on <a href="https://szymonkaliski.com/notes/deliberate-practice/">Deliberate Practice</a></li>
<li><a href="https://www.amazon.com/Coders-Work-Reflections-Craft-Programming/dp/1430219483">Coders at Work</a> — especially interviews with Dan Ingalls, and late Joe Armstrong</li>
<li><a href="https://www.amazon.com/Toward-Theory-Instruction-Belknap-Press/dp/0674897013">Toward a Theory of Instruction</a></li>
<li><a href="https://store.v2.nl/products/art-and-computation">Art and Computation</a> — I really enjoyed the argument that computational art has to deal with, and "show", computation — and for that it has to <em>not</em> be functional, <em>not</em> <a href="https://en.wikipedia.org/wiki/Heideggerian_terminology#Ready-to-hand">ready-to-hand</a> because then it disappears</li>
</ul>
<p>On the web:</p>
<ul>
<li>if you're not fed up with hearing about <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a> yet, Ivan made a <a href="https://pod.link/1559446316/episode/c7ad6adc3d0d43a5c68370942082cb6c">podcast episode discussing how it differs from Hest</a></li>
<li><a href="https://github.com/mxgmn/MarkovJunior">WFC guy strikes again</a></li>
<li><a href="https://andrewhead.info/assets/pdf/augmented-formulas.pdf">"How Authors Enhance the Readability of Formulas using Novel Visual Design Practices"</a></li>
<li><a href="https://twitter.com/toxi/status/1518836630576144384">this is how websites should look like</a></li>
<li><a href="https://www.media.mit.edu/projects/2d-an-exploration-of-drawing-as-programming-language-featuring-ideas-from-lambda-calculus/overview/">drawing lambda calculus</a></li>
<li><a href="https://omar.website/clause-cards/">non-keyboard programming at Dynamicland</a></li>
<li>and while we're on the topic of logic solvers, <a href="https://kevinlynagh.com/pinfigurator-language/">Kevin worked on a non-"sketchy" one</a></li>
</ul>
<h2>Fin</h2>
<p>Thanks for reading — as always ping me about anything that seems interesting, and in the meantime: have a great summer!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/</guid>
            <pubDate>Mon, 04 Jul 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[DIY Document Camera]]></title>
            <description><![CDATA[<p>As I was working on <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> projects at Ink&#x26;Switch, in hopes to record better-looking demos (which never really panned out), I cobbled together some OpenCV to detect four markers glued to a cutting board.</p>
<p>You can read more about the project in the section below, which originally appeared in the <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/">Q2 2022</a> newsletter.</p>

<h2 is-transclusion-title="" class="f5 lh-copy mt5 mb2 near-black">Transcluded from <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#diy-document-camera">DIY Document Camera</a></h2>
          
<p>As you probably know, most of the work I've been doing for a while, has been tablet-oriented.
The thing that we're constantly experimenting with are the touch-and-stylus interactions.
To visualize what's going on, we usually add an overlay showing fingers and stylus positions, but that is just a proxy for actually seeing how the application is used.</p>
<p>To mitigate this, I've built a very simple DIY document camera using:</p>
<ul>
<li>a cutting mat with four <code>ArUco</code> markers glued to the corners</li>
<li>Logitech C920 webcam</li>
<li>some old lamp arm I had lying around</li>
<li>a couple of <a href="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/#3d-printing">3D-printed pieces</a> to attach the webcam to the arm</li>
</ul>
<p>I use the <code>ArUco</code> markers for perspective transformation to fake the camera floating directly above the table.
The code itself is just about 300 lines of Python and OpenCV.
At first, I tried to prototype this in a browser using <a href="https://docs.opencv.org/3.4/d0/d84/tutorial_js_usage.html"><code>OpenCV.js</code></a> but the performance was pretty bad — which is unsurprising, as the official build is <code>emscripten</code>, not <code>wasm</code>.
I've never really tried the unofficial <code>wasm</code> build, and I just defaulted to what everyone recommends: "just use Python".</p>
<p>Here's a short demo (and a sneak peek at the "sketchy logic solver" project I mentioned in the intro):</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/document-camera-demoing.mp4"></video>
<p>And since I know the exact <code>ArUco</code> marker sizes, one additional fun experiment was adding measuring capabilities to the tool:</p>
<video controls><source src="https://szymonkaliski.com/newsletter/2022-07-04-q2-2022/document-camera-measuring.mp4"></video>
<p>Of course, this is something that <a href="https://kevinlynagh.com/cncv/">Kevin already explored in detail</a>, concluding that the accuracy is not good enough for use in a CAD context — which I agree with (forget being 1MM accurate with 1080P webcam).
I'd be curious to try this with a better camera (anyone knows of any inexpensive 4K ones that are not terrible?), but ultimately good calipers probably win here anyway.</p>
<p>While we're on the topic of webcams, I was so happy to stumble upon <a href="https://github.com/joelpurra/uvcc"><code>uvcc</code></a> which allows you to configure the Logitech-family webcams without using their clunky app.</p>
<p>Finally, I spent an afternoon trying to package this as an <code>.app</code> and failing with both <a href="http://py2app.readthedocs.io"><code>py2app</code></a> and <a href="https://pyinstaller.org/en/stable/"><code>pyinstaller</code></a>.
In the end, I made an Automator wrapper around a CLI one-liner which works great for my usecase — starting the app directly from Spotlight search.</p>]]></description>
            <link>https://szymonkaliski.com/projects/diy-document-camera/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/diy-document-camera/</guid>
            <pubDate>Mon, 13 Jun 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q1 2022]]></title>
            <description><![CDATA[<p>Hi,</p>
<p>it's horrific to look at what's happening in Ukraine. It's horrific to imagine what war is like, and we are still in shock that it's happening right next to us, in our neighborhood. I've heard good things about <a href="https://razomforukraine.org">Razom</a> and that's where we've been donating, and I encourage everyone who can, to do the same.</p>
<p>We're incredibly lucky to be able to move over to nerdy computer stuff in the next paragraph.</p>
<p>I don't have that much to share on the side-projects side this time.
In January, I built a simple temperature and humidity Wi-Fi sensor for our basement, just to see if the temperatures there don't go too low, and if humidity doesn't ramp up too high. Do I need a better dehumidifier? Doesn't seem like it right now. The project is nothing exciting, just an <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a>, a sensor I had lying around, piped through <a href="https://mqtt.org">MQTT</a> to my home-server Raspberry Pi which runs a bunch of automations using <a href="https://nodered.org">Node-RED</a>, including logging the collected data into an <code>sqlite</code> database.</p>
<h2>Sketching and Programming</h2>
<p>My talk from <a href="https://liveprog.org">LIVE2021</a>, about one of our recent <a href="http://inkandswitch.com">Ink&#x26;Switch</a> projects, is finally out.
You can watch it below, it's only 10 minutes, and then there's a bit of Q&#x26;A:</p>
<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" width="1280" height="720" src="https://www.youtube.com/embed/z3axx5rZMWI" frameborder="0" allowfullscreen>
  </iframe>
</div>
<p>We're still working on the essay — I'll let you all know when it's out for sure!
In the meantime, I wanted to mention a couple of interesting learnings from this project.</p>
<p><strong><em>Sketchiness</em> of tools.</strong>
Importantly, this is not a matter of leaving hand-drawn marks, though having them helps.
This point is more about working with half-formed ideas, and a big part of it is that the <a href="https://szymonkaliski.com/notes/fidelity-of-the-tool-should-be-proportional-to-the-maturity-of-the-idea/">Fidelity of The Tool Should be Proportional to The Maturity of The Idea</a>.
Basically, computers are great at enforcing rules (<a href="https://szymonkaliski.com/notes/computer-science-positivism/">Computer Science Positivism</a>), but tools in the earliest stages of thinking, should provide the exact opposite — freedom to poke at the problem from multiple ends, freedom to leave unfinished pieces lying around in your <a href="https://szymonkaliski.com/notes/peripheral-vision-in-software/">Peripheral Vision</a>, freedom to be messy.</p>
<p><strong>Programming with live, embodied objects.</strong> There's a distinctive difference in how it <em>feels</em> to program a system where everything is represented by a visible, embodied, and responsive representations — instead of one where you refer to things by abstract names, and imagine what will happen when the program runs (by playing <a href="https://szymonkaliski.com/notes/simulator/">Simulator</a> in your head). Importantly, this is not what most of "<a href="https://szymonkaliski.com/notes/vpl/">Visual Programming</a>" (that I know of) tries to solve — these projects are usually about visualizing the structure of the program which is not as useful as <a href="https://szymonkaliski.com/notes/visualizing-the-problem-domain-is-more-useful-than-visualizing-the-program-shape/">Visualizing the Domain of the Problem</a>.</p>
<p><strong>Spatial messages as a way to communicate between embodied objects.</strong> The way that most programming was done in Inkbase was by sketching out some shapes on the canvas, and making them react to each other, by asking "what's to the right of me?", "is there anything inside that region?", etc. For example, in the demo below, the pink "wires" are not what makes the logic gates talk to each other — they are there just for user feedback. Instead, the logic gates query for what's to the left (inputs), and send the calculated values to everything that's to the right:</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2022-04-04-q1-2022/logic-gates.mp4"></video>
<p><strong>Mixing reactive data-flow and imperative mutations in the same environment.</strong> Our objects were programmed using ad-hoc lisp implementation, with a small library for push-based reactivity. The basic API was as follows:</p>
<ul>
<li>Reactive chains were set up with <code>?</code>.</li>
<li>Imperatively updating values was done with <code>!</code>.</li>
<li>You could also update a value by piping it through a lambda with <code>.</code>.</li>
</ul>
<p>Here's an example to make it bit more concrete:</p>
<pre><code class="language-clojure">(! value 5)
;; ↑ cell named "value" holds `5`

(! double-value (* (? value) 2))
;; ↑ cell "double-value" holds `10`,
;; and will update as "value" updates

(! logger (log (? double-value)))
;; ↑ `10` logged out to console

(! value 7)
;; ↑ `14` logged out to console

(! ticker (interval 1000 #(. value inc)))
;; ↑ `16`, `18`, `20`... logged out every second
</code></pre>
<p>The reality was a bit more complicated, but you hopefully get the idea from this short gist.
I think this could be a pretty useful part of the project to turn into a <code>clojure</code> library, but I'd be surprised if there wasn't anything that does this already.
I haven't dug around yet, so send me a message if you know of any!</p>
<p>Overall, the project taught me a ton, and charted a direction for a next one, that is also finished, <del>and also, as of yet, unpublished</del>.
We managed to push the essay out a couple of days ago after all!
The project is called <a href="https://szymonkaliski.com/projects/crosscut/">Crosscut</a>, and you can read about it <a href="http://inkandswitch.com/crosscut/">here</a>.
The essay is much more comprehensive than anything I would write on my own, and I encourage you to check it out — and do so on a desktop browser as we have a bunch of live demos in there.</p>
<img src="https://szymonkaliski.com/newsletter/2022-04-04-q1-2022/crosscut-on-tablet.jpg" alt="Crosscut running on a Tablet" width="1369" height="853">
<h2>Worth Checking Out</h2>
<p>Books I enjoyed recently:</p>
<ul>
<li><a href="https://www.amazon.com/How-Buildings-Learn-Happens-Theyre/dp/0140139966">How Buildings Learn: What Happens After They're Built</a> — I really enjoyed the "low road" / "high road" framing for how buildings are used, and adapted, over time; architecture always seemed to me like something "set in stone", but Brand argues that it is far from that</li>
<li><a href="https://www.amazon.com/Visual-Thinking-Rudolf-Arnheim/dp/0520242262">Visual Thinking</a> — felt a bit dated and dense, but makes a great argument on how all thinking is based in perception</li>
<li><a href="https://www.amazon.com/Story-Art-H-Gombrich/dp/0714832472/">The Story of Art</a> — great overview of how art evolved from the earliest cave paintings to modernity</li>
<li>I went on a little (mostly graphical) design thread:
<ul>
<li><a href="https://www.amazon.com/Karl-Gerstner-Designing-Programmes-Typography/dp/3037785780">Designing Programmes</a> — a cult classic in some circles, somehow didn't make that much of an impact on me, maybe because of my humble "creative coding" background where making programs to make designs is the bread-and-butter of the field</li>
<li><a href="https://www.amazon.com/Interaction-Color-Anniversary-Josef-Albers/dp/0300179359/">Interaction of Color</a></li>
<li><a href="https://www.amazon.com/Thinking-Type-2nd-revised-expanded/dp/1568989695/">Thinking With Type</a> — this one was excellent, I loved how it plays with the "form", and reminded me a bit of "Understanding Comics" — using typefaces to talk about type, in a similar way as using comic strips to talk about comics</li>
<li><a href="https://www.amazon.com/New-Program-Graphic-Design/dp/1941753213/ref=sr_1_1?crid=1IA9ILYWM25WA">A *New* Program for Graphic Design</a> — didn't go into as many details as I wished it would but still a great overview of the field</li>
<li><a href="https://www.amazon.com/Speculative-Everything-Design-Fiction-Dreaming/dp/0262019841/">Speculative Everything</a></li>
</ul>
</li>
</ul>
<p>On the web:</p>
<ul>
<li>
<p><a href="https://twitter.com/disconcision/status/1486515515090685955">Derivability in internal tools</a> — there's something interesting in here, but I can't quite put my finger on it; feels like part of tool design is figuring out what can be done in the tool-space, and what should be pushed "outside"</p>
</li>
<li>
<p>(almost) <a href="https://twitter.com/andy_matuschak/status/1494392423870435332">Myst in Figma</a></p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=40ua8NRyrro">PRIME</a> — a 3D node&#x26;wire VPL</p>
</li>
<li>
<p><a href="https://natto.dev">Natto</a> (another node&#x26;wire VPL) now has <a href="https://natto.dev/@paul/e88779123ff64547a78a122314323cf4">React state boxes</a> — I'm a huge fan of making data tangible and visible, and this is a step in the right direction</p>
</li>
<li>
<p><a href="https://christophlabacher.com/notes/ethnographic-research-on-dynamicland">Ethnographic research on Dynamicland</a></p>
</li>
<li>
<p><a href="http://paulate.github.io/tadcad/">Tangible 3D Modeling</a></p>
</li>
<li>
<p><a href="http://geoffreylitt.com">Geoffrey</a> is working on <a href="https://riffle.systems/essays/prelude/">moving all of your app state into SQLite</a> — I've built some apps this way with a ton of duct-tape, and I'm excited to see where a more thought-out approach will go!</p>
</li>
</ul>
<h2>Fin</h2>
<p>That's it for this update, as always feel free to reach out if anything in here is interesting.</p>
<p>See you in a couple of months!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2022-04-04-q1-2022/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2022-04-04-q1-2022/</guid>
            <pubDate>Mon, 04 Apr 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Crosscut]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/crosscut/crosscut-on-tablet.jpg" alt="Crosscut running on a tablet" width="1369" height="853">
<p>Crosscut is a research project developed at <a href="https://www.inkandswitch.com/">Ink&#x26;Switch</a> in the <a href="https://szymonkaliski.com/notes/programmable-ink/">Programmable Ink</a> thread together with <a href="http://wolkenmachine.nl">Marcel Goethals</a> and <a href="https://ivanish.ca">Ivan Reese</a>.
It is a spiritual continuation of our work on <a href="https://szymonkaliski.com/notes/end-user-programming/">End-User Programming</a> (with an essay <a href="http://inkandswitch.com/end-user-programming/">here</a>), and the <a href="https://szymonkaliski.com/projects/inkbase/">Inkbase</a> project.</p>
<p>As a teaser, with Crosscut you can build-to-explore things ranging from custom step sequencers:</p>
<div class="aspect-ratio aspect-ratio--4x3 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" loading="lazy" src="https://www.inkandswitch.com/crosscut/crosscut-web.html?example=Sequencer&#x26;isLibraryLocked=true&#x26;isModesLocked=true&#x26;isNoSnaps=true&#x26;isMetaUILocked=true">
  </iframe>
</div>
<p>To bookshelf-designing tools:</p>
<div class="aspect-ratio aspect-ratio--4x3 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" loading="lazy" src="https://www.inkandswitch.com/crosscut/crosscut-web.html?example=Bookshelf&#x26;isLibraryLocked=true&#x26;isModesLocked=true&#x26;isNoSnaps=true&#x26;isMetaUILocked=true">
  </iframe>
</div>
<p>To learn more, check out the <a href="https://www.inkandswitch.com/crosscut/">9000-word essay</a> covering everything from philosophy, through design goals, to the actual implementation of the prototype.</p>
<p>Crosscut was also presented during my <a href="https://www.youtube.com/watch?v=ifYuvgXZ108">2022 Strange Loop talk</a> if you want to see it in action.</p>]]></description>
            <link>https://szymonkaliski.com/projects/crosscut/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/crosscut/</guid>
            <pubDate>Tue, 29 Mar 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Crosscut ↗]]></title>
            <description><![CDATA[Drawing Dynamic Models]]></description>
            <link>https://www.inkandswitch.com/crosscut/</link>
            <guid isPermaLink="true">https://www.inkandswitch.com/crosscut/</guid>
            <pubDate>Mon, 28 Mar 2022 22:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q4 2021]]></title>
            <description><![CDATA[<p>Hi everyone, happy New Year!</p>
<p>This quarter our family grew with this little guy:</p>
<img src="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/pablo.jpg" alt="Pablo, a boxer" width="1600" height="900">
<p>His name is Pablo and he's a boxer.</p>
<p>Juggling finishing renovation of our new place, and potty training a puppy was as hard as it sounds, but we're so happy to have him around.</p>
<p>The rest of the newsletter is a quick update on what I've been up to work-wise, and short description of two side-projects — a <a href="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/#midi%E2%86%92cv">MIDI→CV</a> converter and previously unpublished <a href="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/#cartographist">experimental web browser for rabbit-holing</a>.</p>
<p>Starting with work, we just finished another <a href="https://inkandswitch.com">Ink&#x26;Switch</a> project exploring stylus-based "programming". We hope to publish soon, but we also hoped that for the previous one, and it's still not out there. Sorry.</p>
<p>As a small aside (slash ramble), "programming" is in quotes, because I really don't like that word for describing this sort of work.
I have some early illegible thoughts about this in <a href="https://szymonkaliski.com/notes/end-user-programming-vs-programming/">End-User Programming vs Programming</a> note, but the gist of it is that what I've been after in this research track is "programming" as a tool for understanding, and working with, dynamic systems — same way as a numerals and mathematical notation are tools for working with mathematical ideas.
It now seems to me that a lot of <a href="https://szymonkaliski.com/notes/future-of-coding/">Future of Coding</a> work (including most of my own!), is about making lives of "expert symbol manipulators" easier — which is definitely worthwhile — but this year I started to understand that there's a lot of value in making "working with dynamic systems" accessible to everyone, and that might need another approach than iterating from where we are right now.</p>
<p>In any case, I'm excited to share this new project with you, but it will take a while to finalize the paper. If this sounds like something you'd like to get a preview of, send me a message, and we'll set up a call.</p>
<h2>MIDI→CV</h2>
<p>I'm trying really hard to not get into <a href="https://en.wikipedia.org/wiki/Eurorack">Eurorack</a> as it looks like a great way to quickly spend a lot of money.
I really like a lot of ideas around them — the standardized form-factor, the analog 5V signal as an "API", the physicality of the modules, and the open-endedness of these systems.</p>
<p>Relatedly, one of my favourite effects is <a href="http://tomkatpedals.com/products/cloudy">Cloudy</a>, an infamous <a href="https://mutable-instruments.net/modules/clouds/">Clouds</a> module in a guitar pedal form-factor.
Aside from fitting well into my existing pedalboard, Cloudy exposes <a href="https://tomkatpedals.com/pages/expression-cv-inputs">some CV inputs</a>, and I wouldn't be myself if I didn't do anything with them.</p>
<img src="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/midi-to-cv.jpg" alt="MIDI→CV Hardware" width="1600" height="900">
<p>A couple of afternoons of soldering (<code>MCP4728</code> DAC and <code>A-Star 32U4 Micro</code> board) and light programming later, and I have a small tool for converting MIDI CC messages into a 0-5V signal. Of course, I'm loosing a lot of the resolution by upscaling <code>0-127</code> to the analog range, but that doesn't matter much here. It so fun being able to add additional movement and modulation into the sounds that Cloudy makes, and with eight outputs I have some room for growth here.</p>
<h2>Cartographist</h2>
<p>During the summer of 2020 I played around with an idea for research-focused web browser, embodying some of the concepts from <a href="https://szymonkaliski.com/notes/browsing-vs-searching/">Browsing vs Searching</a> note — <em>browsing</em> being an open-ended divergent activity, and <em>searching</em> understood as information retrieval.</p>
<video autoplay muted loop><source src="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/cartographist.mp4"></video>
<p><a href="https://twitter.com/szymon_k/status/1289942401318977537">I shared a preview on Twitter</a>, to a surprisingly overwhelming response, but I got distracted with other things and never got back to the project. I still occasionally get requests for sharing this, so here it is: <a href="https://github.com/szymonkaliski/cartographist">szymonkaliski/Cartographist</a>.</p>
<p>The main idea of browsing in panes was inspired by <a href="http://andymatuschak.org">Andy Matuschak's website layout</a> and some of <a href="http://nateparrott.com">Nate Parrot's</a> experiments around stacking mobile web browser views next to each other (which I can't seem to find anymore, sorry).
This sort of layout has a long history, starting with <a href="https://en.wikipedia.org/wiki/Miller_columns">Miller columns</a> and the original Smalltalk class browser, and is a great interface for detail-in-context browsing.</p>
<p>As an aside, I also use this technique for navigating code with Vim, where a single shortcut goes to a definition of a function in a new pane:</p>
<img src="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/vim-panes.jpg" alt="Vim panes screenshot" width="3536" height="1790">
<p>(<a href="https://gtoolkit.com">Glamorous Toolkit</a> is worth checking out, as it takes the idea of pane browsing to another level)</p>
<p>In theory, I also really like the idea of disk-persisted history which allows for going back to a browsing session after a while, and consciously deciding which "topic" I am in.</p>
<p>Unfortunately, in practice, I don't think having the full history is that useful.
Yes, it's sometimes good to know how you ended up somewhere, but I think what's most valuable about "research" is the synthesis part — grabbing parts of larger wholes, rearranging, recombining, thinking with the material.
A small step in this direction could be persisting scroll position or maybe selection, and making the history editable — allowing users to remove dead ends, add notes, etc.</p>
<p>Additionally, it started to feel that I'm solving this problem on a wrong level.
For example, a good window manager could replace Cartographist almost completely —
I played around with columnar layout in <a href="https://szymonkaliski.com/projects/hhtwm/">HHTWM</a> for a bit, but lack of horizontal scrolling makes it not that useful in the end.</p>
<p>Well, let me know if you have any ideas how to make Cartographist better! Is there anything interesting here that I'm not seeing? Could it be useful to you in any way?</p>
<h2>Worth Checking Out</h2>
<p>Books I enjoyed recently:</p>
<ul>
<li><a href="https://www.amazon.com/Digital-Design-Crafting-Technology-Environments/dp/0500289018">Digital by Design</a> — a really cool interactive art album</li>
<li><a href="https://www.rewiringamerica.org">Rewiring America</a> — a great take on how to stop our carbon emissions with currently existing technologies</li>
<li><a href="https://www.amazon.com/Over-Our-Heads-Mental-Demands/dp/0674445880">In Over Our Heads</a> — I read this as a way to better understand the context of <a href="https://metarationality.com">In The Cells of the Eggplant</a></li>
<li><a href="https://mitpress.mit.edu/books/embodied-mind">The Embodied Mind</a> — this book was a riot, highly recommended! — I loved combining ideas from Buddhism (like mindfulness meditation), and phenomenology as tools for understanding human experience (hat tip to <a href="http://wolkenmachine.nl">Marcel Goethals</a>)</li>
<li>I had fun doing <a href="https://szymonkaliski.com/notes/syntopic-reading/">Syntopic Reading</a> on philosophy of science:
<ul>
<li><a href="https://www.amazon.com/What-Science-How-Really-Works/dp/1108701647">What Science Is and How It Really Works</a></li>
<li><a href="https://www.amazon.com/Against-Method-Paul-Feyerabend/dp/1844674428/">Against Method</a></li>
<li><a href="https://www.amazon.com/Scientific-Method-Evolution-Thinking-Darwin/dp/0674976193/">The Scientific Method</a></li>
<li><a href="https://www.amazon.com/Creativity-Science-Chance-Genius-Zeitgeist/dp/0521835798/">Creativity in Science</a></li>
</ul>
</li>
</ul>
<p>On the web:</p>
<ul>
<li>Kevin Lynagh has been on a roll lately, <a href="https://kevinlynagh.com/newsletter/2021_11_millifludic_update/">researching DIY microfluidics</a> and building a <a href="https://kevinlynagh.com/pcb-stepper/">PCB stepper motor</a></li>
<li>two new cool visual programming languages: <a href="https://github.com/samuelmtimbo/unit">Unit</a> and <a href="http://circles.software">Circles</a></li>
<li>great interactive explainer of <a href="https://ciechanow.ski/curves-and-surfaces/">Curves and Surfaces</a></li>
<li>Peter van Hardenberg (current head of Ink&#x26;Switch) <a href="https://museapp.com/podcast/46-industrial-research/">appeared on the Muse podcast</a> — he is much better at articulating what we do at Ink&#x26;Switch than I am, so it's worth checking out if you're curious</li>
</ul>
<h2>Fin</h2>
<p>Thanks everyone for all the thoughtful discussions and great collaborations this year.</p>
<p>Wishing you all the best for 2022!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/</guid>
            <pubDate>Mon, 03 Jan 2022 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cartographist]]></title>
            <description><![CDATA[<p>Cartographist is an experimental web browser optimized for rabbit-holing.</p>
<img src="https://szymonkaliski.com/projects/cartographist/miniature.jpg" alt="Cartographist Screenshot" width="1280" height="720">
<ul>
<li>Instead of opening new windows (with <code>cmd</code>-click), Cartographist spawns horizontally scrollable panes.</li>
<li>Instead of forcing you to find things in a linear history, Cartographist shows a tree-structured outline of your browsing:
<img src="https://szymonkaliski.com/projects/cartographist/history.jpg" alt="Browsing history" width="720" height="280"></li>
<li>Instead of always starting fresh, Cartographist can save, and load "trails" — the exact state of the session you've left — supporting researching topics over long periods of time.</li>
</ul>
<p>For more context about the project, you can check out the longer write-up below, which originally appeared as a part of <a href="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/">Q4 2021</a> newsletter.</p>

<h2 is-transclusion-title="" class="f5 lh-copy mt5 mb2 near-black">Transcluded from <a href="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/#cartographist">Cartographist</a></h2>
          
<p>During the summer of 2020 I played around with an idea for research-focused web browser, embodying some of the concepts from <a href="https://szymonkaliski.com/notes/browsing-vs-searching/">Browsing vs Searching</a> note — <em>browsing</em> being an open-ended divergent activity, and <em>searching</em> understood as information retrieval.</p>
<video autoplay muted loop><source src="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/cartographist.mp4"></video>
<p><a href="https://twitter.com/szymon_k/status/1289942401318977537">I shared a preview on Twitter</a>, to a surprisingly overwhelming response, but I got distracted with other things and never got back to the project. I still occasionally get requests for sharing this, so here it is: <a href="https://github.com/szymonkaliski/cartographist">szymonkaliski/Cartographist</a>.</p>
<p>The main idea of browsing in panes was inspired by <a href="http://andymatuschak.org">Andy Matuschak's website layout</a> and some of <a href="http://nateparrott.com">Nate Parrot's</a> experiments around stacking mobile web browser views next to each other (which I can't seem to find anymore, sorry).
This sort of layout has a long history, starting with <a href="https://en.wikipedia.org/wiki/Miller_columns">Miller columns</a> and the original Smalltalk class browser, and is a great interface for detail-in-context browsing.</p>
<p>As an aside, I also use this technique for navigating code with Vim, where a single shortcut goes to a definition of a function in a new pane:</p>
<img src="https://szymonkaliski.com/newsletter/2022-01-03-q4-2021/vim-panes.jpg" alt="Vim panes screenshot" width="3536" height="1790">
<p>(<a href="https://gtoolkit.com">Glamorous Toolkit</a> is worth checking out, as it takes the idea of pane browsing to another level)</p>
<p>In theory, I also really like the idea of disk-persisted history which allows for going back to a browsing session after a while, and consciously deciding which "topic" I am in.</p>
<p>Unfortunately, in practice, I don't think having the full history is that useful.
Yes, it's sometimes good to know how you ended up somewhere, but I think what's most valuable about "research" is the synthesis part — grabbing parts of larger wholes, rearranging, recombining, thinking with the material.
A small step in this direction could be persisting scroll position or maybe selection, and making the history editable — allowing users to remove dead ends, add notes, etc.</p>
<p>Additionally, it started to feel that I'm solving this problem on a wrong level.
For example, a good window manager could replace Cartographist almost completely —
I played around with columnar layout in <a href="https://szymonkaliski.com/projects/hhtwm/">HHTWM</a> for a bit, but lack of horizontal scrolling makes it not that useful in the end.</p>
<p>Well, let me know if you have any ideas how to make Cartographist better! Is there anything interesting here that I'm not seeing? Could it be useful to you in any way?</p>
<hr>
<p>Code is open sourced: <a href="https://github.com/szymonkaliski/cartographist">szymonkaliski/Cartographist</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/cartographist/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/cartographist/</guid>
            <pubDate>Wed, 22 Dec 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q3 2021]]></title>
            <description><![CDATA[<p>Hi everyone, what a quarter this was!</p>
<p>The big "real-life" project which I mentioned briefly in <a href="https://szymonkaliski.com/newsletter/2021-06-28-q2-2021/">the last newsletter</a> kinda concluded.
We're now, finally, living in our new apartment, after 18 months of renovation and construction work, and three years after buying it (in a pretty desolated state).
There's still so much to do, but that's how renovations go. At least so I've been told.</p>
<p>It was a long, tiring and frustrating process, but so totally worth it.</p>
<img src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/sleep.jpg" alt="Sleep" width="1920" height="1080">
<p>On the work side, we finished a <em>programmable ink</em> project at Ink&#x26;Switch.
We're going to present it during the <a href="http://liveprog.org">LIVE 2021 workshop</a> at <a href="http://splashcon.org">SPLASH</a>, and we're still working on the final essay which should be out later this year.</p>
<p>We also started ramping up to another project in the <a href="https://szymonkaliski.com/notes/end-user-programming/">End-User Programming</a> track; there even was a job posting, which you could see, if you <a href="http://twitter.com/szymon_k">follow me on Twitter</a>.</p>
<p>The rest of this newsletter is about my new album, and an experimental interface for collection browsing.</p>
<h2>Gaze Into The Sun</h2>
<p>A bit of backstory first.</p>
<p>Making music was what originally led me to learn programming.
When I got interested in making experimental music, <a href="https://www.ableton.com/en/live/">Ableton Live</a> was the only thing I had — but everything I was making with it, sounded like, well, Ableton Live.
Luckily just around that time <a href="https://www.ableton.com/en/live/max-for-live/">Max for Live</a> was added — a way to embed <a href="https://cycling74.com">Max/MSP</a> code inside Ableton Live devices.
I started re-building various audio effects with my own quirks — a delay with miscalculated time (so it would "drift" a bit), a looper with tons of weird options (and a lot of audio cracks when the loop was readjusted), etc.</p>
<p>Building my own tools was a big part of recording my first album: <a href="https://szymonkaliski.com/music/#discopgraphy">Out Of Forgetting</a>, released on the <a href="http://www.audiobulb.com">Audiobulb</a> label in 2010. Since then, I released an EP, and another full length album, and then nothing happened for a long while.</p>
<p>I played a couple of shows every year, and released single tracks and remixes here and there over the last ten years, but I couldn't finish (or even get to the middle really) any new bigger audio work.
I've been collecting material for what feels like forever, and when the pandemic hit last year, and everything slowed down, I also had more brain-space to focus on music.</p>
<img src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/album-gaze-into-the-sun.png" alt="Gaze Into The Sun: Physical Copy Photo" width="1250" height="703">
<p>I spent almost every weekend working on new, and old, tracks.
I think the process was also kinda therapeutic for me, or maybe self-pacifying in a sense, I'm not sure.</p>
<p>Once things felt complete, I decided on a whim to share the material with a label that I've been a fan of for a while: <a href="https://www.fluidaudio.co.uk">Fluid Audio</a>.
Dan replied just a day later, and a couple of months after that — here we are — my new full-length album, first one in almost ten years, is available for listening!</p>
<p>I don't think there are any <a href="https://www.fluidaudio.co.uk/product/szymon-kaliski-gaze-into-the-sun">physical copies</a> available anymore, but you can always get <a href="https://facture.bandcamp.com/album/gaze-into-the-sun">the digital version</a>.</p>
<h2>Collection Browsing</h2>
<p>Reference material and prior art is an important part of research and design work — and since research and design is what I now spend most of my time on, it's important to me to deal with all the different snippets I keep on collecting.
I use two online platforms for storing things for later: Pinterest where my main visual references end up, and Pinboard for links to articles and interesting websites.
I also take a lot of screenshots and store them all, permanently, in a folder on my hard drive.</p>
<p>These materials are important for my work, and I was worried that since online services tend to change and disappear over time, I <del>might</del> will lose them sooner or later, so a while ago I built a tool for backing all of this up called <a href="https://szymonkaliski.com/projects/archivist/">Archivist</a>.</p>
<p>One problem with the original UI to Archivist is that there's no way to <em>see everything, all at once</em>.
I can either scroll and see a couple of images at the same time, or remember the right phrase to search for — this is the main difference of <a href="https://szymonkaliski.com/notes/browsing-vs-searching/">Browsing vs Searching</a>.</p>
<p>You <em>search</em> for a specific thing, and you <em>browse</em> in an open-ended fashion.</p>
<p>I wanted to <em>browse</em> my Archivist collections.</p>
<p>In general, I'm pretty sceptical about <code>UMAP</code> and other ML-y things. I played around with a couple of online "browsers", but they are often used for artificial data (usually the infamous <a href="https://en.wikipedia.org/wiki/Iris_flower_data_set">Iris flower data set</a>), or for collections that I didn't make myself, so I have little emotional attachment to them.
But, the ability to zoom out to see the whole collection was very compelling, so I decided to try this on my own data.</p>
<p><em>Archivist Browser</em> (obviously I'm terrible at naming) is a way to browse Archivist collection using the <code>UMAP</code> embedding combined with a high-performance UI.</p>
<p>You can fluidly zoom through the whole collection:</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/archivist-browser-zoom.mp4"></video>
<p>Since images often occlude each other, there's a fisheye distortion around a mouse cursor, which has been useful enough not to need any more sophisticated ways of dealing with this issue yet:</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/archivist-browser-picking-occluded-image.mp4"></video>
<p>Finally, you can get to the source of the image you're hovering over:</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/archivist-browser-opening-source.mp4"></video>
<p>So far I've been using it to rediscover old materials that I forgot about — <code>UMAP</code> seems to be very good at clustering visually similar items together.</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/archivist-organic-forms.png" width="995" height="995">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/archivist-weird-electronics.png" width="1191" height="1191">
  </div>
</div>
<p>The data-processing pipeline is implemented in <code>node.js</code> using <a href="https://www.tensorflow.org/js"><code>TensorFlow.js</code></a> and <a href="https://github.com/PAIR-code/umap-js"><code>umap-js</code></a> libraries, and the frontend is written in Rust using <a href="http://nannou.cc"><code>Nannou</code></a> framework.</p>
<h2>Worth Checking Out</h2>
<p>Books I enjoyed recently:</p>
<ul>
<li><a href="https://www.amazon.com/Computers-Theatre-2nd-Brenda-Laurel/dp/0321918622">Computers as Theatre</a> — an interesting look at user interfaces through the lens of theatre, and how we should focus not only on "thinking" but also "emotions" when designing them.</li>
<li><a href="https://www.amazon.com/Tools-Thought-History-Mind-Expanding-Technology/dp/0262681153/">Tools for Thought</a> — another history-of-personal-computing book, I think I preferred The Dream Machine for that though.</li>
<li><a href="https://www.amazon.com/Understanding-Computers-Cognition-Foundation-Design/dp/0201112973">Understanding Computers and Cognition</a> — Heidegger's Phenomenology applied to designing computer systems. Not the lightest read out there, but highly recommended!</li>
<li><a href="https://www.wiley.com/en-us/Computational+Design+Thinking%3A+Computation+Design+Thinking-p-9780470665701">Computational Design Thinking</a> — hat tip to <a href="http://gordonbrander.com">Gordon Brander</a>, a great collection of essays on, well, computational design.</li>
<li><a href="https://www.amazon.com/Creative-Selection-Inside-Apples-Process/dp/1250194466">Creative Selection</a> — a lighter read about the design process at Apple. Some ideas there seem to be similar to what I talked about in my <a href="https://www.youtube.com/watch?v=U29D5M7GoY8">On Rigor in Design &#x26; Research</a> talk. Being able to <em>design</em> the <em>design process</em> still tickles my mind in funny ways.</li>
<li><a href="https://www.routledge.com/Epistemology-Contemporary-Readings/Huemer/p/book/9780415259217">Epistemology: Contemporary Readings</a> — collection of Epistemology writings organised under most important concepts for the field: from perception, through problems of induction, to how knowledge works. This got me interested in the Philosophy of Science, so I grabbed the classic <a href="https://en.wikipedia.org/wiki/The_Structure_of_Scientific_Revolutions">Structure of Scientific Revolutions</a>, and I'm currently in the middle of <a href="https://www.amazon.com/What-Science-How-Really-Works/dp/1108701647">What Science is and How it really works</a> (thanks <a href="https://dubroy.com/">Patrick</a> for the recommendation).</li>
<li><a href="https://www.amazon.com/Thinking-Systems-Donella-H-Meadows/dp/1603580557/">Thinking in Systems</a> — yet another classic, definitely worth a read as an introduction to systems modelling.</li>
<li><a href="https://www.hup.harvard.edu/catalog.php?isbn=9780674744431">Unflattening</a> — a doctoral dissertation in a form of a comic book, talks about points of view and how having more than one "unflattens" our understanding of things.</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="http://makespace.fun">MakeSpace</a> (<a href="https://szymonkaliski.com/newsletter/2021-03-29-q1-2021/#work">which I helped build</a>) is now <a href="http://sprout.place">Sprout</a> and available for free, check it out!</li>
<li><a href="https://kevinlynagh.com/newsletter/2021_08_decarbonization/">Kevin Lynagh on Decarbonization</a></li>
<li><a href="https://drossbucket.com/2021/06/30/hacker-news-folk-wisdom-on-visual-programming/">Hacker News folk wisdom on visual programming</a> — an analysis of what Hacker News generally has to say about "visual programming"</li>
<li><a href="https://pair-code.github.io/understanding-umap/">Understanding UMAP</a> — which was very helpful for the Archivist Browser project presented above</li>
<li><a href="https://www.youtube.com/watch?v=7SOv9zntnMY">DeepUI Vector</a> — four years after the infamous <a href="https://www.youtube.com/watch?v=Gy5m091fOTU">DeepUI Concept Video</a> we're finally getting a glimpse at a new prototype!</li>
<li><a href="https://observablehq.com/@tophtucker/classic-research-in-data-visualization">Classic Research in Data Visualization</a> — great list of academic research papers on visualizing data</li>
<li><a href="https://ludotune.com">3D "sequencer" for making music</a></li>
</ul>
<h2>Fin</h2>
<p>I still can't believe I'm writing this from a couch of an apartment that we actually own.</p>
<p>Always happy to hear your thoughts,
see you around in December!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2021-09-27-q3-2021/</guid>
            <pubDate>Mon, 27 Sep 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q2 2021]]></title>
            <description><![CDATA[<p>Hi everyone!</p>
<p>Most of my time over the last three months went into Ink&#x26;Switch, where we were ramping up on a new project, culminating some of the research I've been involved in for the past year. We're also finishing (hopefully!) a big "real-life" project, so there wasn't that much time for side-explorations, but I managed to squeeze in two smaller things that might be interesting to some of you.</p>
<p>At <a href="https://freeze.app">Freezeframe</a> we sent out first alpha release to friends &#x26; family, it's exciting to get feedback from other people using our small workspace refrigerator. More info coming soon!</p>
<h2>Executing Incomplete Programs</h2>
<p>The consensus in the "serious programming" crowd seems to be that working with strict types and strict compilers is a good thing, and as a serious developer, you should learn to read the error messages, and work with the compiler to write your program; and then, once it compiles successfully, it works correctly.</p>
<p>I never learned to be patient, and I much prefer a program that does something, even if it does that thing incorrectly.
<a href="https://twitter.com/geoffreylitt/status/1192090985318289408">I'm not alone with this, as a friend pointed out</a>:</p>
<blockquote>
<p>A running program, even if not correct, feels closer to working than a program that doesn't run at all</p>
</blockquote>
<p>Running incomplete programs with type checking is still an open research topic, one of the most famous examples being <a href="https://hazel.org">Hazel</a>, which not only allows you to run unfinished programs, but can also (partially) type check them! It's definitely worth looking into, but: one — it's a research project, and two — a totally new universe to adopt (which you probably shouldn't do right now, because of the first point).</p>
<p>I was wondering if there's a small step I could take in that direction, with an already existing language. JavaScript maybe isn't an obvious answer here, but it has two rarely used features (some would argue, anti-patterns), that allowed me to hack a quick experiment together:</p>
<ol>
<li>
<p><code>with</code> — which extends the scope with the provided object, for example:</p>
<pre><code class="language-js">with (Math) {
  // notice that we don't have to use Math.sin or Math.PI
  const x = sin(2 * PI);
}
</code></pre>
</li>
<li>
<p><code>Proxy</code> — which allows you to intercept and overwrite fundamental operations on a given object, for example:</p>
<pre><code class="language-js">const obj = new Proxy({}, {
  get(_, property) {
    return `you requested: ${property}`;
  }
});

console.log(obj.hello);
// => you requested: hello
console.log(obj.world);
// => you requested: world
</code></pre>
</li>
</ol>
<p>You can combine these two, in a way where every <code>get</code> or <code>apply</code> returns the same <code>Proxy</code> object, creating infinite chains that never fail. Then, you can put that object in <code>with (...)</code>, so any time you call for something that doesn't exist, you will get that <code>Proxy</code> object, which will evaluate to itself.
This solution obviously doesn't type check in any way, but it's a fun experience to work on a program that (almost) always runs, even if you didn't finish writing it, and it's interesting to see how powerful vanilla JavaScript can be.</p>
<p>Below is a quick demo of building a small React component with immediate feedback and no <code>_ is not defined</code> errors popping up randomly:</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2021-06-28-q2-2021/with-holes.mp4"></video>
<h2>Magic Lenses</h2>
<p>The second experiment was inspired by research on <a href="https://www.billbuxton.com/tgml93.html">Toolglass and Magic Lenses</a> by <a href="https://www.billbuxton.com">Bill Buxton</a> et al.</p>
<blockquote>
<p>Toolglass widgets are new user interface tools that can appear, as though on a transparent sheet of glass, between an application and a traditional cursor.</p>
</blockquote>
<p>I've been interested in taking a stab at implementing a system like this ever since seeing various takes on it from <a href="http://www.tinlizzie.org/~awarth/">Alex Warth</a> and <a href="https://dubroy.com/blog/sketches-from-cdg/">Patrick Dubroy</a>.  Here's how far I've gotten in a couple of afternoons:</p>
<video controls muted><source src="https://szymonkaliski.com/newsletter/2021-06-28-q2-2021/magic-lenses.mp4"></video>
<p>I found out a couple of interesting things. First of all, magic lenses are fun to use, and feel distinctively <em>different</em> to what most of the computing is like right now. Because the transformations are pure functions (they don't destroy the underlying material, just like a physical lens wouldn't), you can experiment without any fear of losing the original data. You also often get unexpected results, which is great for <a href="https://szymonkaliski.com/notes/novelty-search/">Novelty Search</a>.</p>
<p>Not everything is great though. It's often hard to say what's going on with multiple overlapping toolglasses, and if the interaction is best understood with no more than one-two lenses, then it might imply, that some other UI primitive could work just as well (or even better). Additionally, <code>z-order</code> matters for the output (<code>stroke blue → mirror</code> results in different image than <code>mirror → stroke blue</code>), and I couldn't find a nice way to visualize that ordering. Making a side-pane hierarchy UI didn't feel right, and automatically reordering <code>z</code> axis on interaction was even more confusing.</p>
<h2>Worth Checking Out</h2>
<p>Books I enjoyed recently:</p>
<ul>
<li><a href="https://mitpress.mit.edu/books/new-media-reader">The New Media Reader</a> — it seems as if I was subconsciously collecting the works combined in this book for past couple of years; also, any book on technology that starts with a short story from Borges is worth checking out; <a href="https://twitter.com/szymon_k/status/1385651422205730817">I'm not alone in praising this book</a>, and if you were to pick just one of the things I'm recommending, this should be it</li>
<li><a href="https://mitpress.mit.edu/books/hci-remixed">HCI Remixed</a> — collection of famous HCI practitioner's essays on papers that were most influential for them; the book was a bit uneven for my taste, some writings felt like a summary of the underlying material, where some of them gave me new, interesting  points of view</li>
<li><a href="https://www.amazon.com/Act-Creation-Arthur-Koestler/dp/1939438985">The Act of Creation</a> — cult classic on where breakthroughs come from; quite long but inviting read, going into a ton of historical tangents all circling around the topic of <a href="https://szymonkaliski.com/notes/where-do-ideas-come-from/">Where Do Ideas Come From?</a>
<ul>
<li>I also read <a href="https://www.amazon.com/Art-Fear-Observations-Rewards-Artmaking/dp/0961454733">Art &#x26; Fear</a> which is almost an antithesis to "The Act of Creation", stating that art comes from repeatedly "walking the walk", which I think Koestler would agree, is just one of the "magic ingredients"</li>
</ul>
</li>
<li>three nicely complementary readings around "rationality":
<ul>
<li><a href="https://www.amazon.com/Philosophers-Toolkit-Peter-S-Fosl-dp-1119103215/dp/1119103215/">The Philosopher's Toolkit</a> — as the title suggests, it's a set of tools for making, thinking about, and evaluating (philosophical) arguments; probably not very useful on its own, but often gives an interesting framing of more and less famous philosophical arguments</li>
<li><a href="https://www.amazon.com/Scout-Mindset-Perils-Defensive-Thinking/dp/0735217556/">The Scout Mindset</a> — a bit of a lighter read on why "if only <em>they</em> were rational they would understand" is often the wrong framing of a problem</li>
<li><a href="https://metarationality.com">In the Cells of the Eggplant</a> — it's the first time I read work-in-progress book (well, what is available right now); even if only partially written, it presents an interesting take on how to be rational about rationality itself</li>
</ul>
</li>
<li>in my philosophy thread I made a detour into logic:
<ul>
<li><a href="https://www.amazon.com/Logicomix-search-truth-Apostolos-Doxiadis/dp/1596914521">Logicomix</a> — a very light introduction to the topic through the lens of Bertrand Russel's life, in a form of a comic book</li>
<li><a href="https://milneopentextbooks.org/concise-introduction-to-logic/">A Concise Introduction to Logic</a> — a bit more formal introduction to most topics around formal logic, a good jumping-off point into further reading</li>
<li>I skimmed <a href="https://www.amazon.com/Introduction-Mathematical-Logic-Dover-Mathematics/dp/0486497852">An Introduction to Mathematical Logic</a> which I'll for sure revisit once I want to explore a bit more of the mathematical side of logic</li>
<li>"Sets, Logic, Computation", "Incompleteness and Computability", and "Boxes and Diamonds" from <a href="http://builds.openlogicproject.org">Open Logic Project</a> — again partially skimmed those, but I really enjoyed the journey from formal logic, through lambda calculus, to modern computation</li>
</ul>
</li>
</ul>
<p>On the web:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=rsCul1sp4hQ">Monkey Mind Pong</a></li>
<li><a href="https://www.youtube.com/watch?v=goePYJ74Ydg">Simulating Green Beard Altruism</a> — the channel has a ton of great simulation-driven explainers, which make me think again how useful a general purpose <a href="https://szymonkaliski.com/notes/simulator/">Simulator</a> could be</li>
<li>a great essay on <a href="https://www.mollymielke.com/cc">Computers and Creativity</a></li>
<li><a href="https://se.cs.ubc.ca/compiler-viz/index.html">visualising compilation passes</a></li>
</ul>
<h2>Fin</h2>
<p>What do you think about this shorter style compared to <a href="https://szymonkaliski.com/newsletter/2021-03-29-q1-2021/">the previous one</a>?</p>
<p>Always curious to hear your thoughts and comments on any of the topics I mention. And in the meantime — see you in a couple of months!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2021-06-28-q2-2021/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2021-06-28-q2-2021/</guid>
            <pubDate>Mon, 28 Jun 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Q1 2021]]></title>
            <description><![CDATA[<p>Hi everyone!</p>
<p>I'm surprised by how much can happen in just three months; below is an update of what I've been up to, random thoughts, and things worth checking out.</p>
<h2>Work</h2>
<p>I finished my contract with <a href="https://makespace.fun">MakeSpace</a> in February, I can't wait for the project to become public so you can play with it — it's so much fun to meet <em>in a space</em>, bring notes and images with you, and see what others are looking at. The project reminds me a lot of the <a href="https://www.dougengelbart.org/content/view/131/">original Engelbartian vision of collaboration</a> — a multiplayer <a href="https://szymonkaliski.com/notes/canvas-for-thinking/">Canvas for Thinking</a>.</p>
<p>I worked on a couple of things with the team — starting with helping figure out some of the main questions for the product, that would guide the technology choices. Next big one was figuring out the actual engineering needed to bring that vision to the web. I've built four different rendering backend prototypes, so we'd be able to compare the performance and their advantages/disadvantages — from basic DOM rendering, through 2D <code>&#x3C;canvas></code>, to WebGL — including tricks like culling the viewport while still using the native browser scrollbars for accessibility. Quick, and quite unsurprising realisation is, that as difficulty grows, we can get more performance out of the web stack (we got to 10.000 items on a 5000x3000px canvas at 60FPS, without going to WASM).</p>
<p>We also had fun in the space itself, one of the experiments with biggest <em>impact-to-implementation-difficulty</em> ratio was a styling block, echoing how customisation was done in the MySpace times — by injecting snippets of global CSS. <a href="https://szymonkaliski.com/notes/end-user-programming-should-be-task-oriented/">Task-Oriented End-User Programming</a> at its finest. Since MakeSpace is built on top of <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">CRDT</a>, these changes propagate to all users in a given space, which allowed us to live-code the UI from within MakeSpace itself, or have each users' notes styled differently (by adding a <code>.user-${username}</code> CSS class so it can be targeted with a custom selector).</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/newsletter/2021-03-29-q1-2021/makespace-01.png" width="600" height="600">
  </div>
  <div class="w-100 mh1">
    <img src="https://szymonkaliski.com/newsletter/2021-03-29-q1-2021/makespace-02.png" width="600" height="600">
  </div>
</div>
<p>At <a href="https://flow-control.io">flow/control</a>, we finished a bit more conceptual consulting project with <a href="http://clay.run">Clay</a>. We worked on exploratory research on <em>integrations</em> and <em>enrichments</em> — basically how to make Clay a central point for connecting various web applications through a end-user programmable spreadsheet.</p>
<p>As for what's next? I'm going to spend a couple of months with <a href="https://www.inkandswitch.com">Ink&#x26;Switch</a> as a principal investigator. I'm excited for the opportunity to lead research projects aligned with my <a href="https://szymonkaliski.com/notes/">personal agenda</a>.</p>
<h2>Haze</h2>
<p>I've had an urge to make some new music software for a while, and the idea of granular looper has been going through my head since <a href="https://szymonkaliski.com/projects/nott/">Nótt</a> (which featured a custom granulation mode). I grabbed <a href="https://www.midifighter.com/#Twister">Midi Fighter Twister</a> and <a href="https://monome.org/docs/norns/">Norns</a> and wrote some Lua and <a href="https://supercollider.github.io">SuperCollider</a> code to make <a href="https://szymonkaliski.com/projects/haze/">Haze</a>:</p>
<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://player.vimeo.com/video/513390690?color=FFF&#x26;title=0&#x26;byline=0&#x26;portrait=0" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>I wouldn't be myself if, along the way, I didn't build some helper tools. <a href="https://github.com/szymonkaliski/maiden-remote-repl"><code>maiden-remote-repl</code></a> is an extremely simple remote REPL connection to Maiden (a process that provides Lua REPL on Norns). Combining it with file watch script and <code>rsync</code> allowed me to live reload Haze on the hardware — which sped up the actual work by a lot. It's also fun to see the UI refresh almost immediately after saving a file on my laptop. In my experience, spending time on making the project development feedback loop as short and frictionless as possible always pays out.</p>
<p>If all goes well, I should have some exciting music news to share soon.</p>
<h2>Freezeframe</h2>
<p>I've been working on <a href="http://freeze.app">Freezeframe</a> together with <a href="http://jasonyuan.design">Jason Yuan</a> and <a href="https://www.ty.works">Tyler Angert</a> in hiding for a while now. We decided to <a href="https://twitter.com/getFreezeframe/status/1358805285393948673">tease it a bit in February</a>:</p>
<div class="aspect-ratio aspect-ratio--8x5 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://player.vimeo.com/video/509684619?color=FFF&#x26;title=0&#x26;byline=0&#x26;portrait=0" width="1280" height="800" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>Freezeframe is a way to capture and restore your workspaces — opened applications, windows with tabs and documents (where possible), including their spatial layout. I've wished for something like this to exist for a while, and I used to create various crutches to make parts of it happen: from writing AppleScripts to capture Safari tabs to a markdown file, through shell scripts to open multiple applications based on specific project. I'm excited for a unified interface that replaces all of this for me.</p>
<p>This project grew in part out of my experiments with <a href="https://szymonkaliski.com/projects/hhtwm/">making a tiling window manager for macOS</a>, and trying to bend the OS to my will with my over-engineered <a href="https://github.com/szymonkaliski/dotfiles/tree/master/Dotfiles/hammerspoon">Hammerspoon config</a>. I have at least one friend who would ask if I was "playing around" or doing "actual work" — turns out I was doing both.</p>
<p>We're currently working towards an alpha release.</p>
<h2>Personal Experiments</h2>
<p>Finally, something a bit less technical, still nerdy, just on another axis. For almost a year now, I've been running "personal experiments" on myself. I actually used to say <em>I'm experimenting with ...</em> for a long time, but it was more of a figure of speech than anything else. My main issues were:</p>
<ul>
<li>forgetting that what I'm doing is temporary and that I can change my mind later</li>
<li>forgetting to systematically review and make decisions based on the "experiments"</li>
</ul>
<p>Luckily I didn't have to look for new software to solve my problems, but I had to devise an algorithm (an <a href="https://notes.andymatuschak.org/z53fk5XwrsnueNDDCq6WNe2VbPhrDGQmmVgNS">Executable Strategy</a> after Andy Matuschak). I started creating special notes which contain:</p>
<ul>
<li>the main idea that I'm experimenting with</li>
<li>the goals — why am I doing this, what do I hope to achieve/change, what's the ideal outcome</li>
<li>scheduled checkpoints</li>
</ul>
<p>With checkpoints, I usually leave some questions for myself, so I can compare my previous thinking with my current one. So far I've "completed" about ten experiments, and have a couple currently running (with these regular newsletters being one of them).</p>
<p>I backtracked on some (like not using an alarm clock in the morning), paused two (because my situation has changed), and overall allowed myself to try, what feels to me as "wilder", things out — like capping the amount of hours I'm allowed to work daily, or not allowing myself on the internet before spending some time on <a href="https://szymonkaliski.com/notes/do-your-own-thinking/">Doing My Own Thinking</a>.</p>
<p>This is yet another application of <a href="https://szymonkaliski.com/notes/self-cybernetics/">Self-Cybernetics</a> on myself — making my experiments visible to me, reminding myself to reflect on them, and presenting them to myself in a way that works around my psychology.</p>
<p>Running experiments this way was an experiment in itself (tracked within the system; <em>so meta</em>). I concluded it works for me, for now.</p>
<h2>Worth Checking Out</h2>
<p>Books I've enjoyed over these last three months:</p>
<ul>
<li><a href="https://www.amazon.com/Dream-Machine-M-Mitchell-Waldrop/dp/1732265119">The Dream Machine</a> — history of computing, from invention of binary logic, Turing machine and stored procedure, up until the internet; it's probably not the only history of computing book that you should read (I have <a href="https://www.hup.harvard.edu/catalog.php?isbn=9780674970977">A People’s History of Computing</a> waiting for me, that everyone recommends) but it was a fun, informative read</li>
<li><a href="https://mitpress.mit.edu/books/small-matter-programming">A Small Matter of Programming</a> which would be one of my recommendations for anyone interested in <a href="https://szymonkaliski.com/notes/end-user-programming/">End-User Programming</a> (hat tip to <a href="https://adamwiggins.com">Adam Wiggins</a>)</li>
<li><a href="https://takesmartnotes.com">How to Take Smart Notes</a> which describes infamous <a href="https://en.wikipedia.org/wiki/Niklas_Luhmann">Luhmann's</a> <a href="https://en.wikipedia.org/wiki/Zettelkasten">Zettelkasten</a> system in detail, and also touches on interesting topics like <a href="https://szymonkaliski.com/notes/where-do-ideas-come-from/">Where Do Ideas Come From?</a></li>
<li><a href="https://www.amazon.com/Tools-Conviviality-Ivan-Illich/dp/1842300113">Tools for Conviviality</a> — super dense but extremely interesting take on why modern tools might not be the best thing ever, I could draw some hand-wavy similarities to <a href="https://www.amazon.com/Seeing-like-State-Certain-Condition/dp/0300078153">Seeing Like a State</a>, so if you enjoyed this one it's worth checking the other one out</li>
<li><a href="https://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/1118766571">About Face</a> — an overview of the whole field of interaction design, I have a couple of other HCI classics waiting for me, so more to come</li>
<li>I read <a href="https://www.edwardtufte.com/tufte/books_vdqi">The Visual Display Of Quantitative Information</a> a long time ago, and with Tufte's new <a href="https://www.edwardtufte.com/tufte/seeing-with-fresh-eyes">Seeing With Fresh Eyes</a>, I've decided to grab the whole set — it's worth getting for the typesetting and layout alone, not to mention the actual contents</li>
<li>I've finally finished <a href="https://www.amazon.com/New-History-Western-Philosophy/dp/0199656495/">A New History of Western Philosophy</a>, taking detours on reading some of the original cited works, and I'm excited to dig into more specific topics next</li>
</ul>
<p>On the web:</p>
<ul>
<li>
<p><a href="https://apenwarr.ca/log/20201227">Systems design explains the world</a></p>
</li>
<li>
<p><a href="https://rsms.me/">Rasmus Andersson</a> is working on <a href="https://playb.it">a new thing</a> which looks like modern take on <a href="https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs">Plan 9</a> (and more)</p>
</li>
<li>
<p><a href="https://spectrum.ieee.org/automaton/aerospace/robotic-exploration/nasa-designed-perseverance-helicopter-rover-fly-autonomously-mars">How NASA Designed a Helicopter That Could Fly Autonomously on Mars</a></p>
<blockquote>
<p>We use a cellphone-grade IMU, a laser altimeter <strong>(from SparkFun)</strong>, and a downward-pointing VGA camera for monocular feature tracking.</p>
</blockquote>
</li>
<li>
<p><a href="https://sin-ack.github.io/posts/a-tour-of-self/">A tour of Self</a></p>
</li>
<li>
<p><a href="https://www.reddit.com/r/unixporn/comments/l0g09z/pipeworld_teaser_revenge_of_the_zuis/">A redditor is working on a ZUI WM</a></p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=UH0A2iujtY8">What even is code?</a></p>
</li>
</ul>
<h2>Fin</h2>
<p>Let me know what you think, and see you in a couple of months!</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2021-03-29-q1-2021/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2021-03-29-q1-2021/</guid>
            <pubDate>Mon, 29 Mar 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Haze]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://player.vimeo.com/video/513390690?color=FFF&#x26;title=0&#x26;byline=0&#x26;portrait=0" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>Haze is a four track live granular looper for <a href="https://monome.org/docs/norns/">Norns</a>, optimised for Midi Fighter Twister, but also usable without it.</p>
<p>The <a href="http://supercollider.github.io">SuperCollider</a> engine is based on <a href="https://llllllll.co/t/mangl/21066">Mangl</a>, which itself is based on <a href="https://llllllll.co/t/ash-a-small-collection/21349">angl</a> and <a href="https://llllllll.co/t/glut/21175">glut</a>.</p>
<p>Incoming audio is recorded into an 8 second loop (with configurable feedback), and granular engine samples from this loop.
Each row represents a single track, and there are three banks of parameters, the UI shows currently active bank together with the parameter names and values.</p>
<p>This project is available on github: <a href="https://github.com/szymonkaliski/haze">szymonkaliski/haze</a>.</p>
<hr>
<p>For other experiments around hardware/software for experimental music check out: <a href="https://szymonkaliski.com/projects/nott/">Nótt</a>, <a href="https://szymonkaliski.com/projects/diy-monome/">DIY Monome</a>, and <a href="https://szymonkaliski.com/projects/loop-pi/">LoopPI</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/haze/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/haze/</guid>
            <pubDate>Wed, 17 Feb 2021 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[End of 2020]]></title>
            <description><![CDATA[<p>Hi everyone!</p>
<p>End of 2020 seems as good time as any to refresh this newsletter, and start sharing more openly again. My plan for 2021 is to publish four of these, roughly one for every season.</p>
<p>This newsletter is divided into two parts — what I've been up to, and what interesting things I came across this year. I'll try to keep everything brief.</p>
<p>This year was tough and weird for everyone, to say the least. Luckily, everyone here is safe and healthy.
Poland has been doing quite well earlier this year and seems to be doing pretty bad right now, especially in terms of share of positive tests.</p>
<p>We've been stuck in the same walls for almost a year now, and living mostly the same day on repeat.
But it's ok, my personal take on this is that it's a small price to pay for hopefully much more years when we get to go out into the world again.</p>
<p>Even though the beginning of this year was pretty turbulent, I've been lucky to work on a bunch of interesting projects, in no particular order:</p>
<ul>
<li>a new interface for working with huge datasets for ML-generated molecular synthesis paths for <a href="https://molecule.one">MoleculeOne</a></li>
<li>bespoke layouting system for ground controls screens for <a href="https://www.esa.int">European Space Agency</a> (collaboration with <a href="http://www.recoded.co">Recoded</a>)</li>
<li>helping with the research process, and working on new ways of collecting information online at <a href="https://thebrowser.company">The Browser Company</a></li>
<li>R&#x26;D work for a new financial modeling spreadsheet at <a href="https://www.causal.app">Causal</a></li>
</ul>
<p>...and a couple of other things I can't talk about.</p>
<p>I've been also continuing research at <a href="https://www.inkandswitch.com">Ink&#x26;Switch</a> around the topic of "programming by drawing" for a tablet form-factor (trying to bring some of the Dynabook ideas to life). Latest spin-off work includes in-house Lisp with a projectional editor. This work is not public yet, but if you're interested in these topics, I'm happy to give a demo on a call.</p>
<p>I'm currently working with lovely folks at <a href="http://makespace.fun">MakeSpace</a> on a new way to be together, and doing R&#x26;D work at <a href="http://clay.run">Clay</a>.</p>
<p>Earlier this year I gave a talk at <a href="https://www.intersection-conference.eu">Intersection Conference</a> on the process of solving open-ended problems, if you have 25 minutes to spare, you can have a look here:</p>
<div class="aspect-ratio aspect-ratio--16x9 mv3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" width="1280" height="720" src="https://www.youtube.com/embed/U29D5M7GoY8" frameborder="0" allowfullscreen>
  </iframe>
</div>
<p>On the personal project side, I published a couple of things, in order of twitter likes:</p>
<ul>
<li><a href="https://twitter.com/szymon_k/status/1289942401318977537">multi pane "Research Browser"</a> — this one is currently unpublished, I also don't seem to use it that much, I might just publish it as-is soon</li>
<li><a href="https://szymonkaliski.com/projects/archivist/">Archivist</a> — which was technically made in 2019, is something I use a lot, I recently added a way to search through screenshots I take (using OCR) and this had a huge impact on how I collect things, I should probably share an update about it soon</li>
<li><a href="https://szymonkaliski.com/projects/protoboard/">Protoboard</a> and <a href="https://szymonkaliski.com/projects/liveboard/">Liveboard</a> — another projects technically from 2019, an answer to a prompt "what if programming was more like using a breadboard"</li>
<li><a href="https://szymonkaliski.com/projects/fabfungus/">FabFungus</a> — yet another 2019 project finally documented in 2020 — an artwork exploring cellular growth and questions of artificial life; selected in the <a href="https://digitalcultures.pl/en/programme/best-of-poland-physicality">Best Of Poland</a> section at Digital Cultures festival this year (<a href="https://www.youtube.com/watch?v=yohXN07TWFU&#x26;start=2018">here's me presenting the work</a>)</li>
<li><a href="https://szymonkaliski.com/projects/hhann/">HHANN</a> — a way to doodle on your screen, this is super useful when screen-sharing</li>
</ul>
<p>I also wrote an article on my <a href="https://szymonkaliski.com/writing/2020-04-19-memex-dreams/">note-todo system hybrid</a>, and <a href="https://szymonkaliski.com/notes/">made a subset of my notes public</a>, if you want to browse through my, even more half-baked, ideas.</p>
<p>Finally, onto something other than myself. One success this year was switching my information diet from mostly web articles, to mostly books (and academic papers). Some of the things I read through this year which I'd recommend:</p>
<ul>
<li><a href="https://www.amazon.com/Mindstorms-Children-Computers-Powerful-Ideas/dp/0465046746">Mindstorms</a> by Seymour Papert — which shed more light on why Alan Kay keeps talking about finding ways to help children think better — they grow up to be adults after all</li>
<li><a href="https://www.amazon.com/Art-Doing-Science-Engineering-Learning/dp/1732265178/">The Art of Doing Science and Engineering</a> by Richard Hamming (with great foreword from Bret Victor) — about half of the book was way over my head (I need to brush up on my math and physics) but I enjoyed the chapters on creativity, and approach to research</li>
<li><a href="https://www.amazon.com/Seeing-like-State-Certain-Condition/dp/0300078153">Seeing Like a State</a></li>
<li><a href="https://www.amazon.com/Death-Life-Great-American-Cities/dp/067974195X/">The Death and Life of Great American Cities</a></li>
<li><a href="https://www.amazon.com/Design-Everyday-Things-Revised-Expanded/dp/0465050654/">The Design of Everyday Things</a></li>
<li><a href="https://www.amazon.com/Thinking-Fast-Slow-Daniel-Kahneman/dp/0374533555/">Thinking, Fast and Slow</a></li>
<li><a href="https://www.amazon.com/How-Do-Nothing-Resisting-Attention/dp/1612197493">How to Do Nothing</a></li>
<li><a href="https://www.amazon.com/Understanding-Comics-Invisible-Scott-McCloud/dp/006097625X/">Understanding Comics</a> — I'm not a big comic fan, but I can't remember when I had so much fun reading a book</li>
<li><a href="https://www.amazon.com/Seeing-Forgetting-Name-Thing-Sees/dp/0520256093">Seeing Is Forgetting the Name of the Thing One Sees</a></li>
<li><a href="https://www.amazon.com/Think-Compelling-Introduction-Simon-Blackburn/dp/0192854259/">Think</a> — a quite light introduction to common themes in Philosophy, which made me want more, so I grabbed <a href="https://www.amazon.com/New-History-Western-Philosophy/dp/0199656495/">A New History of Western Philosophy</a> and I just finished the Ancient Greeks section</li>
</ul>
<p>Various other links worth checking out:</p>
<ul>
<li><a href="https://kevinlynagh.com/newsletter/">Kevin Lynagh's newsletter</a> has been a fun read every month, good starting point would be this entry on <a href="https://kevinlynagh.com/newsletter/2020_08_extreme_outcomes/">moving to Taipei</a> to flee the pandemic</li>
<li><a href="https://twitter.com/andy_matuschak">Andy Matuschak</a> research work on his <a href="https://notes.andymatuschak.org/">thinking notes</a> and <a href="https://www.patreon.com/quantumcountry/posts">upcoming spaced repetition system</a></li>
<li><a href="https://github.com/baku89/glisp">Glisp</a> — lisp editor for digital graphics from <a href="https://twitter.com/_baku89">Baku Hashimoto</a></li>
<li>assorted notes from <a href="https://twitter.com/yoshikischmitz">Yoshiki Schmitz</a>, including <a href="https://www.notion.so/A-Pattern-Language-for-Interfaces-c2f88d6b16d84293995c006042e79d88">A Pattern Language for Interfaces</a></li>
<li><a href="https://podcasts.apple.com/podcast/id1504506097">Metamuse</a> a podcast from <a href="http://museapp.com">Muse</a> — a spin-off project from Ink&#x26;Switch</li>
<li><a href="https://shape.design.gatech.edu">Shape Computation Lab</a> working on "shape grammars" making visual design resemble <a href="https://en.wikipedia.org/wiki/Rewriting">rewrite rules</a> — it's hard to explain in text, check out their videos!</li>
<li><a href="https://adamwiggins.com">Adam Wiggins</a> wrote great personal manifesto on <a href="https://adamwiggins.com/making-computers-better/">making computers better</a></li>
<li><a href="https://www.semilattice.xyz">Semilattice</a>, another interesting take on <a href="https://szymonkaliski.com/notes/canvas-for-thinking/">canvas for thinking</a></li>
<li><a href="https://www.quora.com/profile/Alan-Kay-11">Alan Kay is pretty active on Quora</a></li>
<li>interesting take on <a href="https://ryosuzuki.org/realitysketch/">interactive sketching in AR</a></li>
<li><a href="https://www.youtube.com/watch?v=HrwxbQj5mj0">programming with machines?</a></li>
<li>I'm approaching my first decade of professional work, so I've been also reading on various things "career":
<ul>
<li><a href="https://lethain.com/forty-year-career/">A Forty Year Career</a></li>
<li><a href="https://www.kalzumeus.com/2012/01/23/salary-negotiation/">Salary Negotiation</a>, <a href="https://www.kalzumeus.com/2011/10/28/dont-call-yourself-a-programmer/">Don't Call Yourself A Programmer, And Other Career Advice</a> (and other writings from Patrick McKenzie)</li>
<li><a href="https://www.amazon.com/Getting-Yes-Negotiating-Agreement-Without/dp/0143118757">Getting to Yes</a></li>
<li>also thinking of things like taking a <a href="https://en.wikipedia.org/wiki/Sabbatical">sabbatical</a> and <a href="https://szymonkaliski.com/notes/thinking-and-time/">time needed for thinking</a></li>
</ul>
</li>
</ul>
<p>Friends, colleagues, collaborators — thanks so much for everything, wishing you (and myself) that 2021 is a bit kinder to all of us.</p>]]></description>
            <link>https://szymonkaliski.com/newsletter/2020-12-28-end-of-2020/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/newsletter/2020-12-28-end-of-2020/</guid>
            <pubDate>Mon, 28 Dec 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[FabFungus]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//player.vimeo.com/video/384362210?color=FFF&#x26;title=0&#x26;byline=0&#x26;portrait=0" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>FabFungus is a physical installation inspired by questions of <em>digital life</em> and <em>cellular growth</em>. It was created together with <a href="https://www.renderboys.pl">Marek Straszak and Arek Zub</a>, and exhibited for the first time at <strong>Posthuman_Data</strong> exhibition in Poznań in 2019.</p>
<p>FabFungus is a computational tool for creating digital structures grown out with a simulated process. It is also a manifestation of couple of these forms, brought to physical reality through imperfect 3D printing.</p>
<p><a href="https://szymonkaliski.com/projects/fabfungus/fabfungus.png">FabFungus Photo</a></p>
<blockquote>
<p>FabFungus (...) is a technologically advanced work annexing the theoretical perspective of medianatures and their potential adaptations in the digital-biological environment. In this design, data is part of a new nature, its physical representation is just one of the possible biological interpretations of the code. We are talking here about redefining what is alive and inanimate, artificial and natural. The work raises the question: how much closer to "nature" and biological definitions are algorithms and "non-human" programming languages than anthropocentric strategies for creating cultural narratives and myths?</p>
<cite>—  Agnieszka Jelewska, Michał Krawczak</cite>
</blockquote>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/projects/fabfungus/making-of-3.png" width="1000" height="1000">
  </div>
  <div class="w-100 mh1">
    <img src="https://szymonkaliski.com/projects/fabfungus/making-of-2.png" width="757" height="757">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/projects/fabfungus/making-of-1.png" width="1000" height="1000">
  </div>
</div>
<p>From technical side, FabFungus was a culmination of three personal research projects:</p>
<ul>
<li>questions about SDF modeling answered with <a href="https://szymonkaliski.com/projects/hiccup-sdf/"><code>hiccup-sdf</code></a></li>
<li>high-performance simulation algorithms, still partly unpublished: <a href="https://github.com/szymonkaliski/behaviours-rs"><code>behaviours-rs</code></a></li>
<li>experiments in creating a medium for quick exploratory work: <a href="https://szymonkaliski.com/projects/protoboard/">Protoboard</a></li>
</ul>
<img src="https://szymonkaliski.com/projects/fabfungus/protoboard.png" alt="Protoboard Screenshot" width="1568" height="1048">
<hr>
<p>In 2020 FabFungus was a part of <a href="https://digitalcultures.pl/en/programme/best-of-poland-physicality">Best of Poland</a> section at <a href="https://digitalcultures.pl/en/home">Digital Cultures</a>, you can see me talking about it below:</p>
<div class="aspect-ratio aspect-ratio--16x9 mv3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" width="1280" height="720" src="https://www.youtube.com/embed/yohXN07TWFU?start=2018" frameborder="0" allowfullscreen>
  </iframe>
</div>]]></description>
            <link>https://szymonkaliski.com/projects/fabfungus/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/fabfungus/</guid>
            <pubDate>Thu, 12 Nov 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Liveboard]]></title>
            <description><![CDATA[<video controls>
<source src="https://szymonkaliski.com/projects/liveboard/livecoding.mp4" type="video/mp4">
</video>
<p>Liveboard is a library built on top of <a href="https://szymonkaliski.com/projects/protoboard/">Protoboard</a>, providing a set of high-level functions for live-coding music and visuals.</p>
<p>Thanks to hot module reload the functions can be swapped immediately, without the need to refresh the whole page.</p>
<p>Midi-based nodes can be mixed with visual ones, creating an interesting platform for audio-visual performances.</p>
<p>Liveboard provides a couple of useful modules:</p>
<ul>
<li><code>midi</code> for controlling music software</li>
<li><code>metronome</code> and <code>tempo</code> — multiple metronomes could be used at once to create <a href="https://en.wikipedia.org/wiki/Polyrhythm">polyrhythms</a></li>
<li><code>out</code> as a basic creation block</li>
<li>a couple of helpers based around music theory (using the <a href="https://github.com/tonaljs/tonal">tonal</a> library)</li>
</ul>
<p>Example Liveboard session:</p>
<pre><code class="language-js">const board = createBoard();
board.start();

metronome(board, [0, 0]);
tempo(board, [1, 0], 90);
midi(board, [2, 0]);

// `tick` is triggered on every metronome tick
// `play` triggers MIDI note
out(board, [2, 2], ({ tick, play }) => {
  const seq = ["G2", "F2", "E2", "D2"];
  const note = pick(seq, tick);

  play({ note, dur: random(2000, 8000) });
});
</code></pre>
<p>In 2019 I got a chance to teach a couple of live-coding workshops using Liveboard.
Environments with immediate feedback make a great teaching tools, and we also managed to spend some of the time actually playing around and making music.</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/projects/liveboard/workshops-kolonia.jpg" width="1280" height="720">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/projects/liveboard/workshops-48k.jpg" width="1280" height="720">
  </div>
</div>]]></description>
            <link>https://szymonkaliski.com/projects/liveboard/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/liveboard/</guid>
            <pubDate>Thu, 23 Jul 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Protoboard]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/protoboard/screenshot.jpg" alt="Protoboard screenshot" width="1827" height="1439">
<p>This project was inspired by <a href="https://en.wikipedia.org/wiki/Breadboard">breadboards</a>: they are used for both learning, and experimenting, allow for very fast iterations, and tap into our spatial reasoning.</p>
<p>Protoboard is a frontend library built on <a href="https://thi.ng/hdom"><code>thi.ng/hdom</code></a>. There's a single exposed function called <code>createBoard</code> which fills the screen with a grid.
Pieces of code can be attached to that grid by supplying a name, position, size, and a function:</p>
<pre><code class="language-js">import createBoard from "protoboard";

const board = createBoard();
board.start();

board.add("hello world", [0, 0], [2, 2], () => {
  return ["h1", "hello!"];
});
</code></pre>
<p>Nodes on the board can hold internal state, which other nodes can react to, forming a <a href="https://szymonkaliski.com/notes/computational-dags/">computational DAG</a>:</p>
<pre><code class="language-js">board.add("count every second", [0, 0], [2, 2] (state) => ({
  init: () => {
    // initialize with 0
    if (state.deref() === undefined) {
      state.reset(0);
    }

    handle = setInterval(() => {
      state.swap(count => count + 1);
    }, 1000);
  },

  render: () => {
    return ["div", `counter value: ${state.deref()}`];
  },

  release: () => {
    clearInterval(handle);
  }
}));

board.add("counter times two", [2, 0], [2, 2], ({ nodes }) => {
  return ["div", nodes["count every second"] * 2]
});
</code></pre>
<p>Protoboard nodes by design encapsulate code instead of other nodes, compared to some VPLs where even basic math equations have to use blocks and connections.</p>
<p>Combination of the background grid, and a quick way to build <code>DOM</code> elements, allows for adding pieces of documentation, notes, and inspiration images inline on the board, creating a <a href="https://szymonkaliski.com/notes/canvas-for-programming/">canvas for programming</a>:</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/projects/protoboard/mini-0.jpg" width="1206" height="679">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/projects/protoboard/mini-1.jpg" width="1208" height="680">
  </div>
</div>
<p>Protoboard isn't without issues though.
The need to describe position and size of the node in code seems very <em>clean</em> — everything is defined in the same place, and rendering is a pure function over the input file.
I just keep on catching myself trying to move the nodes around and resize them using a mouse.
Something I want to try is updating the code file when the nodes are moved or resized.</p>
<p>Another issue grows out of the way that nodes are connected together through global naming.
This makes it hard to create reusable pieces of code, and the user is forced to create unnecessary abstractions, like:</p>
<pre><code class="language-js">const createDebugNode = (pos, size, name) => {
  board.add(`${name} debug`, pos, size, ({ nodes }) => {
    return ["code", JSON.stringify(nodes[name], null, 2)];
  });
}
</code></pre>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/projects/protoboard/mini-3.jpg" width="1280" height="720">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/projects/protoboard/mini-2.jpg" width="1212" height="682">
  </div>
</div>
<p>I believe that writing code in <a href="https://en.wikipedia.org/wiki/Vertical_slice"><em>vertical slices</em></a> on some form of canvas has a lot of benefits, we just don't have the proper interactions and abstractions discovered yet.</p>]]></description>
            <link>https://szymonkaliski.com/projects/protoboard/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/protoboard/</guid>
            <pubDate>Tue, 14 Jul 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[HHANN]]></title>
            <description><![CDATA[<video loop autoplay muted>
  <source src="https://szymonkaliski.com/projects/hhann/video.mp4" type="video/mp4">
</video>
<p><code>HHANN</code> was created to fill a basic need of being able to draw on top of the screen.</p>
<p>Allowing users to <a href="https://szymonkaliski.com/notes/pencil-and-os-level-doodling/">doodle on the OS-level</a> turns the whole system into a <a href="https://szymonkaliski.com/notes/canvas-for-thinking/">canvas for thinking</a>.</p>
<p>The tool is especially useful during screen-shared calls, or when quickly annotating designs and documents — doodle on top and take a screenshot.</p>
<p>This project as available on github: <a href="https://github.com/szymonkaliski/hhann">szymonkaliski/hhann</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/hhann/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/hhann/</guid>
            <pubDate>Tue, 30 Jun 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Memex Dreams]]></title>
            <description><![CDATA[<p><a href="https://en.wikipedia.org/wiki/Memex">Memex</a> has become a kind of holy grail for information workers, never-built tool which inspired the web and hypertext back in 1945.</p>
<p>For me, the web is one side of the puzzle, although implemented in the way that leaves some things to be desired (<a href="https://en.wikipedia.org/wiki/Project_Xanadu">Project Xanadu</a> tried to solve that).</p>
<p>The other part, one that feels missing, is a network for my knowledge.</p>
<h2>Origins</h2>
<p>I stopped trusting my memory a long time ago, and I hate the feeling of stuff slipping through the cracks.
I started to use a dedicated todo app sometime in early college, and discovered <a href="https://en.wikipedia.org/wiki/Getting_Things_Done">GTD</a> methodology soon after. This worked well for a while. I've been a happy <a href="https://culturedcode.com/things/">Things</a> user for a while, and migrated to <a href="https://www.taskpaper.com/">TaskPaper format</a> when I felt too constrained by Things assumptions.</p>
<p>I even wrote my own <a href="https://github.com/szymonkaliski/taskpaper-parser">TaskPaper parser</a>, and started scripting my task list: automatically turning <code>@due</code> dates to <code>@today</code> at appropriate day (in combination with <code>cron</code>), archiving <code>@done</code> tasks, or a script that would group tasks by date and print them out, so I could see how my next week is looking.</p>
<p>This worked well for a few years, but over time, my tasks started turning more from <em>implement X</em>, to <em>research Y</em>, <em>think through Z</em>, etc.</p>
<p>Once my TaskPaper had more comments than tasks, I knew that this was not going to work for long.</p>
<p>I was also keeping separate folder of notes, initially using <a href="http://notational.net/">Notational Velocity</a>, which then changed to just a folder of markdown files. Some of the notes were related to projects, some of them not. I never knew if a given piece of information should go in my TaskPaper comments, or my other notes. And then, there were notes for thinking about things, which sometimes spawned new projects. This was a disaster in slow-motion.</p>
<h2>Fixing the Mess</h2>
<p>Since notes and tasks were overlapping so much, I decided to combine them. I wanted to introduce as little complexity as I could, so writing a web app to store all that data in a database didn't feel right. I needed just a bunch of markdown files, some basic structure, and one thing I couldn't live with — that script to show my tasks for the next few days.</p>
<p>The structure that I currently use looks like this:</p>
<ul>
<li><code>/inbox.md</code> - my first-order everything inbox</li>
<li><code>/Projects/</code> - with sub folders per personal project:
<ul>
<li><code>/Projects/Archivist/</code>, which usually includes at least <code>index.md</code> and <code>worklog.md</code></li>
</ul>
</li>
<li><code>/Work/</code> - with the same structure as <code>/Projects/</code>, just with work stuff</li>
<li><code>/Journal/</code> - with single file per date — I keep that file opened the whole day, it serves as a scratchpad, brain dump, way to record reminders, ideas, etc.</li>
<li><code>/Calendar/</code> - with single file per year — used to schedule long-term reminders that don't fit anywhere else</li>
<li><code>/Notes/</code> - personal knowledge base</li>
</ul>
<p>To deal with upcoming tasks I wrote <a href="https://github.com/szymonkaliski/muninn"><code>muninn</code></a>, a small CLI utility which parses all the files, and organises tasks by date. I use <a href="https://github.github.com/gfm/">github flavored markdown</a> to store my todos, and extended markdown parser to deal with <code>@due(YYYY‑MM‑DD)</code> dates, in the end a file for this article looks like this:</p>
<pre><code class="language-markdown"># Memex Article

- [worklog](&#x3C;./worklog.md>)

## References

- [memex and workshop vs library](&#x3C;../Notes/Zettels/memex\ and\ workshop\ vs\ library.md>)
- [self-cybernetics systems](&#x3C;../Notes/Zettels/self-cybernetics.md>)

## Todo

- [x] rough outline @due(2020-04-01)
- [x] re-read outline @due(2020-04-02)
- [x] article setup @due(2020-04-03)
- [x] initial writing @due(2020-04-03)
- [ ] rough pass at first section @due(2020-04-04)

## Outline

- ...

</code></pre>
<h2>On Inboxes</h2>
<p>I have two conceptual inboxes.</p>
<p>First one, <code>inbox.md</code>, is where the most interesting links end up, together with my random thoughts, waiting for a weekly review. I mainly append to that file through iOS shortcut. I can quickly share a twitter link, or jot a quick note in drafts.</p>
<p>Second one is a bit more convoluted. Sometimes during the day I have, well, <em>thoughts</em>. Some of them don't want to go away, and as a way to temporarily "close the loop" I jot them down in my daily journal. Sometimes an idea keeps coming back, and if that happens, I work on it through multiple days in those daily journals, and once it feels good enough, I move it to the longer-term storage — <a href="https://szymonkaliski.com/notes/"><code>/Notes/</code></a> directory.</p>
<p>Weekly review is an important part of this process. <br> An inbox is not worth much if it's never cleared.</p>
<p>Right now, usually on Sunday mornings, I check out every collected link, and last week of daily journals. At this stage, I'd say half of the things are ignored, because after a couple of days they just don't matter much anymore.</p>
<p>Some things are migrated to be stored as reference materials, articles end up in <a href="https://pinboard.in/">pinboard</a>, and images/gifs/short videos in <a href="https://pinterest.com/szymon_k/">pinterest</a>. I then archive those archives in <a href="https://szymonkaliski.com/projects/archivist/">Archivist</a> so I can be sure I won't lose them even if the online services stop working.</p>
<h2>On Worklogs</h2>
<p>Keeping worklogs had the biggest positive impact on my work in recent years.</p>
<p>The basic idea is simple — to just jot down whatever I'm working on at the moment. Even better, jot down my assumptions, potential issues, and conclusions.</p>
<p>Sometimes I sketch out an API before I write it, sometimes I draw some boxes and lines, then I take a photo and add as an image to that document. Sometimes I outline a few slides for a talk, or just think through how something could work, without implementing it.</p>
<p>This process leaves a visible trail of what I actually did on a given project, which makes it so much easier to get back to things after a break. It also helps fight against <a href="https://szymonkaliski.com/notes/zeigarnik-effect/">Zeigarnik effect</a> — I don't have to keep thinking about things once I wrote them down.</p>
<p>Worklogs also introduced me to the idea of <a href="https://szymonkaliski.com/notes/thinking-by-writing/">writing as a thinking tool</a>. Instead of trying to "come up" with a solution in my head, I write/draw through/with my thinking process. Writing is a great metacognition tool, it allows me to <em>see my thinking</em>, and <a href="https://szymonkaliski.com/notes/metacognition-and-debugging/">debug the thinking process</a> afterwards.</p>
<h2>On Thinking by Writing</h2>
<p>This all leads my to the way I store notes.</p>
<p>My main inspiration was the infamous <em>Zettelkasten</em> system. I'm not going to introduce the ideas here — <a href="https://www.lesswrong.com/posts/NfdHG6oHBJ8Qxc26s/the-zettelkasten-method-1">The Zettelkasten Method</a> on LessWrong does a great job of that.</p>
<ul>
<li>obviously, everything is stored in files instead of index cards</li>
<li>I don't use stable <code>id</code> to name the notes, I prefer human-readable ones, even if that means I sometimes have to fix broken links</li>
<li>I'm not against adding quotes to the note, but I never leave it at a quote alone, I always write my own thoughts next to it</li>
</ul>
<p>The main premise is there though — notes are short, they usually contain one idea, even if I can't name it yet (this also leads to interesting note titles, like <a href="https://szymonkaliski.com/notes/spreadsheet-for-end-user-programming-might-be-a-wrong-model/"><em>spreadsheets might be a wrong model</em></a>, or <a href="https://szymonkaliski.com/notes/understanding-requires-effort/"><em>understanding requires effort</em></a>). Notes are interlinked through direct links, and automatic backlinks (via <a href="https://github.com/szymonkaliski/muninn"><code>muninn</code></a> cli tooling). If I have a bunch of notes which seem related in some way, I create index note to collect them together, enforcing a specific point of view. Single note can be in multiple different indexes that way (<a href="https://szymonkaliski.com/notes/connections-are-usually-better-than-taxonomies/">connections are usually better than taxonomies</a>).</p>
<p>I edit my thoughts in <a href="https://www.vim.org/">vim</a>, which allows me to easily view multiple notes at once, and with addition of <a href="https://github.com/szymonkaliski/muninn-vim"><code>muninn-vim</code></a>, to explore backlinks.
Typical thinking session looks similar to this:</p>
<img src="https://szymonkaliski.com/writing/2020-04-19-memex-dreams/editing.png" alt="typical editing session" width="2611" height="1468">
<p>Once something ends up as a note in my system, it was probably <a href="https://szymonkaliski.com/notes/on-the-importance-of-rewriting/">rewritten</a> at least a couple of times, through inboxes and daily notes. I put it there when I'm pretty sure it's not a temporary <em>thing-to-remember</em>, but something that will allow me to make new connections, and grow ideas. I try to not replace already existing notes, but build upon them, even if my understanding and ideas change.</p>
<h2>Fin.</h2>
<p>Like with most of my projects, this is a very personal one. It fits my way of doing things, and similarly like with <a href="https://szymonkaliski.com/writing/2017-04-30-time-tracking/">Timav</a>, changes the things I do. The latter forces me to spend time doing the things I want to do, by showing me the time tracking data in a specific way, the former makes me think thoughts that I probably wouldn't have thought otherwise.</p>
<h2>References</h2>
<ul>
<li><a href="https://notes.andymatuschak.org/">Andy Matuschak's notes</a> — research project on similar ideas</li>
<li><a href="https://roamresearch.com/">Roam Research</a> — web app providing automatically backlinked Zettelkasten-like system</li>
<li><a href="https://tiddlywiki.com/">TiddlyWiki</a> — single-file personal wiki system</li>
<li><a href="https://orgmode.org/">Org Mode</a> — emacs-based plain-text organisation suite</li>
</ul>]]></description>
            <link>https://szymonkaliski.com/writing/2020-04-19-memex-dreams/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2020-04-19-memex-dreams/</guid>
            <pubDate>Sun, 19 Apr 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Archivist]]></title>
            <description><![CDATA[<video loop autoplay muted>
  <source src="https://szymonkaliski.com/projects/archivist/archivist.mp4" type="video/mp4">
</video>
<p>Archivist is a set of tools for archiving and exploring of reference materials.</p>
<p>I spend a lot of time gathering resources and <em>lateral thinking</em> material. Over the years I noticed that stuff tends to disappear from the web, both the original content, and services used to collect it.</p>
<p>Archivist fetches local copies of the source images and <a href="https://github.com/WebMemex/freeze-dry">frozen copies</a> of the websites, so things wont get lost. I'm trading my local disk space for feeling safe that the content stays with me.</p>
<p>This work was partially prompted by <a href="https://www.inkandswitch.com/local-first.html">local-first ideas from Ink&#x26;Switch</a>.</p>
<p>There's no UI except for the content, and no interaction except for scrolling and searching.</p>
<p>Code is open sourced: <a href="https://github.com/szymonkaliski/Archivist">szymonkaliski/Archivist</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/archivist/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/archivist/</guid>
            <pubDate>Wed, 01 Jan 2020 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nótt]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/nott/nott-1.jpg" alt="Nótt photo" width="1280" height="720">
<p>Nótt contains six independent loops, up to 8 seconds long, including speed control, sublooping, reverse playing, and custom granular mode. It combines my previous <a href="https://szymonkaliski.com/projects/loop-pi/">hardware looper experiment - LoopPI</a> and my <a href="https://szymonkaliski.com/projects/diy-monome/">DIY Monome research</a>.</p>
<p>It was inspired by <a href="https://monome.org/docs/norns/dust/tehn/mlr/">mlr</a> and <a href="https://monome.org/norns/">norns</a>, built on Raspberr Pi, <a href="https://blokas.io/pisound">Blokas Pisound</a> and <a href="https://www.adafruit.com/product/3954">Adafruit NeoTrellis</a> using <a href="http://chuck.stanford.edu/">Chuck</a> and Python.</p>
<p>Detailed usage instructions are available <a href="https://github.com/szymonkaliski/nott/blob/master/docs/USAGE.md">here</a>, and build instructions <a href="https://github.com/szymonkaliski/nott">here</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/nott/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/nott/</guid>
            <pubDate>Mon, 01 Jul 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[volume-brush]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/volume-brush/screen.png" alt="Screenshot" width="2022" height="1137">
<p><a href="https://github.com/szymonkaliski/volume-brush">volume-brush</a> is a volumetric brush implementation, inspired and adapted from <a href="http://toxiclibs.org/docs/volumeutils/toxi/volume/VolumetricBrush.html">toxiclibs</a>.</p>
<p>It's using <a href="https://en.wikipedia.org/wiki/Sparse_voxel_octree">sparse voxel octree</a> for storing the data, and <a href="https://en.wikipedia.org/wiki/Isosurface#Surface_Nets">surface nets</a> for meshing the isosurface into a mesh.</p>
<p>This approach opens a lot of possibilities, for creating complex, organically-looking 3d shapes.
The library can be easily combined with particle simulations, agent-based drawings, or for example sampling data from images (<a href="https://www.printmag.com/article/building_august2008_cover/">technique explored by Karsten Schmidt back in 2018</a>).</p>
<p>For more information and examples go to github: <a href="https://github.com/szymonkaliski/volume-brush">szymonkaliski/volume-brush</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/volume-brush/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/volume-brush/</guid>
            <pubDate>Tue, 25 Jun 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Modeler]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/modeler/modeler.png" alt="Screenshot" width="2201" height="1239">
<p><a href="https://github.com/szymonkaliski/modeler">Modeler</a> is a <a href="https://en.wikipedia.org/wiki/Constructive_solid_geometry">CSG</a> modeling library for React, and a cli helper tool.</p>
<p>It is built from two packages: <code>modeler-csg</code> - the main modeling library, and <code>modeler-cli</code>.</p>
<p><code>modeler-csg</code> is a custom React <a href="https://reactjs.org/docs/reconciliation.html">reconciler</a> designed to work with <a href="https://github.com/drcmda/react-three-fiber"><code>react-three-fiber</code></a>:</p>
<pre><code class="language-js">const React = require("react");
const ReactDOM = require("react-dom");
const { Canvas } = require("react-three-fiber");
const { Model } = require("modeler-csg");

ReactDOM.render(
  &#x3C;Canvas>
    &#x3C;ambientLight color={0x888888} />
    &#x3C;spotLight position={[0, 10, 10]} />

    &#x3C;Model>
      &#x3C;subtract>
        &#x3C;cube />
        &#x3C;sphere radius={1.3} />
      &#x3C;/subtract>
    &#x3C;/Model>
  &#x3C;/Canvas>,
  document.getElementById("root")
);
</code></pre>
<p><code>modeler-cli</code> provides a quick live-reloading preview, and offline STL export.</p>
<p>For more information and examples go to github: <a href="https://github.com/szymonkaliski/modeler">szymonkaliski/modeler</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/modeler/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/modeler/</guid>
            <pubDate>Fri, 19 Apr 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[End-User Programming ↗]]></title>
            <description><![CDATA[End-User Programming]]></description>
            <link>https://www.inkandswitch.com/end-user-programming/</link>
            <guid isPermaLink="true">https://www.inkandswitch.com/end-user-programming/</guid>
            <pubDate>Sat, 30 Mar 2019 23:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building Dacein]]></title>
            <description><![CDATA[<p><a href="http://szymonkaliski.github.io/dacein/">Dacein</a> is an experimental creative coding IDE combining a few different ideas that I've been thinking about:</p>
<ul>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#functional-creative-coding-library">functional creative coding library</a></li>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#time-travel">time travel abilities</a></li>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#livecoding">livecoding editor</a></li>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#direct-manipulation">direct manipulation</a></li>
</ul>
<p>It was created during January and February 2019 as a part of bimonthly projects challenge that I'm running this year.</p>
<h2>Functional creative coding library</h2>
<p>Creating graphics in Dacein is done using single <code>sketch</code> function which accepts a few parameteres:</p>
<ul>
<li><code>size</code> - size of the canvas</li>
<li><code>initialState</code> - initial state of the sketch</li>
<li><code>update</code> - update function which produces new state</li>
<li><code>draw</code> - drawing function which consumes current state</li>
</ul>
<p><code>state</code> mutations are only allowed within the <code>update</code> function, and even though the <code>state</code> itself is immutable, it can be modifed with familiar imperative JS API thanks to the <a href="https://github.com/mweststrate/immer">immer</a> library.</p>
<p>In addition to providing simple mental model - <em>all changes are done in the update function</em> - this technique also allows for easy implementation of <a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#time-travel">time travel</a>.</p>
<p>This fixes one of the issues I have with languages like <a href="https://processing.org">Processing</a>, where drawing and updating are often intertwined, and in complex programs it's usually hard to follow where the values come from, and where they are changed.</p>
<p>Drawing happens through a small declarative API, borrowing ideas from <a href="https://reactjs.org">React</a> - instead of imperatively accessing the canvas API, the user returns an object representing current state of the drawing.
This is actually much simpler to implement for canvas vs DOM, because we can just keep redrawing the screen - there's no <a href="https://reactjs.org/docs/reconciliation.html">reconciliation</a> step that needs to happen.
The object returned from <code>draw</code> function is an array of arrays, idea borrowed from <a href="https://github.com/weavejester/hiccup">hiccup</a>.
So, combining all of these ideas together, a simple sketch of pulsating circle looks like this:</p>
<pre><code class="language-js">sketch({
  size: [600, 600],

  initialState: {
    x: 0,
  },

  update: (state) => {
    state.x++;

    return state;
  },

  draw: (state) => {
    const r = (Math.sin(state.x) + 1) * 100;

    return [
      ["background", { fill: "#ffffff" }],
      ["ellipse", { pos: [300, 300], size: [r, r] }],
    ];
  },
});
</code></pre>
<p>Compared to similar sketch implemented in <a href="https://p5js.org">p5</a>, which even though shorter, intertwines (global) state manipulation with producing output:</p>
<pre><code class="language-js">let x = 0;

function setup() {
  createCanvas(600, 600);
}

function draw() {
  background(255);

  x++;
  const r = (Math.sin(state.x) + 1) * 100;

  ellipse(300, 300, r, r);
}
</code></pre>
<p>To deal with user input, the <code>update</code> function accepts second argument, which is an array of events that happened between the last and current frame.
This array contains objects with <code>source</code> key (borrowed from DOM event sources: <code>mousedown</code>, <code>mousemove</code>, <code>keydown</code>, etc.), and additional event metadata (mouse position, clicked key, etc.).</p>
<p>This allows us to create predictable, declarative sketches, where the output drawing is a function of state, and events that happened in the system.</p>
<p>It's easy to imagine that reasoning and testing such sketches is much simpler than their imperative counterparts.</p>
<p>This part of Dacein project could potentially leave on it's own, without the rest of the IDE.
One of the ideas that I didn't get around to, was to allow users to export <em>standalone</em> sketches, that don't require Dacein to run.</p>
<p>If you're interseted in forking Dacein and ripping this part out, <a href="mailto:hi@szymonkaliski.com">let me know</a>.
You should also check out <a href="https://github.com/thi-ng/umbrella/tree/master/packages/hdom-canvas"><code>hdom-canvas</code></a> for a much more developed similar idea created by <a href="http://postspectacular.com">Karsten Schmidt</a>.</p>
<h2>Time travel</h2>
<p>Because <code>draw</code> and <code>update</code> parts of <code>sketch</code> are immutable, we can record changes made to the <code>state</code> before each <code>draw</code> call, store them, and then allow users to pause, replay, and scrub through time:</p>
<div class="mb3 ba b--light-gray br2" style="background:#101010; display:inline-block;">
  <video loop autoplay muted class="pa3 bw0" style="max-width:calc(100% - 2rem)">
    <source src="https://szymonkaliski.com/writing/2019-03-01-building-dacein/time-travel.mp4" type="video/mp4">
  </video>
</div>
<p>The current <code>state</code> value is also visualised, so it's easier to debug and understand what's happening.</p>
<p>The actual implementation of that feature was pretty straightforward.</p>
<ol>
<li>If the sketch is playing, we keep producing new <code>currentState</code> using <code>immer</code> library:</li>
</ol>
<pre><code class="language-js">currentState = immer(currentState, (draft) => sketch.update(draft, events));
</code></pre>
<ol start="2">
<li>We also keep a history object, where we store both the <code>state</code> and <code>events</code> (mouse, keyboard, etc.), as well as current index inside of those arrays, which we use for scrubbing:</li>
</ol>
<pre><code class="language-js">setHistory((draft) => {
  draft.stateHistory.push(currentState);
  draft.eventsHistory.push(events);

  // we make sure we only keep MAX_HISTORY_LEN elements in the arrays
  while (draft.stateHistory.length > MAX_HISTORY_LEN + 1) {
    draft.stateHistory.shift();
    draft.eventsHistory.shift();
  }

  draft.idx = Math.min(MAX_HISTORY_LEN, draft.idx + 1);
});
</code></pre>
<ol start="3">
<li>If the sketch is paused, we're not running that part of the code at all, and read the state and events from the history, only calling the <code>draw</code> function:</li>
</ol>
<pre><code class="language-js">currentState = stateHistory[index];
</code></pre>
<p>The actual implementation is a bit more complex because of how the sketch container is set up, you can check the relevant parts <a href="https://github.com/szymonkaliski/dacein/blob/master/src/sketch-container.js#L206-L222">here</a> and <a href="https://github.com/szymonkaliski/dacein/blob/master/src/sketch-container.js#L279-L285">here</a>.</p>
<h2>Livecoding</h2>
<p>Livecoding can mean different things in different context. For Dacein, by livecoding I understand ability to immediately see code changes on the screen, as well as custom pickers to <em>scrub</em> through numbers and colors without typing.</p>
<p>The <em>hot</em> reload of code is again piggybacking on the immutability.
When the user changes the code, we can evaluate it again, and swap current <code>draw</code> and <code>update</code> functions to see the changes on the screen immediately (well, by next frame).</p>
<p>This approach becomes problematic when user makes a change to <code>initialState</code>.
I tried to automatically patch-in the new <code>initialState</code> on top of current <code>state</code> but it was finicky and was breaking the history scrubbing, so in the end I decided that any change to how the <code>state</code> object looks would automatically reset the sketch (start from initial values).</p>
<p>Here's how it looks like when modifying code:</p>
<div class="mb3 ba b--light-gray br2" style="background:#101010; display:inline-block;">
  <video loop autoplay muted class="pa3 bw0" style="max-width:calc(100% - 2rem)">
    <source src="https://szymonkaliski.com/writing/2019-03-01-building-dacein/livecoding-text.mp4" type="video/mp4">
  </video>
</div>
<p>And here's how the user can play with constants using just mouse:</p>
<div class="mb3 ba b--light-gray br2" style="background:#101010; display:inline-block;">
  <video loop autoplay muted class="pa3 bw0" style="max-width:calc(100% - 2rem)">
    <source src="https://szymonkaliski.com/writing/2019-03-01-building-dacein/livecoding-pickers.mp4" type="video/mp4">
  </video>
</div>
<p>I'm doing a bit of <em>not always correct</em> detection of what kind of thing is under a cursor, and if I detect a number or string that looks like a color, I'm displaying a custom picker on top of the editor.
That picker returns a new value, which is <a href="https://github.com/szymonkaliski/dacein/blob/master/src/editor.js#L205-L218">replaced in code</a> which in turn is re-evaluated, leading to new value on screen.
This could be optimised of course with some additional engineering time, but I hope it shows how easy this can be to implement in a text editor.</p>
<p>The last interesting thing implemented here in the livecoding space is custom highlight from result, to the code that produced it:</p>
<div class="mb3 ba b--light-gray br2" style="background:#101010; display:inline-block;">
  <video loop autoplay muted class="pa3 bw0" style="max-width:calc(100% - 2rem)">
    <source src="https://szymonkaliski.com/writing/2019-03-01-building-dacein/livecoding-highlight.mp4" type="video/mp4">
  </video>
</div>
<p>Implementing this was a bit harder.
I'm traversing the sketch AST, looking for everything that looks like a drawing command - that is, an array with first item being a string of one of the draw commands.
So <code>["circle", {}]</code> is a draw command, but <code>[10, 20]</code> is not.</p>
<p>When I find an array like that, I augment the second argument with <code>__meta</code> field which holds <code>lineStart</code> and <code>lineEnd</code> values grabbed from the AST.
The relevant code is <a href="https://github.com/szymonkaliski/dacein/blob/master/src/ast-transforms.js#L10-L93">here</a>.</p>
<p>Knowing the origin of a current drawing is only half of the battle.
I needed a way to know what the user is hovering over, and since the library uses canvas, this wasn't as easy as adding custom <code>onMouseOver</code> handlers.</p>
<p>What is possible though, is encoding the items identity in color, picking the current color under the mouse, and working back to get to the <code>__meta</code> field.</p>
<p>We can encode and decode limited (but huge) number of values in color using these two functions:</p>
<pre><code class="language-js">const encodeInColor = (num) => {
  const hex = num.toString(16).substr(0, 6);
  return `#${leftPad(hex, 6, "0")}`;
};

const decodeFromColor = (hex) => {
  return parseInt(`0x${hex}`);
};
</code></pre>
<p>We then create another, offscreen canvas, and draw on it using this encoded color, instead of the one selected by user:</p>
<pre><code class="language-js">const drawInspector = (state) => {
  let i = 0;

  const operations = sketch.draw(state);

  for (const operation of operations) {
    const [command, args] = operation;

    // replace fill and stroke with index encoded in color
    const inspectorArgs = Object.assign(args, {
      fill: args.fill ? encodeInColor(i) : undefined,
      stroke: args.stroke ? encodeInColor(i) : undefined,
    });

    if (COMMANDS[command]) {
      COMMANDS[command](ctx, inspectorArgs);
    }

    i++;
  }
};
</code></pre>
<p>We can then pick the color from where the mouse is:</p>
<pre><code class="language-js">const onHover = (x, y) => {
  const data = ctx.getImageData(x, y, 1, 1).data.slice(0, 3);
  const hex = Array.from(data)
    .map((n) => leftPad(n.toString(16), 2, "0"))
    .join("");

  return decodeFromColor(hex);
};
</code></pre>
<p>And then, once we have the index back, we can grab a relevant item from what sketch <code>draw</code> function returns, and pick out it's <code>__meta</code> value, to highlight the code.</p>
<p>It's a bit of long-winded process, but worth it, as it removes the need to keep a tab on where which piece of graphic comes from — something that in my opinion is unnecessary mental requirement while writing code.</p>
<h2>Direct manipulation</h2>
<p>Direct manipulation is how most of non-developer software works.
If you want to move something in Photoshop, you just drag it over directly on the canvas; if you want to change a volume in Ableton you just drag a slider in the mixer.
Same when changing fonts in Word, making slides in Powerpoint, etc.</p>
<p>Unfortunately, with programming we are stuck with indirect manipulation, the infamous cycle of change code, reload, test, change code...</p>
<p>With Dacein I tried to bring a bit of direct manipulation when working with sketches, mainly it shouldn't be required to go back to code, just to move something on the screen.
When the sketch is paused, anything that has a <code>pos</code> attribute can be selected, and dragged around (with some caveats).</p>
<div class="mb3 ba b--light-gray br2" style="background:#101010; display:inline-block;">
  <video loop autoplay muted class="pa3 bw0" style="max-width:calc(100% - 2rem)">
    <source src="https://szymonkaliski.com/writing/2019-03-01-building-dacein/uncmin.mp4" type="video/mp4">
  </video>
</div>
<p>Dacein tries to come up with new code constants within the <code>draw</code> function that fit where the dragged object should be.
This is achieved using unconstrained optimisation (thanks to <code>uncmin</code> from <a href="http://freeman2.com/numjsdoc.htm">numeric.js</a>).</p>
<p>The optimiser is run on a draw function, and tries to minimise the distance between the mouse and currently dragged object.</p>
<p>For <code>uncmin</code> to work, we need a few things:</p>
<ul>
<li>a function to optimise</li>
<li>the initial set of parameters</li>
<li>a way to encode how far we are from the target solution</li>
</ul>
<p>In this case, the function we're optimising is the <code>draw</code> part of the sketch, and the thing we're optimising are the numeric constants within it.
Usually premature optimisation is not a good idea, but here I knew that replacing the constants in text, and evaluating the modified code again to get the results, would slow down the process a lot.
I wrote another AST transform, that walks through all the numbers in <code>draw</code>, and pulls them out into an array, transforming:</p>
<pre><code class="language-js">const draw = (state) => {
  const a = 20;

  return [["rect", { pos: [a, 10] }]];
};
</code></pre>
<p>Into:</p>
<pre><code class="language-js">const draw = (state, constants) => {
  const a = constants[0];

  return [["rect", { pos: [a, constants[1]] }]];
};
</code></pre>
<p>Basically parametrising the code constants.
This is invisible to the user, but allows me to run <code>uncmin</code> more efficiently.
The relevant AST transform code <a href="https://github.com/szymonkaliski/dacein/blob/master/src/ast-transforms.js#L198-L263">is here</a>.</p>
<p>The actual magic itself is a fairly straightforward, short piece of code:</p>
<pre><code class="language-js">const minimised = uncmin((newConstants) => {
  // "draws" the sketch with current state, and constants provided by uncmin
  const drawCalls = sketch.draw(state, newConstants);

  // simple wrapper to get the position of a draw call with given index
  const position = getPosition(drawCalls, id);

  return dist(position, mousePosition);
}, currentConstants);

// minimised.solution is a new set of constants,
// where the distance between position and mousePosition is closest to zero
</code></pre>
<p>With some optimisations this works surprisingly well, and makes me wonder why most of our software is not made this way.</p>
<p>If you're interested in working with constraint optimisation, a good place to start would be <a href="https://en.wikipedia.org/wiki/Cassowary_(software)">cassowary</a>, and for not only coming up with parameters, but actually generating new code, <a href="http://minikanren.org/">miniKanren</a> is worth taking a look at.</p>
<h2>Technical notes</h2>
<p>Finally, some smaller technical notes from making Dacein.</p>
<p><code>eval</code> was obviously a huge part of the project, and working with it safely was important, so the IDE doesn't crash.
There are three <code>try {} catch()</code> blocks happening before the running code is actually replaced:</p>
<ol>
<li>all AST transforms are wrapped in <code>try</code> as the code might be malformed, and the parser might fail</li>
<li>after that the actual <code>eval</code> is also placed in <code>try</code> to make sure nothing goes wrong</li>
<li>lastly, when the <code>sketch()</code> command is executed it first tries to run <code>draw(update(initialState))</code> in hopes of finding some runtime errors</li>
</ol>
<p>The relevant code <a href="https://github.com/szymonkaliski/dacein/blob/master/src/app.js#L28-L103">is here</a>.</p>
<p>To make the system a bit more open, I implemented a way to use <code>require</code>, thanks to <a href="https://github.com/d3/d3-require"><code>d3-require</code></a> and <a href="https://bundle.run">bundle.run</a>.
I wanted to allow users to use familiar <code>const _ = require("lodash")</code> calls, but <code>d3-require</code> returns a <code>Promise</code> instead of happening synchronously.
I wrote yet another small AST transform that turns this code:</p>
<pre><code class="language-js">const _ = require("lodash");
const vec2 = require("gl-vec2");

sketch({
  // ...
});
</code></pre>
<p>Into:</p>
<pre><code class="language-js">require("lodash").then((_) => {
  require("gl-vec2").then((vec2) => {
    sketch({
      // ...
    });
  });
});
</code></pre>
<p>And that was all that was needed to make this work; everything works on client side, and there's no need for a special server and bundling.
You can test it out with the <code>particle system</code> example which uses <code>gl-vec2</code> for some calculations.</p>
<p>Least importantly, the whole app was written using still fresh React hooks, excluding the actual sketch container, where combining internal state, function calls to parent, and orchestrating <code>requestAnimationFrame</code> was easier for me to be done using <code>React.Component</code>.
You can browse this part of code <a href="https://github.com/szymonkaliski/dacein/blob/master/src/sketch-container.js">here</a>, it's using a lot of discouraged techniques (like <code>componentWillReceiveProps</code> or <code>shoulComponentUpdate() { return false }</code>), but sometimes workarounds are required to get the proper user experience.</p>
<h2>Fin.</h2>
<p>Dacein is yet another project that is nowhere near being production ready, but hopefully, shows some interesting ideas, and also shows that it's possible to play with those things in relatively short timeframes.
It took about 35 hours to build, working after hours and on the weekends.</p>
<p>Dacein is also the first thing made in my 2019 meta-project of bimonthly projects.
Unsurprisingly, it feels much more relaxed that my monthly projects in 2017, and also more focused than the last year where I was just trying to do <em>something</em> every day.</p>
<p>I had a lot of fun putting a few different ideas together, and seeing them work well.
There are some leftover lower-hanging fruits, like a future-parity of the <code>sketch</code> library to what 2d canvas exposes and squashing some bugs.</p>
<p>For now, I'm moving to the next project, leaving this one open-sourced: <a href="https://github.com/szymonkaliski/dacein/">szymonkaliski/dacein</a>, and available online: <a href="https://szymonkaliski.github.io/dacein/">szymonkaliski.github.io/dacein</a>.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2019-03-01-building-dacein/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2019-03-01-building-dacein/</guid>
            <pubDate>Fri, 01 Mar 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Dacein]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/dacein/screen.png" alt="Screenshot" width="1540" height="1140">
<p><a href="http://szymonkaliski.github.io/dacein/">Dacein</a> is an experimental creative coding IDE combining few different ideas together:</p>
<ul>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#library">functional creative coding library</a></li>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#time-travel">time travel abilities</a></li>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#livecoding">livecoding editor</a></li>
<li><a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/#direct-manipulation">direct manipulation</a></li>
</ul>
<p>It borrows heavily for <a href="https://processing.org">Processing</a>, <a href="https://p5js.org">p5</a>, and <a href="https://reactjs.org">React</a>.</p>
<p>Sketches are created in a functional, declarative style, which allows the system to record state changes, and gives the user ability for easy time travel and livecoding.</p>
<p>Additionally, the user can directly manipulate the sketch and thanks to the magic of <a href="http://freeman2.com/numjsdoc.htm">unconstrained optimization</a> the system is able to create new code constants:</p>
<video loop autoplay muted>
  <source src="https://szymonkaliski.com/projects/dacein/uncmin.mp4" type="video/mp4">
</video>
<p>You can read more about the process and ideas behind making this project in this leanghty article: <a href="https://szymonkaliski.com/writing/2019-03-01-building-dacein/">building dacein</a>.</p>
<p>Code is open sourced: <a href="https://github.com/szymonkaliski/dacein">szymonkaliski/dacein</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/dacein/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/dacein/</guid>
            <pubDate>Fri, 01 Mar 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Laboratory Residency]]></title>
            <description><![CDATA[<p>I was quite tired after last year, where I worked on monthly projects and pushed hard to publish something every month.
I also knew that this year would be a bit different due to my personal life, so I had to plan accordingly.
I decided to aim for working on one personal project every day, but without any tight deadlines; this could be reading a research paper, exploring some technology if I had time, or playing a bit of music.</p>
<p>This, combined with publishing <a href="https://soundcloud.com/szymonkaliski/sets/studio-diary-2018">weekly studio diary of music sketches</a>, was both easy enough that I knew I could do it, but also kept me accountable.</p>
<p>But still, I missed longer, more focused projects, so I was very happy to be invited for the residency, where I could spent four weeks of focused work on whatever I wanted.</p>
<p>I spent the whole August 2018 in Spokane, Washington at <a href="https://laboratoryspokane.com/">Laboratory</a>, working on open source creative coding tools.</p>
<h2>The project</h2>
<p>I had a very rough idea of what I wanted to do when I arrived.
Few years ago I was exploring 3D growth, and wanted to continue that idea through building my own tools that would allow me to create organic 3D shapes.</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/old-1.jpg" width="640" height="640">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/old-2.jpg" width="640" height="640">
  </div>
</div>
<p>First week was full of learning in the most frustrating way — trying and failing over and over again.
I still didn't know what exactly I wanted to do, and was exploring different techniques.
I finally settled on using SDFs (signed distance fields) after short research on meshing <a href="https://en.wikipedia.org/wiki/Isosurface">isosurfaces</a>.</p>
<p>After I settled on a technique, I quickly realised that what I really need is a language that would allow me to create SDF models without the need to touch GLSL.</p>
<p>I also wanted to be able to run them on CPU or GPU, and mesh them with the simplest possible API.</p>
<p>One thing that helped me a lot, was starting from imagining and sketching how the API could work like, and then building it to fit my needs.
I would create <code>notes.md</code> file, sketch out a few different approaches with comments, and then try to implement the one that looked the most promising.
I was keeping dates in those files as well, it's interesting to read them after some time, here's where I realised that <code>hiccup</code>-like language could work:</p>
<pre>## 2018-08-11

Thinking of using hiccup-like syntax for building geometries:

```js
const geom = [
  unionRound,
  { r: 0.02 },
  [
    [sdSphere, { r: 0.1, p: [0.0, 0.2, 0.3] }]
    [sdCube, { p: [0.0, 0.2, 0.3], s: [1.0, 1.0, 1.0] }]
  ]
];
```

And for larger datasets:

```js
const geom = [
  withDataset,
  {
    data: somePositions,
    op: [opUnionRound, { r: 0.02 }],
    mapper: [mapProp, { prop: "p" }, sdSphere, { r: 0.01 }]
  }
];
```
</pre>
<p>One of important things for me to solve with this system was the ability to use large datasets.
Creating GLSL from trees like that is fairly straightforward, but there are limitations of the size of GLSL shader, and number of instructions that can be executed on GPU, and I was hitting it often.</p>
<p>The solution at the time was <code>withDataset</code> instruction that later was changed to <code>map</code>, and from the user standpoint works like <a href="https://en.wikipedia.org/wiki/MapReduce">MapReduce</a> — one functions maps over all the data, and then second one reduces it into single value.
Behind the scenes I'm turning this into floating point data texture uploaded to GPU, and then stepping over it in the shader.
This allowed me to radically improve number of data points that I can use with this technique, although it obviously has its own limitations.</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/data-1.png" width="800" height="800">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/data-2.png" width="800" height="800">
  </div>
</div>
<h2>Metatools</h2>
<p>It was really nice to have enough time to be able to tackle related (but not really) problems that I was hitting while developing the main project.
For example, I didn't want to wait for requesting/processing large datasets so I wrote <a href="https://github.com/szymonkaliski/persistent-memo"><code>persistent-memo</code></a> to memoize results of functions where input parameters or function body don't change, and persist it over reloads (either in <code>localStorage</code> or on filesystem).</p>
<p>Another issue that I was hitting, was jumping between different sketches, or running multiple different local server instances.</p>
<p>I solved this by creating <a href="https://szymonkaliski.com/projects/sketchbook-cli/"><code>sketchbook-cli</code></a> which provides automatic gallery of screenshots on top of folder of flat javascript sketch files.
I could see all the sketches I've explored at the same time, and this sped up my workflow a lot, especially since some of the SDF geometries are expensive to render.</p>
<img src="https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/sketchbook.png" alt="" width="1460" height="1305">
<h2>Learnings</h2>
<p>I've learned some important lessons as well.
First of all, a month of residency sounds like a long time, and I was even planning smaller "downtime" projects, but I've obviously never got to them, I barely had time to finish the main project.</p>
<p>Next time, I would probably aim for either fully research/learning related residency, or one where I know almost everything, and produce artwork.
I've tried to combine both, and ended up only building the tools, without ever actually making anything bigger with them.</p>
<h2>Fin</h2>
<p>All of the tools I developed through the residency are now open sourced:</p>
<ul>
<li><a href="https://github.com/szymonkaliski/hiccup-sdf">szymonkaliski/hiccup-sdf</a> - main tool for modeling with SDFs</li>
<li><a href="https://github.com/szymonkaliski/persistent-memo">szymonkaliski/persistent-memo</a> - memoization that persists over reloads</li>
<li><a href="https://github.com/szymonkaliski/sketchbook-cli">szymonkaliski/sketchbook-cli</a> - sketchbook with gallery</li>
<li><a href="https://github.com/szymonkaliski/behaviours">szymonkaliski/behaviours</a> - experimental declarative behaviour modeling that I explored briefly (work in progress)</li>
</ul>
<p>I also got a chance to play a few music gigs in the US, where I presented new material that I've been working on together with the studio diary project.</p>
<p>I'd definitely want to go for another residency.
As usual, working on one thing brings up ten new ideas, and my notebook is only getting bigger.
There's something really nice about being able to set aside everything, and allow myself to work around the clock while exploring and learning.</p>
<p>This for sure is not sustainable long-term, but for a month or two, it allows me to create larger chunks of work and not feel burned out, or as if I were avoiding my responsibilities.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/</guid>
            <pubDate>Tue, 27 Nov 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[hiccup-sdf]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/hiccup-sdf/miniature.png" alt="" width="1036" height="583">
<p><a href="https://github.com/szymonkaliski/hiccup-sdf">hiccup-sdf</a> is set of open source tools made for creating, displaying and exporting 3d models made with SDFs.</p>
<p>It's another iteration of my exploration of SDFs started with <a href="https://szymonkaliski.com/projects/sdf-ui/">SDF-UI</a>.</p>
<p>This project consists of three libraries:</p>
<ul>
<li><code>hiccup-sdf</code> - main library providing simple language for building models</li>
<li><code>display-sdf</code> - utility for displaying SDFs</li>
<li><code>hiccup-sdf-to-obj</code> - utility for exporting <code>hiccup-sdf</code> models to OBJs, for 3d printing or other uses</li>
</ul>
<p>Modeling is done with language inspired by <a href="https://github.com/weavejester/hiccup">hiccup</a>, adapted to use in javascript:</p>
<pre><code class="language-js">const { displayRaw } = require("display-sdf");
const { compileShader, glslHelpers } = require("hiccup-sdf");

const translatedSphere = (t, r) => ["translate", { t }, [["sphere", { r }]]];

const shape = [
  "repeatPolar",
  { r: 10 },
  [
    [
      "translate",
      { t: [0.5, 0, 0] },
      [
        [
          "intersection",
          {},
          [
            ["box", { s: [0.1, 0.1, 0.1] }],
            translatedSphere([0.15, 0, 0], 0.2),
          ],
        ],
      ],
    ],
  ],
];

const { inject, model } = compileShader(shape);
const shader = glslHelpers.createShaderFull(model, inject);

displayRaw(shader);
</code></pre>
<p>SDFs can be meshed using <a href="https://en.wikipedia.org/wiki/Isosurface#Surface_Nets">surface nets</a> and <code>hiccup-sdf-to-obj</code> provides set of tools to help with that, and export 3d-printer ready models:</p>
<img src="https://szymonkaliski.com/projects/hiccup-sdf/obj.png" alt="" width="1091" height="614">
<p>For more information and examples go to github: <a href="https://github.com/szymonkaliski/hiccup-sdf">szymonkaliski/hiccup-sdf</a>.</p>
<p>This project was developed in part at Laboratory, an artist residency for interactive arts: <a href="https://laboratoryspokane.com/">laboratoryspokane.com</a>.
You can read more about my time in Spokane in this blog post: <a href="https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/">Laboratory Residency</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/hiccup-sdf/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/hiccup-sdf/</guid>
            <pubDate>Sun, 25 Nov 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[HHTWM]]></title>
            <description><![CDATA[<video loop autoplay muted>
  <source src="https://szymonkaliski.com/projects/hhtwm/video.mp4" type="video/mp4">
</video>
<p>I've built my own window manager for macOS that gives me layout-based automatic tiling.</p>
<p>Not having to think about placing windows on the screen, and having everything always visible, has been a huge boost for me.</p>
<p><code>HHTWM</code> is library with small API to be used within larger <a href="http://www.hammerspoon.org">Hammerspoon</a> configuration.</p>
<p>It's open sourced and well documented: <a href="https://github.com/szymonkaliski/hhtwm">szymonkaliski/hhtwm</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/hhtwm/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/hhtwm/</guid>
            <pubDate>Sat, 03 Nov 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sketchbook]]></title>
            <description><![CDATA[<p><code>sketchbook-cli</code> is a tool for organising, editing and displaying code-based sketches in real-time.</p>
<p>It complimentes live-reloading with live-screenshotting capabilities, providing a gallery with previews generated from code.</p>
<p>The tool was built to help me <em>see</em> all the sketches that I'm working on, as I usually create a bunch of small random files to test ideas and play around.</p>
<p>These files are usually named either <code>0001.js</code> or <code>20181029-1814.js</code>, so being able to see what they all output at the same time removes a lot of friction from my sketching workflow.</p>
<p><code>sketchbook-cli</code> is open sourced: <a href="http://github.com/szymonkaliski/sketchbook-cli">szymonkaliski/sketchbook-cli</a>, and can be installed via <code>npm</code>: <code>npm install -g sketchbook-cli</code>.</p>
<img src="https://szymonkaliski.com/projects/sketchbook-cli/screenshot.png" alt="" width="1460" height="1305">
<p>Most of the live-reload code was adapted from <a href="https://github.com/mattdesl/budo">budo</a>.</p>
<p>This project was developed in part at Laboratory, an artist residency for interactive arts: <a href="https://laboratoryspokane.com/">laboratoryspokane.com</a>.
You can read more about my time in Spokane in this blog post: <a href="https://szymonkaliski.com/writing/2018-11-27-laboratory-residency/">Laboratory Residency</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/sketchbook-cli/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/sketchbook-cli/</guid>
            <pubDate>Wed, 29 Aug 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Editable]]></title>
            <description><![CDATA[<p><code>editable-cli</code> is a command line tool piggybacking on <a href="http://observablehq.com/">observable</a> internals which provides file-based interactive notebooks.</p>
<p>User has access to new top-level function: <code>def</code>. This function is used to define constants and functions which are live-reloaded, with persisted state (unless the body of the function has changed):</p>
<pre><code class="language-js">def("a", 10);
def("b", 20);
def("sum", (a, b) => a + b); // sum is "tied" to defs "a" and "b" here
</code></pre>
<p>This environment is ideal for quick sketches and explorations. It provides all that observable exposes, including DOM access and more.</p>
<p>File-based notebooks have few additional nice properties:</p>
<ul>
<li>they work offline, even if the online serivce goes out of business</li>
<li>they compose well with standard javascript tools: <code>prettier</code>, <code>eslint</code>, etc.</li>
</ul>
<p><code>editable-cli</code> is open sourced: <a href="http://github.com/szymonkaliski/editable-cli">szymonkaliski/editable-cli</a>, and can be installed via <code>npm</code>: <code>npm install -g editable-cli</code>.</p>
<img src="https://szymonkaliski.com/projects/editable-cli/screenshot.png" alt="Screenshot" width="1140" height="1045">
<pre><code class="language-js">def("chart", (DOM, data, margin, d3, yAxis, xAxis, y, x, width, height) => {
  const svg = d3.select(DOM.svg(width, height));

  svg
    .append("g")
    .attr("fill", "#444")
    .selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", x(0))
    .attr("y", (d) => y(d.name))
    .attr("width", (d) => x(d.value) - x(0))
    .attr("height", y.bandwidth());

  svg
    .append("g")
    .attr("fill", "white")
    .attr("text-anchor", "end")
    .style("font", "12px sans-serif")
    .selectAll("text")
    .data(data)
    .enter()
    .append("text")
    .attr("x", (d) => x(d.value) - 4)
    .attr("y", (d) => y(d.name) + y.bandwidth() / 2)
    .attr("dy", "0.35em")
    .text((d) => d3.format(".3f")(d.value));

  svg.append("g").call(xAxis);
  svg.append("g").call(yAxis);

  return svg.node();
});

def("margin", { top: 30, right: 0, left: 30, bottom: 10 });
def("height", (data, margin) => data.length * 18 + margin.top + margin.bottom);
def("width", 600);

def("alphabet", (require) => require("@observablehq/alphabet"));
def("d3", (require) => require("d3"));

def("yAxis", (d3, margin, y) => (g) => {
  return g
    .attr("transform", `translate(${margin.left},0)`)
    .call(d3.axisLeft(y).tickSizeOuter(0));
});

def("xAxis", (d3, margin, x, width) => (g) => {
  return g
    .attr("transform", `translate(0,${margin.top})`)
    .call(d3.axisTop(x).ticks(width / 80))
    .call((g) => g.select(".domain").remove());
});

def("y", (d3, margin, data, height) => {
  return d3
    .scaleBand()
    .domain(data.map((d) => d.name))
    .range([margin.top, height - margin.bottom])
    .padding(0.1);
});

def("x", (d3, margin, data, width) => {
  return d3
    .scaleLinear()
    .domain([0, d3.max(data, (d) => d.value)])
    .range([margin.left, width - margin.right]);
});

def("data", (alphabet) => {
  return (alphabet || [])
    .slice()
    .sort((a, b) => b.frequency - a.frequency)
    .map(({ letter, frequency }) => ({ name: letter, value: frequency }));
});
</code></pre>]]></description>
            <link>https://szymonkaliski.com/projects/editable-cli/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/editable-cli/</guid>
            <pubDate>Sun, 19 Aug 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[HOT Visualize Change]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/hot-visualize-change/screenshot.png" alt="Application screenshot" width="1280" height="921">
<p>I collaborated with <a href="https://www.hotosm.org/">Humanitarian OpenStreetMap</a> to design and build an online tool for tracking changes made to OpenStreetMaps map layers.</p>
<p>The tool allows users to start quickly by selecting one of predefined modes (last week, month, year), focusing on relevant viewport, and sharing the output. For experienced users we expose options to play with colors, map styles, the length, and speed of the animation.</p>
<p>Visualization can be shared both as a link to online version, and as a video/gif static export, which makes it ideal for embedding on websites or in presentations.</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/hot-visualize-change/render.mp4" type="video/mp4">
</video>
<p><a href="https://flow-control.io">flow/control</a> was responsible for the design and development of this project, from start to finish.
The different parts of the system are containerized and communicate through API calls, and RabbitMQ queue.
Offline rendering uses exactly the same code as the frontend, but is executed within offscreen Electron instance, which allowes us to grab each of the frames, and compose them into static video or gif file.</p>
<p>The tool is available online: <a href="http://visualize-change.hotosm.org">http://visualize-change.hotosm.org</a>, and the code is open sourced: <a href="https://github.com/hotosm/visualize-change">hotosm/visualize-change</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/hot-visualize-change/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/hot-visualize-change/</guid>
            <pubDate>Wed, 16 May 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[CRLN]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/crln/screenshot.png" alt="Screenshot" width="1900" height="1071">
<p><a href="http://szymonkaliski.github.io/CRLN/">CRLN</a> is an experiment in bending curl noise on the GPU (desktop Chrome only).</p>
<p>Particle movement is calculated on the GPU using framebuffer ping-pong technique.</p>
<p>Movement is controlled by curl noise combined with rotation with varying parameteres that change over time, independently of each other, which creates endless combinations of values.</p>
<p>CRLN was built with <a href="https://threejs.org">THREE.js</a>.</p>
<p>Full source code: <a href="http://github.com/szymonkaliski/CRLN">szymonkaliski/CRLN</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/crln/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/crln/</guid>
            <pubDate>Sat, 07 Apr 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[MNTN]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/mntn/screenshot.png" alt="Screenshot" width="2286" height="1288">
<p><a href="http://szymonkaliski.github.io/MNTN/">MNTN</a> is a small experiment in creating procedural mountains.</p>
<p>Mountain generation begins with a 2d plane, that is then deformed by simplex noise.</p>
<p>Deformations are controlled by array of points and distances, which allowed me to have more control over final scene, even if the actual mountain shape is different on every visit.</p>
<p>MNTN was built with using simplex noise, and is rendered with <a href="https://threejs.org">THREE.js</a>.</p>
<p>Full source code: <a href="http://github.com/szymonkaliski/MNTN">szymonkaliski/MNTN</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/mntn/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/mntn/</guid>
            <pubDate>Sat, 10 Mar 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[DIY Monome]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/diy-monome/miniature.jpg" alt="Photo" width="1280" height="720">
<p>I've built two DIY Monome clones as last project of my 2017 one-project-a-month challenge.</p>
<p>More info in the detailed <a href="https://szymonkaliski.com/writing/2018-01-28-diy-monome/">blog post</a>, and full source code and instructions on github: <a href="http://github.com/szymonkaliski/diy-monome">szymonkaliski/diy-monome</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/diy-monome/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/diy-monome/</guid>
            <pubDate>Sun, 28 Jan 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[DIY Monome]]></title>
            <description><![CDATA[<p>Building my own Monome has been the last of my monthly projects in 2017.
It was also the only project that grew horribly out of scope, that's why I'm documenting it almost a month later.</p>
<img src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/monomes.jpg" alt="" width="1280" height="720">
<h2>Intro</h2>
<p>I remember when the first Monome came out around 2007, a simple (and not necessarily new) idea of grid with 64 buttons and 64 LEDs behind them. It was a beautiful little controller, fully programmable, and I dreamed of getting one.</p>
<p>It was around the time when I started experimenting with max/msp and making my own music, but I've never bought one.</p>
<p>Since then, Monome has created a lot of different devices, from Monome companion — <a href="https://market.monome.org/collections/primary/products/arc">arc</a>, to fully programmable DSP computer (<a href="https://monome.org/aleph/">aleph</a>), and recently a lot of modular hardware.</p>
<p>For a while Monome was quite popular in music-making scene, and at some point there was an effort around <code>arduinome</code> project, which provided Arduino code and build instructions for building DIY Monomes.
With appearance of Launchpad and other cheap grid-based controllers that project died off.</p>
<p>I kept thinking about getting one of them at some point, and by accident, stumbled upon <a href="https://www.sparkfun.com/products/8033">Sparkfun 4x4 PCB</a>, and later at <a href="https://www.adafruit.com/product/1616">Adafruid 4x4 PCB</a> and decided to finally build my own.</p>
<h2>Building Sparknome</h2>
<p>I bought four Sparkfun boards, along with some RGB LEDs and diodes, and started assembling single 4x4 board first.
Sparkfun PCBs are build to support scan matrix technique, where each column is queried one by one, reading values of all the rows in that column.
If this is done very fast, user has a feeling of near-immediate feedback, and button grid can be driven with relatively few connections.
I started by wiring single 4x4 grid, connecting four rows and four columns, testing and rewriting <a href="https://learn.sparkfun.com/tutorials/button-pad-hookup-guide#exercise-1-monochrome-leds">the code provided by Sparkfun</a>.</p>
<video loop autoplay muted>
  <source src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/sparknome-4x4.mp4" type="video/mp4">
</video>
<p>Next step was connecting four 4x4 grids together to form big 8x8 grid.
Unfortunately, Sparkfun didn't prepare the board for this (by, for example, providing paths to wire the boards together like Adafruit does), so I had to do a lot of wiring, and it didn't go too well.
I'm pretty sure I could redo it in a much nicer way, but I was rushing to get the prototype working.</p>
<img src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/sparknome-wiring.jpeg" alt="" width="1280" height="960">
<p>Next step was designing, and 3d-printing the case, since the boards were only connected by wires, the whole structure felt very fragile.
As the case was a simple rectangle with holes for buttons and screws, I thought it would make sense to design it in code.
I already played a with CSG (constructive solid geometry), some time ago while exploring <a href="http://thi.ng">thi.ng</a> clojure libraries, and later while building <a href="https://szymonkaliski.com/projects/sdf-ui/">SDF-UI</a>.</p>
<p>For this project I went with <a href="https://github.com/jscad/csg.js/">csg.js</a> library combined with <a href="https://threejs.org/">three.js</a> for live preview.
Rendering required me to figure out how to convert csg.js polygons to three.js geometry:</p>
<pre><code class="language-js">const geometryFromPolygons = (polygons) => {
  const geometry = new Geometry();

  const getGeometryVertice = (geometry, v) => {
    geometry.vertices.push(new Vector3(v.x, v.y, v.z));
    return geometry.vertices.length - 1;
  };

  for (i = 0; i &#x3C; polygons.length; i++) {
    let vertices = [];

    for (let j = 0; j &#x3C; polygons[i].vertices.length; j++) {
      vertices.push(getGeometryVertice(geometry, polygons[i].vertices[j].pos));
    }

    if (vertices[0] === vertices[vertices.length - 1]) {
      vertices.pop();
    }

    for (let j = 2; j &#x3C; vertices.length; j++) {
      const face = new Face3(
        vertices[0],
        vertices[j - 1],
        vertices[j],
        new Vector3().copy(polygons[i].plane.normal)
      );

      geometry.faces.push(face);
    }
  }

  geometry.computeVertexNormals();
  geometry.computeBoundingBox();

  return geometry;
};
</code></pre>
<p>This code basically iterates over all the polygons, adding them to geometry one by one, and remembering the indexes for creating faces.
Generating the csg geometries was quite fun, for example, to get the rectangle with button holes, I started with a simple cube:</p>
<pre><code class="language-js">const genCasing = ({ caseHeight, caseSize }) => {
  return CSG.cube({
    corner1: [0, 0, -caseHeight],
    corner2: [caseSize, caseSize, 0.0],
  });
};
</code></pre>
<p>And then cut out the buttons:</p>
<pre><code class="language-js">let casing = genCasing({
  caseHeight: CASE_HEIGHT,
  caseSize: CASE_SIZE * MONOME_SIZE_MOD,
});

// button holes
let buttons = [];

times(8).forEach((i) =>
  times(8).forEach((j) => {
    const x = i * (BUTTON_SIZE + BUTTON_OFFSET) + BUTTON_CASE_OFFSET;
    const y = j * (BUTTON_SIZE + BUTTON_OFFSET) + BUTTON_CASE_OFFSET;

    const button = CSG.cube({
      corner1: [0, 0, 1],
      corner2: [BUTTON_SIZE, BUTTON_SIZE, -1],
    }).transform(CSG.Matrix4x4.translation([x, y, 0]));

    casing = casing.subtract(button);
  })
);
</code></pre>
<p>I also added some debugging information to the preview, so I could see not only the final shape, but also all the "helper" geometries used to cut out things:</p>
<img src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/csg.png" alt="" width="1380" height="1220">
<p>Three.js <code>GridHelper</code>s were very helpful in making sure my measurements were correct.
I was using a ruler to measure the PCB, and then recreating the shapes in 3D.</p>
<p>Once the case model was done, and I got the STL export working, I spent a few days playing with different Ultimakers Cura options to get the print working on my 3D printer.
It was quite a challenge since the exported model was 20cm x 20cm — exactly the size of my printers heated bed.
The solution was to disable any brim printing, and disable the printer from avoiding zero distance from the rim of the bed.</p>
<video loop autoplay muted>
  <source src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/3d-printing.mp4" type="video/mp4">
</video>
<p>Next step was to get this thing to talk through serial in a way that <code>serialoscd</code> understands, so it can communicate with hundreds of max/msp patches available online.
Luckily, Monome provides serial reference online: <a href="https://monome.org/docs/serial.txt">monome.org/docs/serial.txt</a>, and I also found one implementation on github by Mike Barela: <a href="https://github.com/TheKitty/Untz_Monome"><code>Untz_Monome</code></a>, that I could use as a starting point.
To get <code>serialoscd</code> on my system, I used <a href="https://monome.org/docs/linux/">linux instructions</a> for compiling it by hand, which boils down to <code>git clone</code>, <code>./waf configure</code> and <code>./waf install</code>.
<code>serialoscd</code> is also available on homebrew, but I wanted to have access to the source code, so I could debug it while trying to understand what's happening.</p>
<p>I quickly stumbled upon the first bigger issue, as <code>serialoscd</code> recognises the device as Monome based on FTDI name, I had two solutions, either flash my Arduino FTDI eeprom, or hack around this in <code>serialoscd</code>.
I chose the latter, and luckily the change required was single-line update in <code>devices.h</code>:</p>
<pre><code class="language-cpp">static monome_devmap_t mapping[] = {
  ...
  /* diy monome */
  {"%d", "mext", {0, 0}, "monome i2c", NO_QUIRKS},
}
</code></pre>
<p>This basically recognises any device with some numbers in the name as Monome — this probably would lead to some problems further down the road, but worked for now.</p>
<p>I also had some problems establishing proper "handshake" between Arduino and <code>serialoscd</code>, that I fixed by just increasing the timeout that <code>serialoscd</code> waits for response for the device.
I suspect that official monomes are much faster at processing serial messages than the code I wrote for Arduino.</p>
<img src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/monome-home.png" alt="" width="675" height="553">
<p>After all of this, I finally got my Sparknome to appear in <a href="https://github.com/monome-community/monome-home">Monome Home</a>.
From there on it was few more hours to get all the messages to properly send both ways, and I had working Monome clone on my hands.</p>
<p>Well, it wasn't working completely, due to my hardware wiring issues, but at that point I already ordered Adafruit based boards, so I decided to build a second one, before deciding if I should work on that wiring.</p>
<h2>Building Trellinome</h2>
<p>Soldering Trellinome was much quicker, mainly because there was much less to solder — only the LEDs, and few pins to connect the boards together.
The important point was shortening the jumpers at the back of the boards, so they can <a href="https://learn.adafruit.com/adafruit-trellis-diy-open-source-led-keypad/tiling#changing-addresses">address properly</a>.
For Arduino, I went with much, much smaller Arduino Pro Mini (5V version, since the boards are poweresd by 5V).</p>
<img src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/trellinome.jpg" alt="" width="1280" height="720">
<p>I slightly modified the code for case generation, and printing was also much simpler because Trellinome is smaller compared to Sparknome.</p>
<p>Overall, I had the board ready and seemingly working in just a few evenings of work, but there was one problem I discovered while testing: if some <code>mext</code>-compatible application flood the serial connection, the <code>serialoscd</code> would hang, and stop sending messages to Arduino.
I was pretty sure the Arduino itself wasn't a problem, since key events were still flowing back to the applications, just the display wasn't refreshing.</p>
<p>I spent a few good days trying to debug <code>serialoscd</code> and find the culprint, but in the end I decided to try and write my own replacement.</p>
<p>I went with my familar ecosystem of node, <a href="https://github.com/node-serialport/node-serialport">node-serialport</a> and <a href="https://github.com/deanm/omgosc">omgosc</a> for this.
After getting basic communication with Monome, I spent quite some time trying to understand all the endpoints that <code>serialoscd</code> supports.
I set up two different scripts that I used to grab all the messages flying between serialoscd and max/msp patch.
I first recorded initial sequence of messages from <code>serialoscd</code>, then re-played them to <code>Monome Home</code> to get next batch of messages, and so on, until I found out what execatly was happening.
I could call this "paused" man-in-the-middle attack, but I really wanted to be able to not only see the messages, but also send different ones to understand the replies.</p>
<img src="https://szymonkaliski.com/writing/2018-01-28-diy-monome/node-serialoscd.png" alt="" width="900" height="740">
<p>In the end, it took me some time to test my <code>serialoscd</code> implementation with a few different scripts, but I'm happy to say it works with everything that I needed it to, and doesn't hang when flooded with messages.</p>
<h2>Fin.</h2>
<p>This project was extremely fun, but also took way more time that I anticipated.
I started with the idea of building working prototype in first half of December, and then making some music with it, but that music-making part didn't happen until mid January.</p>
<p>Either way I'm very happy with my final Trellinome, it's really nice to play with, but I suspect it's nowhere near the quality of official Monome hardware.</p>
<p>This project also concludes my one-project-a-month experiment, and I'm moving on to different goals in 2018.</p>
<p>I'm going to write some kind of summary of 2017 at some point in the future, but for now, I plan on taking some time off of writing long blog posts.</p>
<p>As usual, the code is open sourced on github: <a href="https://github.com/szymonkaliski/diy-monome">szymonkaliski/diy-monome</a>.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2018-01-28-diy-monome/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2018-01-28-diy-monome/</guid>
            <pubDate>Sun, 28 Jan 2018 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[FLSUN i3 3D Printer]]></title>
            <description><![CDATA[<p>I’ve been debating getting a 3D printer for quite some time, I thought that I might not use it that much to justify the expense.</p>
<p>This year, while doing one-project-a-month, my attitude towards this changed, and I realised that buying things that push me forward and make me learn is always worth the money.</p>
<h2>Hardware</h2>
<p>I found a cheap <a href="https://www.prusaprinters.org/prusa-i3/">Prusa i3</a> clone from <a href="http://www.flsun3dprinter.com/index.php?route=product/product&#x26;product_id=51">FLSUN</a> and ordered the DIY kit for November's project. Assembling the printer was a great fun as I love hardware projects and working with my hands.
I've spent a few enjoyable long evenings listening to podcasts and screwing it together.</p>
<p>Parts of instructions were hard to decipher (mostly due to not the greatest English translation) but overall, I managed to build it without any bigger problems.
Some of the connecting cables are very short (for example LCD connection to main board), so placing everything neatly on the frame was a bit of a challenge.</p>
<img src="https://szymonkaliski.com/writing/2017-12-04-flsun-i3-3d-printer/printer.jpg" alt="" width="1280" height="1280">
<h2>Software</h2>
<p>One of the biggest problems was connecting the printer to OSX.
I've wasted a few hours loading <code>kext</code>'s by hand trying to force OSX to see the device, and finally, I stumbled upon <a href="http://forums.reprap.org/read.php?4,728633">this thread</a> on RepRap forum, and <a href="https://blog.sengotta.net/signed-mac-os-driver-for-winchiphead-ch340-serial-bridge/">this driver</a> for <code>MKS Gen_L v1.0</code> board that the printer came with.</p>
<p>Instructions attached to the printer recommend use of <a href="https://www.repetier.com">Repetier</a> for printing, and <a href="http://slic3r.org">Slic3r</a> for slicing, but I've found that the recommended configuration setup is at best confusing (there are different settings presented as the recommended ones in different README files).</p>
<p>Luckily, someone on the <a href="https://www.facebook.com/groups/FLSUN3DP/">FLSUN Facebook group</a> suggested <a href="https://ultimaker.com/en/products/ultimaker-cura-software">Ultimaker Cura</a> as a replacement, since FLSUN i3 is compatible with Prusa i3.
Cura was much simpler to set up, and produced better print than combination of Slic3r and Repetier did for me.</p>
<h2>Fin.</h2>
<p>I'm pretty happy with my printer, and like I hoped, my <em>ideas</em> list grew with a few new entries while assembling and using it.</p>
<p>So far I only made a few test prints including <a href="https://www.thingiverse.com/thing:978876">simple spool holder</a>, and I plan on using it for making enclosure for my December project.
This will require getting into 3D modeling, and I'm excited to learn!</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-12-04-flsun-i3-3d-printer/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-12-04-flsun-i3-3d-printer/</guid>
            <pubDate>Mon, 04 Dec 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Learning Haskell part 2]]></title>
            <description><![CDATA[<p><a href="https://szymonkaliski.com/writing/2017-10-02-learning-haskell/">Learning Haskell</a> was one of my one-project-a-month projects in 2017.
I can't say I'm anywhere near fluent in the language, but it's been an interesting journey, and I've learned a lot of new concepts.</p>
<p>October was all about exploring different <em>creative-coding</em>-related uses of Haskell: famous live-coding environment — <a href="https://tidalcycles.org/">Tidal</a>, and (a bit less) famous graphics library — <a href="https://archives.haskell.org/projects.haskell.org/diagrams/">Diagrams</a>.</p>
<h2>Tidal</h2>
<p>Tidal is a live-coding environment for creating live music.
It's mostly sample-based, using <a href="https://github.com/musikinformatik/SuperDirt">SuperDirt</a> as a backend (which itself is <a href="https://supercollider.github.io/">SuperCollider</a> addon).</p>
<p>In Tidal, music is based around patterns — there's nine <em>channels</em> (named <code>d1</code> to <code>d9</code>) where they can be sent through to SuperCollider.
The most basic example is playing single sample every cycle:</p>
<pre><code class="language-hs">d1 $ sound "bd"
</code></pre>
<p>Complex patterns, in combination with audio effects, can create interesting small compositions:</p>
<pre><code class="language-hs">d1 $ fast "0.75" $ n "d3? d4*2 e3 a3 f3 c3?" # s "supersaw" # speed "0.3 0.2" # shape 0.6 # room 0.8 # delay 0.4
d2 $ fast "0.25" $ n "a2 ~ a1 ~ c2" # s "supersaw" # speed "-0.1" # room 0.9 # shape 0.9 # gain 0.9
d3 $ fast "1.5" $ n "d7 a7" # s "supersaw" # speed "-0.9" # room 0.2 # shape 0.9 # gain 0.5 # delay 0.8
</code></pre>
<p>I played with Tidal during first two weeks of October, going through <a href="https://github.com/tidalcycles/Tidal/blob/master/tutorial/tutorial.md">Tidal tutorial</a> and <a href="https://tidalcycles.org/patterns.html">Tidal patterns</a> documents.</p>
<p>Log of my experiments is available online: <a href="http://github.com/szymonkaliski/haskell-playground/tree/master/tidal">szymonkaliski/haskell-playground/tidal</a>.</p>
<p>Tidal, although extremely interesting as stand-alone project, didn't make me feel that I was gaining any Haskell knowledge.
It has its own set of functions and uses quite small part of Haskell language.</p>
<p>This is not something good nor bad, I feel that Tidal can be extremely productive and is quick to build up complex patterns of sounds, but after two weeks I wanted to explore more of Haskell itself.</p>
<h2>Diagrams</h2>
<p>Diagrams is Haskell's DSL for creating vector graphics.
I followed the <a href="https://archives.haskell.org/projects.haskell.org/diagrams/doc/quickstart.html">quick start tutorial</a>, and tried to build at least a simple graphic every day, first by making simple shapes, then patterns, and later using noise, and finishing the month with L-System implementation.</p>
<p>One thing I really enjoyed, is how terse Haskell can be. To build this shape:</p>
<img src="https://szymonkaliski.com/writing/2017-11-10-exploring-tidal-and-diagrams/patterns.svg" style="background-color:white;padding:40px" width="400" height="398">
<p>I only needed this:</p>
<pre><code class="language-hs">blackCircle = circle 0.1 # fc black
circleEdges w = atPoints (trailVertices $ regPoly w 1) $ repeat blackCircle

diagram :: Diagram B
diagram = foldr1 mappend $ map circleEdges [3,6..30]
</code></pre>
<p>I wouldn't say that terseness of a language signifies in any way how powerful it is, or that the amount of letters that have to be typed influences productivity in any way but, for me, shorter functions with little syntax, feel easier to read.</p>
<img src="https://szymonkaliski.com/writing/2017-11-10-exploring-tidal-and-diagrams/noise.svg" style="background-color:white;padding:40px" width="500" height="476">
<h2>L-System</h2>
<p>Last part of my two weeks with Diagrams was spent building simple <a href="https://en.wikipedia.org/wiki/L-system">L-System</a> from scratch.
I started with basic rule rewriting code:</p>
<pre><code class="language-hs">rules = Map.fromList [('F', "FF+[+F-F-F]-[-F+F+F]")]

getRule axiom = case Map.lookup axiom rules of
                     Just result -> result
                     Nothing -> [axiom]

genGeneration axiom = concat $ map getRule axiom

genGenerations :: Int -> [Char] -> [Char]
genGenerations 0 axiom = axiom
genGenerations n axiom = genGeneration (genGenerations (n - 1) axiom)
</code></pre>
<ul>
<li><code>rules</code> is a <code>Map</code> from axiom to some rule, <code>getRule</code> queries that <code>Map</code> and returns matching rule or input axiom if no rule is matching</li>
<li><code>genGeneration</code> (no idea what would be a good name for it) generates new axiom based on current one, by concatenating results of <code>getRule</code></li>
<li><code>genGenerations</code> (even worse name) runs <code>genGeneration</code> recursively <code>n</code> times (using awesome Haskell pattern matching)</li>
</ul>
<p>All this code can be tested in <code>ghci</code>:</p>
<pre><code class="language-hs">*Main> genGeneration "F"
"FF+[+F-F-F]-[-F+F+F]"

*Main> genGenerations 2 "F"
"FF+[+F-F-F]-[-F+F+F]FF+[+F-F-F]-[-F+F+F]+[+FF+[+F-F-F]-[-F+F+F]-FF+[+F-F-F]-[-F+F+F]-FF+[+F-F-F]-[-F+F+F]]-[-FF+[+F-F-F]-[-F+F+F]+FF+[+F-F-F]-[-F+F+F]+FF+[+F-F-F]-[-F+F+F]]"
</code></pre>
<p>The next thing that I needed was a <a href="https://en.wikipedia.org/wiki/Logo_%28programming_language%29">turtle</a>, following my L-System rules:</p>
<ul>
<li><code>F</code> - move forward and draw a line</li>
<li><code>G</code> - move forward without drawing a line</li>
<li><code>+</code> - turn right</li>
<li><code>-</code> - turn left</li>
<li><code>[</code> - save current position</li>
<li><code>]</code> - load last saved position</li>
</ul>
<p>I started by creating some types:</p>
<pre><code class="language-hs">type Angle = Double
type Position = (Double, Double)
data Turtle = Turtle Position Angle deriving Show
type TurtleStatus = (Turtle, [Diagram B], Stack Turtle)
</code></pre>
<ul>
<li><code>Angle</code> and <code>Position</code> should be self-explanatory - one is just an alias for <code>Double</code>, another is a tuple of two <code>Double</code>: <code>x</code>/<code>y</code> position</li>
<li><code>Turtle</code> contains <code>Position</code> and <code>Angle</code></li>
<li><code>TurtleStatus</code> (another name that could be improved) contains current turtle information, array of Diagrams that it created, and Stack of <code>Turtle</code> informations (for saving and loading positions)</li>
</ul>
<p>For <code>[</code> and <code>]</code> L-System rules I've created simple <code>Stack</code> implementation, so turtle information can be pushed and popped when needed:</p>
<pre><code class="language-hs">data Stack a = Stack [a] deriving Show

push :: a -> Stack a -> Stack a
push x (Stack xs) = Stack (x:xs)

pop :: Stack a -> (a, Stack a)
pop (Stack (x:xs)) = (x, Stack xs)
</code></pre>
<p>This way I could <em>execute</em> the turtle over all of the L-System rules, gather Diagrams that it created, and generate graphics in the last step.
To move the turtle forward I'm calculating an end point using current turtle position and angle (notice how <code>drawLineAndMoveForward</code> returns a <code>Diagram</code>):</p>
<pre><code class="language-hs">moveForward :: TurtleStatus -> TurtleStatus
moveForward ((Turtle (x, y) angle), ds, st) = ((Turtle (nx, ny) angle), ds, st)
  where nx = (x + (sin (angle / 360) * pi) * stepDistance)
        ny = (y + (cos (angle / 360) * pi) * stepDistance)

drawLineAndMoveForward :: TurtleStatus -> TurtleStatus
drawLineAndMoveForward (t, ds, st) = (nt, d:ds, nst)
  where (nt, _, nst) = moveForward (t, ds, st)
        d = fromVertices $ map p2 [(getPosition t), (getPosition nt)]
</code></pre>
<p>Next step is to get turtle function for given rule, and execute set of rules:</p>
<pre><code class="language-hs">getRuleFn :: Char -> (TurtleStatus -> TurtleStatus)
getRuleFn r = case r of
                   'F' -> drawLineAndMoveForward
                   'G' -> moveForward
                   '+' -> turnRight
                   '-' -> turnLeft
                   '[' -> saveLocation
                   ']' -> restoreLocation

executeTurtleRules :: [Char] -> TurtleStatus -> TurtleStatus
executeTurtleRules (r:rs) t = executeTurtleRules rs $ getRuleFn r t
executeTurtleRules [] t = t
</code></pre>
<p>To get the final diagram, we have to execute turtle rules, get the diagrams part of <code>TurtleStatus</code> and <code>fold</code> them into single diagram:</p>
<pre><code class="language-hs">getDiagrams :: TurtleStatus -> [Diagram B]
getDiagrams (_, ds, _) = ds

diagram :: Diagram B
diagram = foldr1 mappend $ getDiagrams $ executeTurtleRules rs t
  where rs = genGenerations numGenerations "F"
        t = ((Turtle (0,0) 0), [], Stack [])
</code></pre>
<p>By modifying L-System rules, as well as <code>stepDistance</code>, <code>turnAngle</code> and <code>numGenerations</code> constants we can get a variety of different structures.</p>
<img src="https://szymonkaliski.com/writing/2017-11-10-exploring-tidal-and-diagrams/l-system-1.svg" style="background-color:white;padding:40px" width="400" height="759">
<h2>Fin.</h2>
<p>I'm pretty happy with my progress in Haskell, especially with the last mini-project of building functioning L-System.</p>
<p>After two months, I can say that Haskell doesn't feel like a good <em>creative-coding</em> environment for me, strong types look like a great thing for refactoring and maintaining big applications, but when exploring, I felt that it was slowing me down a little.
Having to think about type of a <em>thing</em>, when in early stages of exploring the <em>thing</em> is not a very useful thing for me.</p>
<p>I stared less at a blank screen caused by runtime error, and more at compiler output.</p>
<p>Usually, once the compiler was happy, the application was running without issues, so it feels like trading runtime errors for compile-time errors, with the overhead of needing to have more things figured out upfront.</p>
<p>I can imagine using Haskell for building server-side code, or backend for installation, and I hope I'll get relaxed enough timeline on one of my client projects to try it out.</p>
<p>For now, all the code is published online: <a href="http://github.com/szymonkaliski/haskell-playground">szymonkaliski/haskell-playground</a>, and I'm moving forward to November's project.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-11-10-exploring-tidal-and-diagrams/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-11-10-exploring-tidal-and-diagrams/</guid>
            <pubDate>Fri, 10 Nov 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Learning Haskell]]></title>
            <description><![CDATA[<p>Haskell has been on my to-learn list for a long time, I was interested in a different approach to functional programming than LISP, and was ready to give strong typing a chance.
I was also tired of building things every month and decided to take my time and focus on input, rather than output.</p>
<p>I took 15-45 minutes every day to read through <a href="http://learnyouahaskell.com/">"Learn You a Haskell for Great Good"</a> (free to read online).
I was taking notes as I go, and pushed them to online repo: <a href="http://github.com/szymonkaliski/haskell-playground">szymonkaliski/haskell-playground</a></p>
<h2>First impressions</h2>
<p>Setup was extremely simple, I didn't need anything special besides <code>brew install ghc</code>.
<code>vim</code> already supports Haskell, so when compared to Reason (another language <a href="https://szymonkaliski.com/writing/2017-05-31-exploring-reasonml/">I tried out recently</a>), the setup was much easier.</p>
<p>I enjoyed working with <code>ghci</code> REPL similarly to how I like to work with <code>Clojure</code> — in split view with my editor, executing code piece by piece.</p>
<img src="https://szymonkaliski.com/writing/2017-10-02-learning-haskell/screen.png" alt="" width="1060" height="1060">
<p>"Learn You a Haskell" was a very nice introduction to the language, and as far as I understand it coveres all the basis.</p>
<h2>What I enjoyed about the language so far:</h2>
<ol>
<li>How terse it is — there's a lot of strange symbols <code>::</code>, <code>(\</code>, <code>>>=</code>, but syntax itself is quite simple, functions usually are very short, but that doesn't come in hand with them being simple to understand (at least from my newbie perspective)</li>
<li>Immutability — I try to write most of my code in a functional and immutable fashion, but having it be enforced by a language, and not a programmer, is a great feature</li>
<li>Types — I usually prefer non-typed languages, but Haskell's type system is really interesting, and type annotations are very helpful in trying to understand what functions do; I'm still fuzzy on some details, and plan on doing a bit more reading on type classes</li>
</ol>
<h2>What I didn't enjoy that much:</h2>
<ol>
<li>Nomenclature — "applicative", "functor", "monoid", "monad"..., some of the concepts behind the names seem easy, some seem hard, but trying to understand some explanation filled with those cryptic names can lead to a headache</li>
<li>There's only a few longer examples in the book, so I haven't actually written that much code yet, but I plan on spending next month exploring some popular libraries (Tidal and Haskell's OpenGL bindings if I get them to work)</li>
</ol>
<h2>Fin.</h2>
<p>I doubt if I'll ever get paid to write Haskell, but I'm sure this month wasn't wasted, I learned a few new concepts and looked at things from new perspective which is always a big win.</p>
<p>I'm curious to see how different libraries utilise Haskell type system and how working with bigger pieces of code looks like.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-10-02-learning-haskell/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-10-02-learning-haskell/</guid>
            <pubDate>Mon, 02 Oct 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building DAS-UI]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/writing/2017-09-08-building-das-ui/screen.png" alt="" width="1382" height="1048">
<p><a href="https://das-ui.firebaseapp.com/">DAS-UI</a> is another node-based experiment (after <a href="https://szymonkaliski.com/projects/sdf-ui/">SDF-UI</a>) that I've built during my one-project-a-month meta-project in 2017.</p>
<h2>Intro</h2>
<p>I've already built a few node-based UIs and I seem to quite like them (if you're curious about previous ones, you can read the intro to <a href="https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/">SDF-UI blogpost</a>).</p>
<p>I spend most of my days in CLI, there's something hard to beat about text based interfaces, and I feel I'm much faster with keyboard shortcuts than with pointing and clicking.</p>
<p>Combining both of those worlds has been on my mind for quite some time, but as August began, and as I decided to work on this problem, I had no idea how to start.</p>
<h2>Explorations</h2>
<img src="https://szymonkaliski.com/writing/2017-09-08-building-das-ui/sketch.jpg" alt="" width="1280" height="720">
<p>I've spent a lot of time sketching and thinking, I didn't touch the code for a few days, as I was trying to get at least big-picture view on how this could work.</p>
<p>In hindsight, I was trying to solve to many things at once, I was thinking about UI, UX, and implementation (types? multiple inputs/outputs? streams? user-coded ui? blocks as simple functions? etc...) at the same time.
I've finally decided that the biggest exploration here is going to be the UI/UX part, and focused on this for a while.</p>
<h2>UI</h2>
<p>Since I didn't want to use mouse at all, it became obvious that there needs to be some kind of keyboard-controlled cursor.
This cursor has to move by some predictable amounts, so I've added grid.
Since there's a grid, I decided to make all the blocks always fit that grid.
Blocks can still be dragged around and resized, but they always snap to predefined sizes.</p>
<img src="https://szymonkaliski.com/writing/2017-09-08-building-das-ui/grid.gif" width="830" height="544">
<p>The next important part was tackling the block creation.</p>
<p>I knew from the start that I would have little time to focus on actual blocks implementation, so I decided to allow users to create their own blocks.</p>
<p>So when creating a block, user can select either one from already existing block specs (more on that soon), or create a new spec, with custom functionality, that can later be re-used.</p>
<img src="https://szymonkaliski.com/writing/2017-09-08-building-das-ui/new-block.gif" width="830" height="544">
<p>After this was working, the last thing missing was making connections between blocks.
Here the biggest inspiration was how <a href="http://vimperator.org/">vimperator</a> (and similar plugins) handle opening links: you first hit <code>f</code> which adds little tooltips around all the links with few letters, and type those letters to open the link.
I used similar mechanism for connecting blocks: you first hover over the input or output, hit <code>c</code>, and then type matching letter to add that link.</p>
<h2>Implementation</h2>
<p><em>DAS-UI</em> is another project made with <a href="https://facebook.github.io/react/">React</a>, just because I know it well, and I know it's not going to block me when implementing new ideas.
Whole state of application lives in <a href="https://facebook.github.io/immutable-js/">Immutable.Map</a>:</p>
<pre><code class="language-javascript">const initialState = fromJS({
  blockSpecs: {},
  graph: {
    blocks: {},
    connections: {}
  },
  ui: { ... }
});
</code></pre>
<ul>
<li><code>blockSpecs</code> is a map, pointing from name, to block spec info (inputs and outputs name), and stringified block implementation</li>
<li><code>graph</code> handles actual blocks and connections on board, all of them accessible through <code>uuid</code></li>
<li><code>ui</code> containes all the other UI state, including cursor position, grid size, etc...</li>
</ul>
<p>There are two intersting parts of the system that I'm going to describe in more details: block specs, and graph engine.</p>
<h2>Block Specs</h2>
<p>Block specs, meaning the block blueprint of sorts, are simple JavaScript object:</p>
<pre><code class="language-javascript">{
  name: 'some/name',
  inputs: [ 'first-input', 'another-input' ],
  outputs: [ 'some-output-values' ]
  code: ({ inputs, outputs, state }) => {},
  ui: ({ state, setState }) => {}
}
</code></pre>
<ul>
<li><code>name</code> is an identifier of the block, meaning that each <code>some/name</code> on board will have the same implementation</li>
<li><code>inputs</code> and <code>outputs</code> are the arrays of names, they tell the UI to draw relevant items on the screen, and are also used to build the input and outputs objects</li>
<li><code>code</code> is the implementation of the block (more below)</li>
<li><code>ui</code> is an optional React component that will be rendered inside the block</li>
</ul>
<p><code>code</code> is the most interesting part here, this is where the block actually executes some logic.
The argument to that functions is an object containing <code>inputs</code>, <code>outputs</code> and <code>state</code> — collections of RxJS streams.
These colletions are constructed using <code>inputs</code> and <code>outputs</code> properties — each input and output gets its own stream.
In the example above, it would mean that <code>inputs</code> is actually an object:</p>
<pre><code class="language-js">const inputs = {
  "first-input": new rx.Subject(),
  "another-input": new rx.Subject(),
};
</code></pre>
<p>Same thing happens with outputs.
State is a stream that connects <code>ui</code> with <code>code</code>.
<code>ui</code> can, through <code>setState()</code> call, update the state, which then <code>code</code> is notified about (through <code>state.subscribe</code>).
If <code>state</code> was changed from <code>code</code> (with <code>state.onNext</code>), the <code>ui</code> gets re-rendered with updated <code>state</code> values.</p>
<p>This allowed me to keep the whole graph asynchronous, and have most of the piping work being taken care of by RxJS.
Block's code can then easily <code>.subscibe()</code> to changes on one of the streams, and push new values out using <code>.onNext()</code>.
This might be abuse of how <code>rx.Subject()</code>'s are supposed to work, I'm not an expert here, but it seems to work quite well.</p>
<p>Block specs themeselves are kept inside redux store.
This wouldn't be needed if they were constnat, but I wanted users to be able to modify the specs on the go, and easily create new ones.
To acheive that, the specs are kept in redux as strings.
I've experimented with keeping functions inside the store, and stringifying/parsing them when storing to DB, but that proved to be not reliable and complex in implementation.</p>
<p>Block specs are executed using <code>new Function</code> constructor:</p>
<pre><code class="language-js">export const executeBlockSpec = (blockSpec) =>
  new Function(`return ${blockSpec.trim()}`)();
</code></pre>
<p>This simple function turns the block spec object into something resembling self-invoking anonymous function:</p>
<pre><code class="language-js">(function () {
  return {
    name: "some/name",
    //...
  };
})();
</code></pre>
<p>I can then capture the result, and use the block implementation.</p>
<h2>Graph Engine</h2>
<p>Graph engine is what actualy runs the calculations.
I keep graph as part of redux state: <code>connections</code> and <code>blocks</code> contain everything that exists on the board.</p>
<p><code>graph.blocks</code> contain block's <code>id</code>, it's position, size, and name of the block spec that it uses.
<code>graph.connections</code> contain only reference <code>id</code>s for connected blocks, and names of the input and output.</p>
<p>Graph engine is subscribed to store changes, and listens to changes in the <code>graph</code> subtree.
Since the whole state is immutable, I can easily compare if anything has changed (<code>if (!currentGraphState.equals(prevGraphState)) { ... }</code>).</p>
<p>The next important part of the puzzle is <a href="https://github.com/tgriesser/immutable-diff"><code>immutable-diff</code></a> package, which generates differences between two immutable structures.
I first create the diff, and then walk through each of the changes deciding how to change running graph.
The running graph also stores <code>blocks</code> and <code>connections</code>, the difference being that <code>blocks</code> point to actual running implementation (inlcluding reference for input and output streams for piping), and <code>connections</code> point to actual running conneciton, so it can be easily removed (<code>this.connections[id].dispose()</code>).
Changes are not applied until the whole diff was walked through, this helped with a few bugs, where blocks would execute <code>code</code> with part-old, part-new state.
I collect operations and arguments in <code>futureOps</code> array (for example <code>futureOps.push([this.removeBlock, { id: blockId }])</code>), and then, once I'm done with whole graph, I execute them one-by-one: <code>futureOps.forEach(([op, arg]) => op(arg))</code>.</p>
<p>One interesting thing to implement was a change in existing block spec — I wanted all other blocks using the same spec to be updated.
To do that I look for all block <code>id</code>s and connection <code>id</code>s that have anything to do with that block spec, and then I remove them, and re-add them to the graph: <a href="https://github.com/szymonkaliski/DAS-UI/blob/f2583d8dc7f4337b348917ae75c2bcbe7536ee75/src/services/graph.js#L121-L160">services/graph.js</a></p><div></div><p></p>
<p>Block's state is also a part of the redux state, this allows me to know when to re-render the block's UI, and I can <code>.subscribe()</code> to changes in graph engine, and pipe them through <code>state</code> stream to block's <code>code</code> implementation.</p>
<h2>Fin.</h2>
<p>This project, as all previous ones during my one-project-a-month thing, is far from complete.</p>
<p>I think of it as a proof-of-concept that keyboard-based node ui can be usable.</p>
<p>My next idea here would be to move it from web, to Electron, and use filesystem as a source of block's implementations (together with <code>require</code> support, etc..).
This would allow me to write low-level block implementation in vim, and then do the high-level piping using something visual.
I'd also love to tackle the problem of composing things into sub-patches, and reusing parts of graphs.</p>
<p>If you'd like to hack on <code>DAS-UI</code> it's open sourced and available on my Github: <a href="https://github.com/szymonkaliski/DAS-UI">szymmonkaliski/DAS-UI</a>.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-09-08-building-das-ui/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-09-08-building-das-ui/</guid>
            <pubDate>Fri, 08 Sep 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[DAS-UI]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/das-ui/screenshot.png" alt="Screenshot" width="1270" height="856">
<p><a href="https://das-ui.firebaseapp.com/">DAS-UI</a> is an experimental domain-agnostic keyboard-based visual programming language with JavaScript backend.</p>
<p>It is entirely controlled with keyboard shortcuts, most of which were inspired by vim.</p>
<p>Cursor can be moved with <code>hjkl</code>, new blocks are created with <code>n</code>, connections are made with <code>c</code>.
Blocks conform to grid, and can be moved with <code>shift</code> + <code>hjkl</code>, and resized with <code>&#x3C;</code>/<code>></code> and <code>+</code>/<code>-</code>.</p>
<p>You can read more about process behind making this project on the blog: <a href="https://szymonkaliski.com/writing/2017-09-08-building-das-ui/">building DAS-UI</a>.</p>
<p>Code is open sourced: <a href="https://github.com/szymonkaliski/DAS-UI">szymonkaliski/DAS-UI</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/das-ui/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/das-ui/</guid>
            <pubDate>Fri, 08 Sep 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Teaching Creative Coding in Taipei]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/class.jpg" alt="" width="1280" height="720">
<p>I spent July 2017 teaching three weeks of different creative technology workshops during summer program at <a href="http://skyrockprojects.com">Skyrock Projects</a> in Taipei.</p>
<p>The program was divided into week long workshops: <em>body interactions</em>, <em>no screens allowed</em> and <em>city data</em>.
Each week was 2-3 days of <em>heads down</em> — learning technology and programming, and then 1-2 days of student projects.
Each of the groups had one week of P5 and Arduino introduction, so they had some basic knowledge of programming.</p>
<h2>Body Interactions</h2>
<p>The main idea during the first week was to explore interactions that could work with human bodies.
We started with exploring some Arduino sensors: accelerometer, pressure sensor, photoresistor and ultrasonic sensor.</p>
<p>Second day was a re-introduction to P5 (running inside of <a href="https://github.com/szymonkaliski/Neutron">Neutron</a>), and connecting it with Arduino through serial interface.
Third day was all about sound (with <a href="https://tonejs.github.io/">Tone.js</a>), and coming up with interactions around music and sensors.</p>
<p>I was really surprised by the progress that the students made in just few days, and different final projects that they've came up with.</p>
<ol>
<li>A game where you have to jump over obstacles by physically jumping (using accelerometer) — with an idea to expand this further with pulse sensor to measure the heart rate and promote exercise</li>
<li>Stress pong — made using four pressure sensors and LED matrix — that gets harder the harder you press the buttons</li>
<li>Memory game with a custom controller, made using a lot of wires and complex logic to help develop your memory</li>
</ol>
<img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/projects-01.png" width="1294" height="1294">
<p>Code: <a href="https://github.com/skyrockprojects/Body-Interactions">skyrockprojects/Body-Interactions</a></p>
<h2>No Screens Allowed</h2>
<p>Second week was all about <a href="https://www.bareconductive.com/">BareConductive</a> and using conductive paint and capacitive sensors for building interfaces.</p>
<p>We started with exploring <a href="https://www.bareconductive.com/make/introducing-the-touch-board/">Touch Board</a> and playing with some examples.</p>
<p>After that we focused on connecting this to P5 using serial data (and <a href="https://github.com/szymonkaliski/Neutron">Neutron</a>), to finally connect it to <a href="https://tonejs.github.io/">Tone.js</a>.</p>
<img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/projects-02.png" width="1294" height="1294">
<p>Final projects included:</p>
<ol>
<li>An interactive map of Skyrock Projects headquarters</li>
<li>Music-making T-shirt</li>
<li>Touch-based vending machine</li>
</ol>
<video controls>
<source src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/music-t-shirt.mp4" type="video/mp4">
</video>
<p>Code: <a href="https://github.com/skyrockprojects/No-Screens-Allowed">skyrockprojects/No-Screens-Allowed</a></p>
<h2>City Data</h2>
<p>Last week was a bit shorter, we only got two days of "heads down".
During the first day we explored different environmental sensors for Arduino: temperature, humidity, microphone and photoresistors.</p>
<p>At the end of the day we set up data collecting machine that would record the values overnight:</p>
<img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/data-collecting.png" width="1294" height="1294">
<p>Next day was spent <a href="https://github.com/skyrockprojects/City-Data/blob/master/Neutron%20Data%20Visualisation/data-visualisation.js">reading back the data</a>, and exploring how we can use it to create images.</p>
<p>Code: <a href="https://github.com/skyrockprojects/City-Data">skyrockprojects/City-Data</a></p>
<h2>Fin.</h2>
<p>I've really enjoyed my month in Taipei, it's a great feeling to see the students progress and explore new ideas.</p>
<p>Workshop structure is especially important here, students can ask questions and experiment when there's no <em>wrong answers</em>.</p>
<p>I also got a chance to test <a href="https://github.com/szymonkaliski/Neutron">Neutron</a> in the wild — I've added syntax based error checking and better support for Windows, which wouldn't have happened if I didn't seen the problems students had while using it.</p>
<p>It's also nice to take a break from client projects for a while, and take some photos:</p>
<div class="mv1"><img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/trip-01.jpg" width="1280" height="720"></div>
<div class="mv1"><img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/trip-02.jpg" width="1280" height="1280"></div>
<div class="mv1"><img src="https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/trip-03.jpg" width="1280" height="720"></div>]]></description>
            <link>https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-08-20-skyrock-projects/</guid>
            <pubDate>Sun, 20 Aug 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building Neutron]]></title>
            <description><![CDATA[<video loop autoplay muted>
<source src="https://szymonkaliski.com/writing/2017-07-07-building-neutron/neutron.mp4" type="video/mp4">
</video>
<p><a href="https://github.com/szymonkaliski/Neutron">Neutron</a> is a self-contained node &#x26; npm application made for quick prototyping and teaching.</p>
<p>It borrows ideas from <a href="http://processing.org/">Processing</a> and tries to create similar novice and artist friendly environment.</p>
<h2>Intro</h2>
<p>Neutron was born out of two main needs:</p>
<ol>
<li>
<p><em>sketching</em> — I love npm ecosystem, almost every piece of code I would want to reuse is there, usually with a few different approaches. This, unfortunately, is not so nice for quick throwaway sketches. I have to set up a project, set up a build pipeline (<a href="https://github.com/mattdesl/budo">budo</a> helps here though), open browser, and remember to install dependencies by hand. I wanted to be able to do it quicker, with less steps.</p>
</li>
<li>
<p><em>teaching</em> — which I really enjoy, I believe that sharing knowledge is important, and that programming is easiest to understand through creative outlets: making graphics and sounds. I always go with Processing since it works everywhere, you just download binary, and run it. At some point, someone always asks about porting the thing they made to web, and even though Java applet is a possibility, usually JavaScript is a better approach — another language they will have to learn, and a new set of libraries to explore; this can be discouraging for newcomers. I wanted Processing environment, but with JavaScript instead of Java.</p>
</li>
</ol>
<h2>Tech</h2>
<p>Neutron is based on Electron — basically a programmable Chrome window with <code>require()</code> support.
This gives us best of both worlds: file system access with <code>require('fs')</code>, full node support, and a window which can render HTML.
Neutron wraps this functionality in easy to use application.</p>
<p>On start, Neutron asks to load a JavaScript file, this can be done either by dragging it on the window, or clicking to open file select.
This simple UI is build with React, probably overkill in this situation, but this allowed me to quickly move forward.</p>
<p>The most interesting part of this software is an automatic package installation.
This consists of two things:</p>
<ol>
<li>finding out which packages are required</li>
<li>installing packages with npm</li>
</ol>
<p>For 1. I used <a href="https://github.com/allain/recursive-deps"><code>recursive-deps</code></a> package, after having tested few other solutions.
This one was the most straightforward and reliable, and as the name suggests, finds dependencies recursively, which is helpful for sketches spread across multiple files.</p>
<p>Installing packages was trickier, since I knew from the beginning that npm should be a part of the application, and I couldn't just shell out to a globally installed executable.</p>
<p>npm itself doesn't have documented public API right now (it used to have for a while though), so this required some trial and error.
Here's the most important gist (install npm as your project dependency first!):</p>
<pre><code class="language-js">const npm = require("npm");

const packagesToInstall = ["p5", "lodash"];

npm.load(
  {
    color: false,
    progress: true,
    save: true,
    unicode: false,
  },
  (err) => {
    if (err) {
      return console.error(err);
    }

    npm.commands.install(packagesToInstall, (err) => {
      if (err) {
        return console.error(err);
      }

      console.log("installation done");
    });
  }
);
</code></pre>
<p>There are some caveats though, from what I've found:</p>
<ul>
<li><code>save: true</code> to save packages in <code>package.json</code> doesn't work, I solve this by creating <code>package.json</code> containing only <code>{}</code> before installing any packages</li>
<li>there are issues with getting the log info and streaming to the client, I have hacked a semi-solution providing custom node stream that I then send to main process, this works with some issues on OSX, but I couldn't get it to work on Windows</li>
<li>to avoid re-installing already installed packages on every save, I first use <code>npm.commands.ls</code> to check what's already installed</li>
<li>I also had to filter out built-in packages from <code>recursive-deps</code>, so for example <code>require('fs')</code> doesn't try to install <code>fs</code> from npm</li>
</ul>
<p>The full relevant code <a href="https://github.com/szymonkaliski/Neutron/blob/380363f850de2423d091fdfc78f21e5312e9b5ce/index.js#L20-L90">is here</a>.</p>
<h2>Native packages</h2>
<p>The biggest problem of this approach is using native packages.
If this was based on node, then most packages published to npm are already compiled, and it would be much less problematic.
Since Electron uses different V8 version, almost all of native packages have to be compiled after installation.
Usually, if node and npm are set up correctly, this is not that big of a deal, at least on OSX (Windows is still a bit more problematic).</p>
<p>The aim of this tool is to allow users to use JavaScript quickly, without any complex setup.
I've experimented a lot with bundling some build tools with the app, but sadly, I failed.
It seems to be possible on OSX, but I lack Windows-specific knowledge to make this a reality, and I suspect that compilation would still require Visual Studio to be installed.</p>
<p>I've ended up bundling three native packages which I use most often when teaching workshops:</p>
<ul>
<li><a href="https://github.com/EmergingTechnologyAdvisors/node-serialport"><code>node-serialport</code></a> for communicating through serial port</li>
<li><a href="http://johnny-five.io/"><code>johnny-five</code></a> for firmata</li>
<li><a href="https://github.com/justinlatimer/node-midi"><code>node-midi</code></a> for MIDI</li>
</ul>
<h2>CI Builds</h2>
<p>For building an executable version of the app, I started with local Windows builds on my OSX machine, using Wine.
This doesn't work when trying to build native modules — if you need them, you have to compile on yor target platform.</p>
<p>Luckily, this is easily sorted with CI build artifacts!
I use AppVeyor for Windows builds, and Travis for OSX ones.
As long as the project is opensource, they are free, which is great.</p>
<p>They also work great with <a href="https://github.com/electron-userland/electron-builder"><code>electron-builder</code></a> that I use for building the app.
To get this to work, I had to add two config files:</p>
<ul>
<li><a href="https://github.com/szymonkaliski/Neutron/blob/master/appveyor.yml"><code>appveyor.yml</code></a> for AppVeyor</li>
<li><a href="https://github.com/szymonkaliski/Neutron/blob/master/.travis.yml"><code>.travis.yml</code></a> for Travis</li>
</ul>
<p>To have them publish automatically to GitHub, <code>GH_TOKEN</code> has to be set.
It can be generated here: <a href="https://github.com/settings/tokens">https://github.com/settings/tokens</a>, with access right for <code>public_repo</code>.
For Travis, it can be added as an environment variable in project settings, and for AppVeyor, it can be included straight into <code>appveyor.yml</code> if it's encrypted: <a href="https://ci.appveyor.com/tools/encrypt">https://ci.appveyor.com/tools/encrypt</a>.</p>
<h2>Built-in API</h2>
<p>To make Neutron work a bit more like Processing, I've decided to expose a simple wrapper around Electron functions, this allows me not only to get the window size, but move it around the screen, get displays, access mouse position outside of a window, and more.</p>
<p><a href="https://github.com/szymonkaliski/Neutron#api">Detailed API info is up on Github.</a></p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/writing/2017-07-07-building-neutron/window-loop.mp4" type="video/mp4">
</video>
<h2>Fin.</h2>
<p>Building Neutron was painful at times, especially the week I've spent trying to figure out native modules. I believe this tool will be useful for others, for both sketching and teaching.</p>
<p>I'm already using it often enough that I believe it was a good investment of my time.
Lately, any idea I have, or anything I want to try, starts with running this bash function:</p>
<pre><code class="language-bash">mksketch() {
  cd $(mktemp -d)    # make random temp directory
  touch index.js     # create empty JS file
  neutron index.js &#x26; # I'm using neutron through CLI
  vim index.js       # start playing!
}
</code></pre>]]></description>
            <link>https://szymonkaliski.com/writing/2017-07-07-building-neutron/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-07-07-building-neutron/</guid>
            <pubDate>Fri, 07 Jul 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Neutron]]></title>
            <description><![CDATA[<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/neutron/neutron.mp4" type="video/mp4">
</video>
<p><a href="https://github.com/szymonkaliski/Neutron">Neutron</a> is self-contained node &#x26; npm application made for quick prototyping and teaching.</p>
<p>It borrows ideas from <a href="http://processing.org/">Processing</a> and tries to create similar novice and artist friendly environment.</p>
<p>Neutron is based on <a href="https://electron.atom.io/">Electron</a>, so you get everything that Chrome and Node can give you! (Native packages are sadly not supported right now, Neutron ships with ones I use for workshops often: <code>node-serialport</code>, <code>johnny-five</code> and <code>node-midi</code>.)</p>
<p>Detailed info is on <a href="https://github.com/szymonkaliski/Neutron">github</a>, you can also <a href="https://github.com/szymonkaliski/Neutron/releases">download</a> it straight from there.</p>
<p>I've also made a longer write-up about ideas and process behind building this: <a href="https://szymonkaliski.com/writing/2017-07-07-building-neutron/">building neutron</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/neutron/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/neutron/</guid>
            <pubDate>Fri, 07 Jul 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Exploring ReasonML]]></title>
            <description><![CDATA[<p><a href="https://facebook.github.io/reason/">ReasonML</a> is new syntax and toolchain for working with Ocaml, supported by Facebook.
It promises type-safe performant code with near-zero overhead.</p>
<h2>Intro</h2>
<p>After four months spent working on different <em>tools</em> I wanted a break, and explore a bit more.</p>
<p>ReasonML was on my to-learn list for quite a while, and while a month is not a lot to really learn something, I feel like I at least scratched the surface, and have better understanding and <em>"feel"</em> of this language.</p>
<p>I prefer to learn through doing, and I wanted to explore some generative design ideas I was thinking about.
I've spent much more time playing with ReasonML than working on aesthetics, so I hope the presented code might be used as a starting point for doing something more interesting.</p>
<h2>Project Setup</h2>
<p>I followed <a href="https://facebook.github.io/reason/jsWorkflow.html#javascript-workflow-editor-setup-global-utilities">original setup guide</a> for getting my toolchain up and running.</p>
<p>Setting up nactual project is very easy, only <code>bs-platform</code> from npm is needed as dependency, and can be started then using local npm binaries: <code>./node_modules/.bin/bsb</code>.
I've set up simple npm script for building and watching for changes, using <code>package.json</code> <code>scripts</code> section:</p>
<pre><code class="language-json">{
  ...
  "scripts": {
    "build": "bsb",
    "watch": "bsb -w"
  }
}
</code></pre>
<p>Another thing that's needed is <code>bsconfig.json</code> in root directory of the project:</p>
<pre><code class="language-json">{
  "name": "project-name",
  "sources": "src"
}
</code></pre>
<p><code>./src/</code> folder is source folder where ReasonML code wil be kept, and running <code>npm run build</code> compiles it to <code>./lib/js/</code> folder.</p>
<p>This gives us a nice JavaScript code in <code>./lib/js</code>, but we still need to be able to run it.
For small projects I like using <a href="https://github.com/mattdesl/budo"><code>budo</code></a> which also runs <code>browserify</code> so the output code from ReasonML can use npm modules as well!</p>
<p>My final <code>package.json</code> looked like this:</p>
<pre><code class="language-json">{
  "scripts": {
    "build": "bsb",
    "watch": "bsb -w",
    "serve": "budo ./lib/js/src/app.js --port 3000 --live",
    "start": "concurrently --raw 'npm run watch' 'npm run serve'"
  },
  "devDependencies": {
    "bs-platform": "^1.7.3",
    "budo": "^10.0.3",
    "concurrently": "^3.4.0"
  }
}
</code></pre>
<p>This allows me to start serving (and live-reloading) compiled JavaScript using <code>npm run serve</code>, and start both ReasonML compilation and <code>budo</code> with <code>npm start</code>.
<a href="https://bloomberg.github.io/bucklescript/">Bucklescript's</a> compilation (the thing that compiles ReasonML to JavaScript) is extremely fast, and together with <code>budo</code>'s live-reload gives near-instantaneous feedback that feels amazing.</p>
<p>It's much faster than typescript or flow compilation, and actually one of the fastest compilers I've ever used.</p>
<h2>First project: flow-field</h2>
<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://szymonkaliski.github.io/reasonml-flow-field-exp">
  </iframe>
</div>
<p>I've started exploring ReasonML through binding to <code>canvas</code> and some other <code>DOM</code> elements.
Unfortunately, the official docs are lacking here, I tried to make sense of <a href="https://bloomberg.github.io/bucklescript/Manual.html">Bucklescript docs</a> but they are written for Ocaml, not Reason, so that was tricky at first.
What helped a lot was browsing through existing ReasonML projects:</p>
<ul>
<li><a href="https://github.com/BuckleTypes/bs-express/blob/master/src/express.re">bs-express bindings for express</a></li>
<li><a href="https://github.com/reasonml/reason-react/blob/master/src/reactRe.re">reactRe bindings for React</a></li>
</ul>
<p>I ended up writing just the bindings I've needed, first for <code>Document</code>:</p>
<pre><code>let module Document = {
  type element;

  let window: element = [%bs.raw "window"];

  external createElement : string => element = "document.createElement" [@@bs.val];
  external appendChild : element => element = "document.body.appendChild" [@@bs.val];

  external addEventListener :
    element =>
    string =>
    (unit => unit) =>
    unit = "addEventListener" [@@bs.send];

  external getWidth : element => int = "innerWidth" [@@bs.get];
  external getHeight : element => int = "innerHeight" [@@bs.get];

  external setWidth : element => int => unit = "width" [@@bs.set];
  external setHeight : element => int => unit = "height" [@@bs.set];

  external requestAnimationFrame : (unit => unit) => unit = "requestAnimationFrame" [@@bs.val];
};
</code></pre>
<p>Few notes:</p>
<ul>
<li><code>unit</code> is "nothing", and <code>(unit => unit)</code> means function from nothing to nothing, this is used for callback functions</li>
<li><code>[@@bs...]</code> are Bucklescript annotations for <a href="https://bloomberg.github.io/bucklescript/Manual.html#_ffi">FFI</a></li>
</ul>
<p>This allowed me to create canvas and set its size:</p>
<pre><code>let canvas = Document.createElement "canvas";

Document.appendChild canvas;

let setCanvasSize () => {
  let width = (Document.getWidth Document.window);
  let height = (Document.getHeight Document.window);

  Document.setWidth canvas width;
  Document.setHeight canvas height;
};

Document.addEventListener Document.window "resize" setCanvasSize;
Document.addEventListener Document.window "DOMContentLoaded" setCanvasSize;
</code></pre>
<p>I've made similar simple bindings for canvas: <a href="https://github.com/szymonkaliski/reasonml-flow-field-exp/blob/master/src/Canvas.re"><code>src/Canvas.re</code></a>.
Since every file is a module in Reason, we can drop <code>let module Canvas =</code> if saving code in separate file.</p>
<p>Flow-field app logic was quite simple to write, the basic algorithm is:</p>
<ol>
<li><a href="https://github.com/szymonkaliski/reasonml-flow-field-exp/blob/master/src/app.re#L87-L98">create bunch of points</a> (notice nice <code>Random.float</code> functions from Reason core)</li>
<li><a href="https://github.com/szymonkaliski/reasonml-flow-field-exp/blob/master/src/app.re#L134-L142">update point's velocity based on flow field direction in its current x/y position</a></li>
</ol>
<p>For flow-field direction, I use Simplex noise algorithm which generates one value based on two inputs, similarly to Perlin noise.
I calculate vector from this value, treating it as angle:</p>
<pre><code>let angleToVec angle : vecT => {
  x: (sin (angle *. 2. *. Math.pi)),
  y: (cos (angle *. 2. *. Math.pi))
};
</code></pre>
<p>Notice the <code>vecT</code> annotation, this allows compiler to be sure that returned value is <code>{ x: float, y: float }</code>.</p>
<p>I've spent most time building this example exploring ReasonML syntax, and fighting the compiler.</p>
<p>Coming from working mostly in non-typed languages (I've been using <code>JavaScript</code> and <code>Clojure</code> lately), it felt like doing more work for little to no profit.</p>
<p>This was noticeably slowing me down, to the point that I probably won't ever use ReasonML for experimental/exploratory projects.
At the same time, I'm sure that type safety would be great for any bigger UI application.</p>
<h2>Second project: metaballs with regl</h2>
<p>I've added a simple collision detection to the first project and got laplacian growth out of it:</p>
<div>
  <video loop autoplay muted><source src="https://szymonkaliski.com/writing/2017-05-31-exploring-reasonml/laplacian-growth.mp4" type="video/mp4"></video>
</div>
<p>Basic algorithm is:</p>
<ol>
<li>start with a fixed particle, and a lot of "floating" particles</li>
<li>if floating particle hits the fixed particle, it becomes fixed as well</li>
<li>repeat until you run out of particles</li>
</ol>
<p>I got curious how this would look if the particles were <a href="https://en.wikipedia.org/wiki/Metaballs">metaballs</a> — I was looking for more organic "blobby" visuals.</p>
<p>To create metaballs in 2d, we have to calculate distance to all the particles for each pixel, this would perform very badly in CPU-land, so I've decided to switch to webgl.
<a href="https://github.com/regl-project/regl">Regl</a> was another cool project on my to-learn list, so I decided to combine the two — learn about regl API while binding it to ReasonML, and then use it for metaballs.</p>
<p>I've spent a lot of time on writing a nice, usable wrapper.
Regl is great to use in JavaScript, but I had a lot of problems with forcing Bucklescript and ReasonML types to cooperate.
Final wrapper is very <em>hacky</em>, and I'm both ashamed and proud of it, some interesting parts:</p>
<pre><code>let create : Document.element => unit = [%bs.raw {|
  function(canvas) {
    // first hacky thing, expose regl as top-level window things
    window.regl = require('regl')(canvas);
  }
|}];
</code></pre>
<p>This exposes regl as top-level <code>window</code> thing, so I can then use my wrapper as a singleton.
Not sure if that's good or bad idea, but has worked for me.</p>
<pre><code>external makeDrawConfig :
  frag::string? =>
  vert::string? =>
  uniforms::Js.t{..}? =>
  attributes::Js.t{..}? =>
  count::int? =>
  drawConfigT = "" [@@bs.obj];

let makeDrawCommand : drawConfigT => drawComandT = [%bs.raw {|
  function(opts) {
    var command = window.regl(opts);

    /* expose ".draw" so we can use draw external */
    command.draw = command;

    return command;
  }
|}];

external draw : command::drawComandT => uniforms::Js.t 'a? => unit = "" [@@bs.send];
</code></pre>
<p>This allowed me to create JavaScript object using ReasonML syntax:</p>
<pre><code>let drawTriangleConfig = Regl.makeDrawConfig
  frag::triangleFrag
  vert::triangleVert
  count:4
  ...
</code></pre>
<p>Then use this configuration object to create hacked draw command:</p>
<pre><code>let drawTriangleCommand = Regl.makeDrawCommand drawTriangleConfig;
</code></pre>
<p>Which finally can be used in <code>Regl.frame</code> to draw:</p>
<pre><code>let draw t => {
  Regl.clear
    color::[| 0, 0, 0, 1 |]
    depth::1;

  let triangleUniforms = [%bs.obj {
    width: state.window.width,
    height: state.window.height,
  }];

  Regl.draw
    command::drawTriangleComand
    uniforms::triangleUniforms;
};

Regl.frame draw;
</code></pre>
<p>Full wrapper is here: <a href="https://github.com/szymonkaliski/reasonml-metaballs-regl-exp/blob/master/src/Regl.re"><code>src/Regl.re</code></a>, and final results below:</p>
<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://szymonkaliski.github.io/reasonml-metaballs-regl-exp">
  </iframe>
</div>
<h2>Fin.</h2>
<p>I enjoyed this month's exploration and learning a new language as nice break from tool-making research.</p>
<p>ReasonML is an interesting project, I love how fast the compiler is, how readable the output code is, and how types could help while working with data structures and complex applications.</p>
<p>It still feels like early days though, with not the greatest documentation, and only few example projects/libraries using it.
Right now, I would consider using it for UI frontend work, and I'll keep my eye on its future developments.</p>
<p>If someone is interested in making the regl wrapper better — <a href="mailto:hi@szymonkaliski.com">feel free to contact me</a>.
I'd love to help, but I probably won't be pursuing this myself any time soon.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-05-31-exploring-reasonml/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-05-31-exploring-reasonml/</guid>
            <pubDate>Wed, 31 May 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Timav]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/timav/screenshot-1.png" alt="Application screenshot" width="1382" height="902">
<p><a href="http://github.com/szymonkaliski/Timav">Timav</a> is a tool for analysing time tracking data collected in Google Calendar.</p>
<p>It evolved organically to fit the work I do, and how I do it, and should probably be used as reference to building your own system.</p>
<img src="https://szymonkaliski.com/projects/timav/screenshot-2.png" alt="Application screenshot" width="1257" height="837">
<p>You can find more details in this blog post: <a href="https://szymonkaliski.com/writing/2017-04-30-time-tracking/">time tracking</a>.</p>
<p>Code is open sourced: <a href="https://github.com/szymonkaliski/Timav">szymonkaliski/Timav</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/timav/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/timav/</guid>
            <pubDate>Sun, 30 Apr 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Timav]]></title>
            <description><![CDATA[<p><a href="http://github.com/szymonkaliski/Timav">Timav</a> (<em>"chronology"</em> in <em>Volapük</em>) is a tool for analysing time tracking data collected in Google Calendar.</p>
<p>It evolved organically to fit the work I do, and how I do it, and should probably be used as a reference to build your own system.</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/timav-1.png" alt="" width="1382" height="902">
<h2>Intro</h2>
<p>I've built my first time-tracking system when I finished college and jumped into freelance work.
I had two main reasons to build it:</p>
<ol>
<li>
<p>I wasn't sure how much things should cost, and I hoped that over time, by analysing which projects I felt satisfied with, and knowing how much time I've spent on them, I would know how much a day of work is worth.
After over four years of doing this, I know that this is not as simple as it seems, but it was a start.</p>
</li>
<li>
<p>I wasn't sure how much time things can take, and I knew that potential clients would be asking about timelines.
I figured that the more projects I make, and the more data I have, the better I can approximate things better.
Again, I know it's not that easy, but it was something to start with.</p>
</li>
</ol>
<p>I was also curious how much time I would spend working daily, and how it changes over time.</p>
<p>Since then I've been rebuilding this system yearly, as I've realised how much impact on me it has — <em>"We shape our tools and then our tools shape us."</em>.
My ideas about what I want to track keep changing as well.</p>
<p>Timav is actually a fourth version in this process, and I'm pretty sure it's not the last one.</p>
<p>I'll start with some history of previous versions, and then get into more details on how I approach time tracking now.</p>
<h2>First attempt</h2>
<p>Because my first time tracking system has been built before I've started tracking time, I have no idea how long it took to build it.
The idea was pretty simple though, I wanted to store all the logs in a database, and be able to query and analyse them.
The log consisted of starting and ending times, project's name that it belonged to and <em>type</em> — either <em>personal</em> or <em>work,</em> later another type, <em>research</em> was added, but I didn't use it much.
I also tracked payments with date, amount and project name.
Everything was held together by project name, so my tracking was only concerned about how I work on very specific things.</p>
<p>During the day, I would jot down when I started and finished some task.
I've tried to be as honest with myself as possible, so whenever I've started browsing Hacker News or Reddit, I would have noted down that time as end of log.
Usually after a day of work I've had something like this:</p>
<pre><code>Project work 10:15-10:45
Project work 11:00-11:30
Project work 12:00-13:15
...
</code></pre>
<p>I would then go to the browser, and input one-by-one all this data:</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/vanilla-1-1.png" alt="" width="1382" height="1222">
<p>I've had similar UI for inputing payments, and boring but informative table with info about all my projects:</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/vanilla-1-2.png" alt="" width="1382" height="1222">
<p>I've also tried to get simple stats out of the data, but haven't used it much:</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/vanilla-1-3.png" alt="" width="1382" height="1222">
<p>This doesn't look terribly exciting, but had worked well for me for over two years.
There was one big problem in how this system was built, mainly this table of projects.
At some point I changed it to be sorted by how much I made per hour, so all my personal projects, which earn me nothing, would be at the bottom of the list.</p>
<p>After two years of using it, I stopped working on any of my own things, and for a while couldn't figure out why.
I got a bit depressed, and I couldn't force myself to do anything other than work.
It turns out that working on personal projects is very important for me, and seems to be connected to the quality of my life.</p>
<p>The <em>"eureka"</em> moment came after watching <a href="http://wiki.xxiivv.com/">Devine Lu Linvega's</a> talk <a href="https://vimeo.com/129368249"><em>Frameworks for Mystics</em></a>, and hearing how he uses his time tracking to split time between working with audio, visuals and programming.
It was one of strangest mixes of emotions I had, understanding that the tool I made for myself, that should help me, ended up impacting my life in such a big and unpredicted way.</p>
<p>My solution to this problem was simple — to build a new tool, one that would show me things from different perspective.</p>
<h2>Second attempt</h2>
<p>Unfortunately, timeline on this is very messy, second version of this tool was developed somewhere during second year of using the first version.
I planned on re-writing it in React (old version was in Backbone), playing with how data is displayed and adding more charts.
I was also thinking of some kind of external API so I could add logs from command line.
I only spent around 20 hours on this, and it died together with few other projects during that <em>no-personal-projects</em> time.</p>
<h2>Third attempt</h2>
<p>So, back to the main story.</p>
<p>Third attempt started just after understanding what the old version was doing to me.
Distinction between personal projects and work was an important thing to tackle, I also wanted to have more open-ended system, allowing me to track more things, and adapt to what I'm doing at the moment.</p>
<p>The friction of noting down and inputing events into web-based UI was also getting in my way, so I decided to use calendar for logging — idea stolen from <a href="http://marcinignac.com">Marcin Ignac</a>.</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/calendar-tracking.png" alt="" width="1382" height="1062">
<p>The system for describing logs looks like this:</p>
<pre><code>[Project] @tag1 @tag2(subtag)
</code></pre>
<ul>
<li><code>Project</code> is optional, and allows me to group logs for given project, it's usually a client project I work on, or well-defined personal project</li>
<li><code>@tag</code> is additional metadata that I can use to analyse the logs, I can add how many tags I want to a given event, but it's usually just a few; at the moment most often used ones are: <code>@work</code>, <code>@personal</code>, <code>@language()</code> (I track what programming languages I use)</li>
<li><code>@tag(subtag)</code> is a shorthand for having more data about a given tag, but allows me to still nest them under one bigger thing, this might be overly complex, but works for me — I use <code>@language(js)</code> when I'm writing JavaScript, <code>@language(clj)</code> for Clojure, <code>@health(gym)</code> for when I'm training and <code>@health(walk)</code> when strolling</li>
</ul>
<p>In Timav I also added full-day logs that describe <em>events</em>.
Event can be a big milestone or deadline (I'm adding event notes to describe what it was about) or a payment (I use special tag <code>@cash()</code>, so <code>@cash(1000)</code> would mean I earned 1000PLN on a given day).</p>
<p>Third version was also a big technology change, I used Clojure and Clojurescript together with Neo4j, just because I wanted to learn them.
It took around 80 hours to build, and was used for over a year.
The biggest problem was performance — it was my first big thing built with Clojurescript, and I didn't pay much attention to how well it worked.
Turns out that if I have to wait for a minute for the app to load, I'm not going to use it that much.</p>
<p>But it a had few interesting ideas, first of all I had a chart that would show me how I've spent my time between most important tags for me at the moment (here <code>@work</code> and <code>@personal</code>):</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/vanilla-3-1.png" alt="" width="1280" height="720">
<p>I've also built this <em>chain</em> view which showed me each day of the year, with red representing <code>@work</code> and blue <code>@personal</code>:</p>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/vanilla-3-2.png" alt="" width="1382" height="1222">
<p>You can clearly see the 2015 when I wasn't doing any personal projects, and how building third version at beginning of 2016 pushed me to work for at least few minutes on some personal project every day.</p>
<p>The idea has worked — by changing the tool, I changed what I do.</p>
<p>The performance was still a problem, and since I started doing <em>one-project-a-month</em> this year I wanted to finally improve, and open source it.
That's how <em>Timav</em> was born.</p>
<h2>Timav</h2>
<p>Timav is built around ideas that have been collected for last four years, it's still work in progress, and I plan on getting back to it later this year.
For now it provides two views:</p>
<ol>
<li>Projects — with info about logs connected to the projects, featuring a simple chart of time spent, and cash calculations if there are any</li>
<li>Chains — which allows me to track last couple of days with given tag, this lets me build up momentum and create new habits</li>
</ol>
<img src="https://szymonkaliski.com/writing/2017-04-30-time-tracking/timav-2.png" alt="" width="1382" height="902">
<p>All logs still come from Google Calendar, so on the first run you'll have to authorise application access in Settings, and choose calendar where tracking data is stored.</p>
<h2>Fin.</h2>
<p>Timav took 29 hours to build, but is far from complete.</p>
<p>I'm not sure about the Chains UI, I would love more detailed info about the tags in Projects view, and I've been thinking of explorable Gantt Chart for all the projects, so I can see when I'm overworked.
I'm also missing the big-picture view from version three, where I could see the progress since the beginning.</p>
<p>If you want to hack on Timav, it's open sourced and available on my Github: <a href="https://github.com/szymonkaliski/Timav">szymonkaliski/Timav</a>, but honestly, it's probably better if you build your own, I wouldn't want my ideas to limit yours.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-04-30-time-tracking/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-04-30-time-tracking/</guid>
            <pubDate>Sun, 30 Apr 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building Parametrium]]></title>
            <description><![CDATA[<p><a href="http://szymonkaliski.github.io/parametrium">Parametrium</a> is a <em>parameter space</em> explorer for P5.js sketches.
It analyses abstract syntax tree to find constants in uploaded code, and modifies them with interactive evolutionary algorithm.
It was built during my 1-project-a-month <em>meta-project</em> in March 2017.</p>
<img src="https://szymonkaliski.com/writing/2017-03-31-parametrium/screenshot.png" alt="" width="1382" height="1222">
<h2>Intro</h2>
<p>When I work with creative generative systems, it feels like I spend as much time fiddling with different <em>knobs</em> as I spend writing code.</p>
<p>By knobs I mean not only GUI sliders, but also code constants, array sizes, etc.
The bigger the system is, the more knobs it has, and it becomes harder and harder to explore.
It also usually feels like the nicest results come out of extremely specific set of values, and once I find them, it's scary to start fiddling with them again.</p>
<p>I always wanted to able to move through this parameter space fluidly and see the results in real time.
To collaborate with the machine, instead of setting everything by hand.</p>
<p>In February I explored evolutionary algorithms for generating simple <code>GLSL</code> code in <a href="https://szymonkaliski.com/projects/wallgen/">WallGen</a>, and I started wondering how much of that evolutionary process could be abstracted and re-used for more general purpose.</p>
<h2>AST</h2>
<p>First step in making this a reality was to detect all the numbers in code.
I could have used regular expressions, but it's usually a bad idea when it comes to very complex structures (like code).</p>
<p>A proper way of analysing most of programming languages, is parsing them into abstract syntax tree - data structure describing the source code.</p>
<p>This tree can be then traversed and transformed, and as long as it's kept in proper shape, it can be pretty-printed back into text form.
So a simple identity function on code would turn it into AST and back into code: <code>code -> AST -> code</code>.</p>
<p>I've spent a few days trying out different libraries for building and transforming ASTs, and settled on <a href="https://github.com/benjamn/recast">recast</a>.
Parsing with recast is pretty simple in it's most basic form:</p>
<pre><code class="language-js">const ast = recast.parse(sourceCode);

recast.visit(ast, {
  // visit Literal - numbers, strings, etc...
  visitLiteral: function (node) {
    // node.value has raw and parsed value,
    // node.value.value is parsed: 17 instead of "17"
    if (isNumber(node.value.value)) {
      console.log(node, "is a number!");

      // I now know that node is a number, so I can modify it
      node.value.value = Math.random() * node.value.value;
    }

    // tells recast to keep on going
    this.traverse(node);
  },
});
</code></pre>
<p>I tested this on few simple P5.js sketches, it worked well until I hit loops, and colors.</p>
<p>As for the loops, the problem is that numbers can be used to iterate over array, and <code>array[1]</code> exists, but <code>array[0.3551355]</code> does not:</p>
<pre><code class="language-js">for (var i = 0; i &#x3C; 10; i++) {
  points[i].draw();
}
</code></pre>
<p>If starting or ending conditions get changed to floating point numbers (or numbers outside of <code>points.length</code>) this would break horribly, with the infamous <code>undefined is not a function</code>.
I had to find a way to detect if number is part of <code>for</code>/<code>while</code> loop, there are two easy ways in which this could happen: <code>for (var i = 0 ...</code>, and <code>for (i = 0 ...</code>.
It's enough to walk few times up in the tree, and find out whether parent node is <code>for</code> or <code>while</code>.</p>
<p>Unfortunately there's one much more problematic case:</p>
<pre><code class="language-js">var n = 10;

...

for (var i = 0; i &#x3C; n; i++) { ... }
</code></pre>
<p>I've spent a good few days on this one, and I'm still not sure whether my approach is the best one, but it seems to work.
Whenever AST finds a number, which is a part of variable declaration (<code>var i = 10</code>), I ask AST for a whole scope in that place, and traverse it, looking for anything that involves this variable's name (<code>i</code> in this example).
When I find something, I test again if it's a part of <code>for</code>/<code>while</code>, and act on that number differently.</p>
<p>Relevant piece of code can be found on github: <a href="https://github.com/szymonkaliski/parametrium/blob/169ead475e85c61a36b3ce736477d08b88e9c203/src/code-transform/index.js#L73-L88"><code>code-transform/index.js</code></a>.
If you know a better way, please submit an issue or pull request.</p>
<p>Colors are a simpler version of this problem, for example turning <code>background(100)</code> into <code>background(300)</code> (or worse <code>background(-100)</code>) doesn't make any sense.
Numbers found inside of few specific functions (<code>fill</code>, <code>stroke</code>, <code>background</code>, etc...) should be limited between 0 and 255.</p>
<p>So, another check that I run finds out if the <em>callee</em> (function that calls some piece of code) matches one of pre-defined functions.
We have two basic cases here, simple one: <code>fill(10, 20, 100)</code>, and complex one, same as with <code>for</code>/<code>while</code> loops:</p>
<pre><code class="language-js">var r = 120;

...

fill(r, 10, 20);
</code></pre>
<p>I tackled it exactly the same as with loops, but instead of looking for <code>for</code>/<code>while</code> I look for <em>callee</em> names.</p>
<p>A relevant piece of code can be found on github: <a href="https://github.com/szymonkaliski/parametrium/blob/169ead475e85c61a36b3ce736477d08b88e9c203/src/code-transform/index.js#L97-L110"><code>code-transform/index.js</code></a>.</p>
<p>Both solutions are not ideal, but cover <em>most</em> of the cases I could find.</p>
<p>Final code analysis and transformation has to be split into two parts to fit the evolutionary algorithm approach.
I find numbers and their <em>types</em> first and run evolution on this list (with <em>mutation</em> taking in account the <em>type</em> of a number).
When new set of numbers is evolved, I generate a new code, using the modified array and traversing through the input again, this time replacing numbers at matching indexes.</p>
<h2>Displaying the results</h2>
<img src="https://szymonkaliski.com/writing/2017-03-31-parametrium/render.jpg" alt="" width="1280" height="720">
<p>Another thing to tackle was how to show more than one sketch at a time.
The simplest solution would be to force users to use <a href="https://github.com/processing/p5.js/wiki/p5.js-overview#instantiation--namespace"><em>instance mode</em></a> and provide different containers for each of the sketches.
My aim was to make the tool as frictionless as possible and to not force users to change anything about their code, so I thought of using <code>&#x3C;iframes></code> to contain the sketches.
I wanted to have this running without a backend, so responding with different <code>HTML</code> documents containing different modified sketches for different URLs, would be tricky to do.
Luckily there's <code>srcdoc</code> attribute on <code>&#x3C;iframe></code> in html5, and the final rendering code became very simple:</p>
<pre><code class="language-js">const generateHTML = (code) => `
  &#x3C;style>
    * { margin: 0; padding: 0; }
  &#x3C;/style>

  &#x3C;script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.js">&#x3C;/script>

  &#x3C;script type="text/javascript">
    ${code}
  &#x3C;/script>
`;

const Renderer = ({ width, height, code }) => (
  &#x3C;div>
    &#x3C;iframe
      scrolling="no"
      width={width}
      height={height}
      srcDoc={generateHTML(code)}
    />
  &#x3C;/div>
);
</code></pre>
<h2>Attempt at automated testing</h2>
<p>While I was working with AST part of the project, I wanted to test on as many different P5.js sketches as possible.
Someone on twitter suggested using <a href="https://www.openprocessing.org/">openprocessing</a> as a source of sketches, and I quickly wrote this simple scraper: <a href="https://github.com/szymonkaliski/openprocessing-scraper">openprocessing-scraper</a>.
There's over 500 megabytes of sketches there, with over 2700 P5.js ones, it didn't make sense to test them all by hand.</p>
<video loop autoplay muted>
  <source src="https://szymonkaliski.com/writing/2017-03-31-parametrium/electron-tests.mp4" type="video/mp4">
</video>
<p>I experimented with simple electron application that would load all the sketches in directory one-by-one and report on errors.
Unfortunately, it turned out that most of the sketches reported as broken had already been broken before my AST transformer did anything.
On the other hand, errors that I was looking to find wouldn't necessary show up as JavaScript errors, so I gave up on this for now.</p>
<p>In case anyone would like to take this idea further, I left it in the repo: <a href="https://github.com/szymonkaliski/parametrium/tree/master/tests/code-transform-electron-tests">code-transform-electron-tests</a>.</p>
<h2>Fin.</h2>
<p>This project was the first one this year that really pushed me to learn something new — traversing and transforming JavaScript ASTs.</p>
<p>I've spent more time exploring and failing, since I knew all other parts were either already there (evolution), or easy to make (UI).</p>
<p>As usual, there's a lot that could be improved, and I think with relatively little work, this could support different creative-coding libraries as well.</p>
<p>You can play with live version here: <a href="http://szymonkaliski.github.io/parametrium">http://szymonkaliski.github.io/parametrium</a>.</p>
<p>Code is open sourced and available with MIT license here: <a href="https://github.com/szymonkaliski/parametrium">szymonkaliski/parametrium</a>.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-03-31-parametrium/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-03-31-parametrium/</guid>
            <pubDate>Fri, 31 Mar 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Parametrium]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/parametrium/screenshot.png" alt="Screenshot" width="1382" height="1222">
<p><a href="http://szymonkaliski.github.io/parametrium">Parametrium</a> is a <em>parameter space</em> explorer for P5.js sketches.</p>
<p>It allows users to interactively move through parameter space of all the code constants, without modifying anything in code.</p>
<p>You can find more details (including info on AST transformations) in this blog post: <a href="https://szymonkaliski.com/writing/2017-03-31-parametrium/">building parametrium</a>.</p>
<p>Live version is running on github pages: <a href="http://szymonkaliski.github.io/parametrium">http://szymonkaliski.github.io/parametrium</a>, and code is open sourced: <a href="https://github.com/szymonkaliski/parametrium">szymonkaliski/parametrium</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/parametrium/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/parametrium/</guid>
            <pubDate>Fri, 31 Mar 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building Wallgen]]></title>
            <description><![CDATA[<p><a href="http://szymonkaliski.github.io/wallgen">Wallgen</a> is an evolutionary wallpaper generator using genetic algorithm to create never ending list of abstract <em>ambient</em> wallpapers.
It was built during my 1-project-a-month <em>meta-project</em> in February 2017.</p>
<img src="https://szymonkaliski.com/writing/2017-02-28-building-wallgen/screenshot.png" alt="" width="1382" height="1062">
<h2>Intro</h2>
<p>My favourite desktop wallpapers are calming blurry colors, but it's hard to find them and I lack enough Photoshop skills to make something I enjoy looking at.</p>
<img src="https://szymonkaliski.com/writing/2017-02-28-building-wallgen/wallpaper-folder.png" alt="" width="1382" height="902">
<p>My solution to this <em>"problem"</em> was to try to generate them with code, ideally in a way that I could potentially get an endless stream of nice soothing abstract blurs.</p>
<h2>Generating blur</h2>
<p>The first step was to actually get something on a screen, and to get nice and performant fullscreen gradients, I jumped straight to GLSL.
It would be possible to use CSS gradients for example, but for anything more complex than linear/radial gradient it would get tough.</p>
<p>I thought of these kinds of blurs as a set of points which emanate colours.
Combining multiple points with nice color palette and proper placing together could create images similar to what I was looking for.</p>
<p>I got to what seemed like a good approach using <code>distance</code> and <code>mix</code> in GLSL.
Most basic gradient looked like this:</p>
<img src="https://szymonkaliski.com/writing/2017-02-28-building-wallgen/shader.png" alt="" width="1382" height="1062">
<p>Rendered with this small piece of code:</p>
<pre><code class="language-glsl">precision mediump float;

uniform vec2 iResolution;

void main() {
  vec3 color1 = vec3(0.75, 0.31, 1.0);
  vec3 color2 = vec3(0.232, 0.42, 0.529);

  vec2 gradientPoint = vec2(0.23, 0.47);

  vec2 pos   = gl_FragCoord.xy / iResolution.xy;
  float dist = distance(pos, gradientPoint);

  gl_FragColor = vec4(mix(color1, color2, dist), 1.0);
}
</code></pre>
<h2>Generating <em>a lot</em> of blurs</h2>
<p>Getting one shader to work was the easy part, but I wanted endless, similar, but not exactly the same wallpapers.</p>
<p>I started toying with this idea few months back, first approaching this as a <a href="https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm">k-NN</a> problem, with a logic resembling this one:</p>
<ol>
<li>generate a lot of random wallpapers</li>
<li>allow user to select a set of "target wallpapers"</li>
<li>keep coming up with random wallpapers until they are close enough (k-NN) to the set of target wallpapers</li>
</ol>
<p>This has worked awfully — basically, I had been trying to keep coming up with random values until I found a subset close enough to what I like.</p>
<p>The next step was to try to reverse this process — to only come up with random values near the <em>"target"</em> set.
An evolutionary algorithm seemed like an obvious solution — starting with random population of wallpapers and steering the process toward user-selected goal.</p>
<p><a href="http://shiffman.net/">Daniel Shiffman</a> has a great explanation of genetic algorithms in his <a href="http://natureofcode.com/">"Nature of Code"</a> book: <a href="http://natureofcode.com/book/chapter-9-the-evolution-of-code/">natureofcode.com/book/chapter-9-the-evolution-of-code/</a> so I'm not going to go into the details here.</p>
<p>The most challenging problem in interactive evolution is coming up with a nice balance between number of choices presented to the user and calculations based around fitness function.
I didn't want to ask user to rate each of possibly thousands of generated wallpapers, and I came up with a simple solution — the user selects just one wallpaper to "evolve", and fitness of the rest of the wallpapers is calculated as distance from user selected one.
Wallpaper <em>DNA</em> is represented as an array of normalized floating point values, so calculating distances between these arrays is easy, although far away from what happens in nature — I'm not even comparing phenotypes, and two arrays which are very similar in <em>DNA</em> could potentially yield very unalike images.
But it was good enough for this experiment, and I couldn't come up with any other ideas anyways.</p>
<img src="https://szymonkaliski.com/writing/2017-02-28-building-wallgen/notes.jpg" alt="" width="1280" height="720">
<h2>Make it fast</h2>
<p>I try to follow simple set of rules when coding: <a href="http://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast">make it work, make it right, make it fast</a>.</p>
<p>After getting to the point where my generated images started to look similar but different to the previous choices, and after making the code readable and functional (everything operating on immutable arrays and returning new immutable arrays) I ended up in a situation where bigger populations could evolve for few seconds, and since JavaScript is single-threaded it would block the browser.
I had been trying to optimize the code for an afternoon, but couldn't speed it up by a factor of 10x, so I decided to move the calculations to webworker — basically a separate thread to execute JavaScript in, which can communicate asynchronously with the main rendering thread.</p>
<p>Since I used <a href="https://facebook.github.io/immutable-js/">Immutable.js</a> for handling the data, I would have to first convert them to plain JavaScript values, then into JSON and do the opposite in webworker, and then after calculations are done do it again in another direction.
Stringifying with JSON can get quite slow, and since I could potentially use thousands of arrays, each with hundreds of floating point values, I was getting worried of potential bottleneck. Luckily I stumbled upon <a href="https://github.com/glenjamin/transit-immutable-js">transit-immutable-js</a> which can turn immutable structures into transit strings directly.</p>
<p>Still, after doing some tests, running evolution in webworker is slower than running the same code on a main thread (consistently by few percent).
I suspect it's because of an overhead of transit-ing and transmitting data, but it gives us an illusion of things happening much smoother, which is worth few extra milliseconds.</p>
<h2>Make it pretty</h2>
<div>
  <video loop autoplay muted><source src="https://szymonkaliski.com/writing/2017-02-28-building-wallgen/transitions.mp4" type="video/mp4"></video>
</div>
<p>After each evolution step, the whole population is replaced with a new one.
I wanted to make this easy on the eyes, and since each genotype is an array of numbers (with constant length) it was easy to <em>"morph"</em> them into each other.</p>
<p>I render GLSL with amazing <a href="https://github.com/gre/gl-react">gl-react</a> so I just had to re-calculate that genotype array to get my transitions.
I wanted to make this automatic as well, and I ended up with a simple loop function powered by <code>requestAnimationFrame</code> (I'm using <code>raf</code> here) — every time the phenotype component receives new genotype data it starts the update loop, which goes on until current rendered values equal the target ones.
Thanks to Immutable.js comparing two arrays for equality requires just <a href="https://facebook.github.io/immutable-js/docs/#/is"><code>.is()</code></a>, and is very fast.</p>
<p>Below is a relevant part of phenotype component class, whole file is on github: <a href="https://github.com/szymonkaliski/wallgen/blob/master/src/components/phenotype/index.js">phenotype.js</a>.</p>
<pre><code class="language-js">updateLoop() {
  const eps = 0.01;
  const k   = 0.9;

  // move towards target code
  const code = this.state.code.map((v, i) => {
    const dist = abs(v - this.props.code.get(i));

    return dist &#x3C; eps ?  this.props.code.get(i) : k * v + (1 - k) * this.props.code.get(i);
  });

  this.setState({ code });

  if (!code.is(this.props.code)) {
    // keep updating if current code is different from target one
    this.rafHandle = raf(this.updateLoop);
  }
  else {
    raf.cancel(this.rafHandle);
    this.rafHandle = undefined;
  }
}

componentWillReceiveProps(nextProps) {
  if (!nextProps.code.is(this.state.code) &#x26;&#x26; !this.rafHandle) {
    // start animating if target differs from current code
    this.rafHandle = raf(this.updateLoop);
  }
}
</code></pre>
<h2>Fin.</h2>
<p>This project was simpler than January's <a href="https://szymonkaliski.com/projects/sdf-ui/">SDF-UI</a>, and took 6 hours less to make (totaling in almost 24 hours of development time).
There was a lot to figure out, and I ended up learning about webworkers, and implementing my first evolutionary algorithm after I finished college.</p>
<p>Like the last time, there's a lot that could be improved, but March is almost there, and I'm going to move on to something else.</p>
<p>You can play with live version here: <a href="http://szymonkaliski.github.io/wallgen">http://szymonkaliski.github.io/wallgen</a>.</p>
<p>Code is open sourced and available with MIT license here: <a href="https://github.com/szymonkaliski/wallgen">szymonkaliski/wallgen</a>.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-02-28-building-wallgen/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-02-28-building-wallgen/</guid>
            <pubDate>Tue, 28 Feb 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Wallgen]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/wallgen/screenshot.png" alt="Screenshot" width="1382" height="1062">
<p><a href="http://szymonkaliski.github.io/wallgen">Wallgen</a> is an evolutionary wallpaper generator, using genetic algorithm to create never ending list of abstract <em>ambient</em> wallpapers.</p>
<p>Selecting one of initial random wallpapers to <em>evolve</em> makes it the most <em>fit</em> one in the current population, giving it the biggest chance to crossover (exchange genetic material with another wallpaper). Wallpapers also mutate with small random chance, and can be easily downloaded.</p>
<p>You can find more details in this blog post: <a href="https://szymonkaliski.com/writing/2017-02-28-building-wallgen/">building wallgen</a>.</p>
<p>Live version is running on github pages: <a href="http://szymonkaliski.github.io/wallgen">http://szymonkaliski.github.io/wallgen</a>, and code is open sourced: <a href="https://github.com/szymonkaliski/wallgen">szymonkaliski/wallgen</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/wallgen/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/wallgen/</guid>
            <pubDate>Sat, 25 Feb 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Building SDF-UI]]></title>
            <description><![CDATA[<p><a href="https://sdf-ui.firebaseapp.com/">SDF-UI</a> is a node-based DSL for generating complex shapes using SDF, GLSL and WebGL, that I've build in January 2017.
You can read more about it here: <a href="https://szymonkaliski.com/projects/sdf-ui/">projects/sdf-ui</a>.</p>
<img src="https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/screenshot.png" alt="" width="1696" height="1296">
<h2>(Pre-) Intro</h2>
<p>I have a quite common problem of not finishing personal projects.
I tend to start a lot of them, and once the main problem is semi-solved (or I get bored), I move on to something else, leaving no trace of having anything done.
I usually learn something in the process, but it would be much nicer, and hopefully more useful, to have something to share.</p>
<p>In 2017 I decided to work on a single personal project every month, with strong incentive to publishing it at the end of that month, and SDF-UI is first project of that kind.</p>
<h2>Intro</h2>
<p>You can read more about SDFs and why they are cool on the <a href="https://szymonkaliski.com/projects/sdf-ui/">project page</a> and all over the internet, so I'm going to skip that part.</p>
<p>I was experimenting with this technique for generating images in November last year, and one of the biggest problems for me was that after a bit of fun, modeling function would turn into a mess similar to that:</p>
<pre><code class="language-glsl">return vec2(
    max(
      -sdBox(p, vec3(r + .01, r * 2. - c, r - c)),
      max(
        -sdBox(p, vec3(r - c, r * 2. + .01, r - c)),
        max(
          -sdBox(p, vec3(r - c, r * 2. - c, r + .01)),
          max(
            -sdSin(p - vec3(0., r - 1.0, 0.)),
            sdBox(p, vec3(r, r * 2., r))
            ),
          )
        )
      ),
    0.0);
</code></pre>
<p>Obviously, this could have been written much nicer, but then all the parts of the scene must have been named (<code>box1</code>, <code>box2</code>, etc...), and this additional thing to keep in mind doesn't compose well with <em>play</em> mindset, at least for me.</p>
<p>Second reason why I wanted to work on this is that I've already built few node-based UIs, one for <a href="http://flow-control.io/work/zamek-interactive-movie/">building interactive movies</a>, and then two much more interesting ones.
First one is MIDI preprocessor for <a href="https://herrmuttlobby.com">HLO</a> which allows users to modify MIDI messages on the fly and route them between hardware (MIDI keyboards, Arduinos, etc..) and software (OSC, virtual MIDI).</p>
<img src="https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/midi-preproc.png" alt="" width="1376" height="1056">
<p>Second project is SAM 2.0 for <a href="https://www.samlabs.com">SAM Labs</a> - a visual programming language for connecting different bluetooth modules together, aimed at kids.
Unfortunately both of these projects aren't finished yet, and it doesn't seem they will see the light any time soon.</p>
<h2>Graph</h2>
<p>When working on projects like that, I like to start with the thing that I know I have no idea how to do.</p>
<p>In this case that was turning the graph structure into linear shader code.</p>
<p>I started with sketching ideas for graph structure:</p>
<ul>
<li>nodes represent GLSL functions (<code>sdSphere()</code>, <code>opRepeat()</code>, etc.)</li>
<li>nodes can have multiple inputs (function arguments), but only single output (<code>float</code>, <code>vec2</code>, <code>vec3</code>, etc.)</li>
<li>node output can be connected to multiple inputs, but node input can only have one incoming edge (if you imagine input as function argument, there's no easy way of putting two values there at the same time)</li>
</ul>
<p>Basic JSON representing this structure looked like that:</p>
<pre><code class="language-json">{
  "nodes": {
    "n001": { "id": "n001", "type": "sdSphere" },
    "n002": { "id": "n002", "type": "sysInput" },
    "n003": { "id": "n003", "type": "sysOutput" }
  },

  "edges": {
    "e001": {
      "id": "e001",
      "from": { "id": "n001" },
      "to": { "id": "n003", "inlet": "d" }
    },
    "e002": {
      "id": "e002",
      "from": { "id": "INPUT" },
      "to": { "id": "n003", "inlet": "p" }
    }
  }
}
</code></pre>
<p>This would represent simple connection: <code>sysInput -> sdSphere -> sysOutput</code>.</p>
<p>I kept this JSON in a file, and started working on ideas how to <em>unwind</em> the graph.
I ended up with solution where I start from <code>sysOutput</code> node (I know this is the output of the system), and build up by finding what is connected to its input, then by what is connected to that node inputs, and so on.
This recursive function is in <a href="https://github.com/szymonkaliski/SDF-UI/blob/master/src/engine/compile-graph.js"><code>compile-graph</code> file</a>.</p>
<p>Walking the graph backwards is unfortunately not enough to build the shader code — we need to store and access GLSL code that given node type represents: <code>sdSphere</code> has to be turned into <code>sdSphere(p, pos, r)</code> etc.</p>
<p>Second part of the system is a function which generates class for node from simple spec file.
All nodes are created like that:</p>
<pre><code class="language-js">export default generateNode({
  spec: {
    inlets: [
      { id: "p", type: "vec3", value: "vec3(0.0)" },
      { id: "r", type: "float", value: "0.5" },
    ],
    outlet: { id: "d", type: "float" },
  },

  frag: `
float sdSphere(vec3 p, float s) {
  return length(p) - s;
}`,

  generate: ({ p, r }) => {
    return `sdSphere(${p}, ${r})`;
  },
});
</code></pre>
<ul>
<li><code>spec</code> part describes inlets and outlet of that node</li>
<li><code>frag</code> is part of fragment shader that will be injected into final GLSL code</li>
<li><code>generate</code> is function which receives all inlet values and returns string that will be injected into modeling part of the GLSL code</li>
</ul>
<p>You can have a look at internals of <a href="https://github.com/szymonkaliski/SDF-UI/blob/master/src/engine/generate-node.js"><code>generateNode</code></a>.
I think most interesting part is little trick with overwriting <code>toString</code> of returned class.
This allows me to simply plug instances of different classes into each other exactly as if I was concatenating strings.</p>
<p>For example, in <code>sdSphere</code>, if <code>r</code> is connected to <code>mathSin</code> which is connected to <code>sysTime</code>, it will first run <code>toString()</code> on <code>mathSin</code>, which in its <code>generate</code> function will run <code>toString()</code> on <code>sysTime</code> which will return string <code>time</code> (uniform, but that's not important), thus turning this whole chain into <code>sdSphere(p, sin(time))</code>.
On the other hand if <code>r</code> isn't connected to anything it will grab default value for this input — string <code>0.5</code> turning final code into <code>sdSphere(p, 0.5)</code>.
Neat, right?</p>
<p>One thing I wish I could spend more time on was designing the actual DSL that I've created. I tried to keep an eye on things happening organically — I ended up only using <code>float</code> and <code>vec3</code> types, and tried to keep naming and conventions consistent — nodes generating surfaces always have point <code>p</code> as first input, distance is always named <code>d</code>, etc.</p>
<h2>UI</h2>
<p>Once GLSL generation was in place, I started working on the UI.</p>
<p>One month seems like a long time, but I only get 1-2h a day tops for working on my own things, so I had to be pragmatic if I wanted to finish this in time.</p>
<p>I chose stack that I know well: <a href="https://facebook.github.io/react/">react</a>, <a href="https://github.com/gre/gl-react">react-gl</a>, <a href="https://github.com/reactjs/redux">redux</a> and <a href="https://facebook.github.io/immutable-js/">immutable</a>.</p>
<img src="https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/sketch.jpg" alt="" width="1422" height="800">
<p>I augmented initial JSON with <code>x</code> and <code>y</code> positions of each node, and started drawing things on screen — first nodes in its proper positions, then connections between them as SVG lines. Dragging is performed by dynamically adding <code>mosemove</code> event on <code>mousedown</code>, and removing on <code>mouseup</code> — something I've found to be most reliable. You can look at <code>onMouseDown</code> in <a href="https://github.com/szymonkaliski/SDF-UI/blob/master/src/components/editor/editor-node.js"><code>editor-node</code> file</a>.</p>
<p>One of tricks I came up with, inspired mostly by <a href="https://github.com/omcljs/om"><code>om</code></a>, is to keep almost everything in the redux store.
This gives us nice property of being able to dump it in <code>localStorage</code> on every change, and load it from there every time the app is loaded, which gives us something resembling cheap code hot-replace.
It's still easier to set up and manage than HMR in my experience.</p>
<pre><code class="language-js">// check if we are in "debug" mode (http://localhost:3000/?debug)
const isDebug = window.location.search.indexOf("debug") >= 0;

let parsed;

if (isDebug) {
  try {
    parsed = JSON.parse(localStorage.getItem("state"));
  } catch (e) {
    console.error(e);
  }

  // helpful global function for clearing the state
  window.clearState = () => {
    localStorage.setItem("state", null);
    window.location.reload();
  };
}

const initialState = parsed || defaultState;
</code></pre>
<p>This helpful thing allowed me to play with design and debug without having to re-create the state every time from scratch.</p>
<p>Second nice redux trick is keeping all actions in a hash-map, it's easy then to find typos and unhandled actions:</p>
<pre><code class="language-js">const actions = {
  ADD_NODE: addNode,
  MOVE_NODE: moveNode,
  DELETE_NODE: deleteNode,
};

export default (state = initialState, action) => {
  if (actions[action.type]) {
    state = actions[action.type](state, action);
  } else {
    console.warn(`No handler for action ${action.type}`);
  }

  return state;
};
</code></pre>
<h2>Fin.</h2>
<p>I've finished this project in exactly 30 hours of coding, which I think is pretty good for what it can currently do.
It's a nice feeling when things start clicking together, and at the end I was able to add bunch of different nodes quickly, because the architecture has been prepared for that since the beginning.</p>
<p>There's obviously a lot to improve on, but this has never been intended to be a finished product, but more of an inspiration and sample code for people wanting to experiment with building their own node-based DSLs.</p>
<p>You can play with live version here: <a href="https://sdf-ui.firebaseapp.com/">https://sdf-ui.firebaseapp.com/</a>, it's good idea to open <em>HELP</em> if you are visiting for the first time.</p>
<p>Code is open sourced and available with MIT license here: <a href="https://github.com/szymonkaliski/SDF-UI">szymonkaliski/SDF-UI</a>.</p>]]></description>
            <link>https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/</guid>
            <pubDate>Tue, 31 Jan 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[SDF-UI]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/sdf-ui/screenshot.png" alt="Screenshot" width="1696" height="1296">
<p><a href="https://sdf-ui.firebaseapp.com/">SDF-UI</a> is a node-based DSL for generating complex shapes using SDF, GLSL and WebGL.</p>
<p>SDF stands for Signed Distance Function - a function which returns the shortest distance between given input point and some surface. Sign of returned value indicates if point is inside, or outside that surface. Complex scenes can be defined in terms of SDFs and calculated using raymarching.</p>
<p>One of the nicest properties of SDFs is ease of manipulating shapes with constructive solid geometry (CSG): intersection, union and difference can be represented as simple operations on distances from two surfaces: <a href="https://sdf-ui.firebaseapp.com/?id=-KbfA0vlrFa17Sw6KeCL">example of CSG operations with SDF-UI</a></p>
<img src="https://szymonkaliski.com/projects/sdf-ui/csg.png" alt="CSG operations" width="1696" height="1296">
<p>For more explanation on SDFs visit:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Signed_distance_function">https://en.wikipedia.org/wiki/Signed_distance_function</a></li>
<li><a href="http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/">http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/</a></li>
<li><a href="http://iquilezles.org/www/articles/raymarchingdf/raymarchingdf.htm">http://iquilezles.org/www/articles/raymarchingdf/raymarchingdf.htm</a></li>
</ul>
<p>Project was made with <a href="https://facebook.github.io/react/">react</a>, <a href="https://github.com/gre/gl-react">react-gl</a>, <a href="https://github.com/reactjs/redux">redux</a> and <a href="https://facebook.github.io/immutable-js/">immutable</a>. Some of the SDF/GLSL code was borrowed from <a href="http://stack.gl">stack.gl</a> and <a href="http://mercury.sexy/hg_sdf/">hg_sdf</a>.</p>
<p>Live version is running on firebase: <a href="https://sdf-ui.firebaseapp.com/">https://sdf-ui.firebaseapp.com/</a>, and code is open sourced: <a href="https://github.com/szymonkaliski/SDF-UI">szymonkaliski/SDF-UI</a>.</p>
<p>You can read more about process behind making this project on the blog: <a href="https://szymonkaliski.com/writing/2017-01-31-building-sdf-ui/">building SDF-UI</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/sdf-ui/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/sdf-ui/</guid>
            <pubDate>Sun, 29 Jan 2017 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Teaching Creative Coding in Shanghai]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/writing/2016-12-29-ofcourse-io/group.jpg" alt="" width="1200" height="675">
<p>I've spent last two months of 2016 teaching intensive eight week creative coding course at <a href="http://ofcourse.io">OFCourse</a> in Shanghai.</p>
<p>All my previous experiences with teaching were short workshops (2-3 days), so preparing enough material for eight weeks was an interesting challenge.
Classes included Processing, Arduino and <em>Creative Lab</em>, where students worked on their own projects.</p>
<p>It was exciting to go deeply into topics, explore different aesthetics and interactions, something that's not possible during shorter workshops.</p>
<p>On Processing side, we started with introduction to programming, explored functions, and later classes.
Once we got good foundation for how objects work, we used Minim for making sounds, OpenCV for interacting with camera, and even some Machine Learning with Wekinator.</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/writing/2016-12-29-ofcourse-io/particles.mp4" type="video/mp4">
</video>
<p><a href="https://github.com/ofcourseio/OFCourseFall2016/blob/master/Processing_Week3_Particles/Processing_Week3_Particles.pde"><em>Particles interacting with mouse made as introduction to arrays</em></a></p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/writing/2016-12-29-ofcourse-io/opencv.mp4" type="video/mp4">
</video>
<p><a href="https://github.com/ofcourseio/OFCourseFall2016/blob/master/Processing_Week5_BasicOpenCV/Processing_Week5_BasicOpenCV.pde"><em>Introduction to edge detection with OpenCV</em></a></p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/writing/2016-12-29-ofcourse-io/classification.mp4" type="video/mp4">
</video>
<p><a href="https://github.com/ofcourseio/OFCourseFall2016/blob/master/Processing_Week6_CameraClassifier/Processing_Week6_CameraClassifier.pde"><em>Live camera image classification with Wekinator</em></a></p>
<br>
<p>We explored world of electronics with Arduino, starting from simple LED examples, through segment displays, LED matrixes, to working with different types of motors, and most importantly communicating with Processing through serial connection.
This last part was very inspiring for students, and almost all of final projects featured some kind of interaction with physical world.</p>
<div class="aspect-ratio aspect-ratio--16x9 mb1">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://player.vimeo.com/video/193035890?color=ffffff&#x26;title=0&#x26;byline=0&#x26;portrait=0" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p><em>One of midterm projects made by students</em></p>
<br>
<p>From my experiences, the hardest thing for students to understand was <em>scope</em>, where variables come to life, differences between global and local, and everything connected to that.</p>
<p>It also seems very strange that even with all the tools we have, it's still near impossible to teach without markers and whiteboard.</p>
<p>I'm glad I had the opportunity to be involved in this course, I'm a firm believer in giving back to community and sharing what I know.
It's also very encouraging to see students making progress, and having those little <em>eureka</em> moments when things start to click.</p>
<p>Code we created during workshops is available on github: <a href="https://github.com/ofcourseio/OFCourseFall2016">ofcourseio/OFCourseFall2016</a></p>]]></description>
            <link>https://szymonkaliski.com/writing/2016-12-29-ofcourse-io/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/writing/2016-12-29-ofcourse-io/</guid>
            <pubDate>Thu, 29 Dec 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Pi Cap]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/bareconductive-picap/miniature.jpg" alt="Pi Cap photo" width="1280" height="784">
<p>I collaborated with <a href="http://www.bareconductive.com/">Bare Conductive</a> in building software for <a href="http://www.bareconductive.com/shop/pi-cap/">Pi Cap</a> which brings capacitive sensing known from their <a href="http://www.bareconductive.com/shop/touch-board/">TouchBoard</a> to Raspbbery Pi.</p>
<p>Pi Cap has 12 electrodes for sensing capacitive touch, high quality audio output, prototyping area for soldering, button, and RGB led.</p>
<p>Our main task was to prepare software examples for users to quickly start playing with this board in C++ or Python. We also created Python wrapper for C++ MPR121 driver prepared by <a href="http://www.bycgwtsf.com/">Stefan Dzisiewski-Smith</a> from Bare Conductive.</p>
<div class="mw-100 flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/projects/bareconductive-picap/project-1.jpg" width="679" height="679">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/projects/bareconductive-picap/project-2.jpg" width="679" height="679">
  </div>
</div>
<p>Examples range from controlling RGB led and reading input from the button, to more complicated things, like streaming data through OSC, playing polyphonic sounds, and even text-to-speech.</p>
<p>All examples are open sourced and available at <a href="https://github.com/BareConductive">Bare Conductive's github account</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/bareconductive-picap/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/bareconductive-picap/</guid>
            <pubDate>Fri, 09 Sep 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Heartbeats]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="https://player.vimeo.com/video/176152973?color=FFF&#x26;title=0&#x26;byline=0&#x26;portrait=0" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>I created unique hardware, and custom software, which let <a href="http://piotrbejnar.com">Piotr Bejnar</a> play a concert on human heartbeats.</p>
<p>We built 12 bracelets reading pulse and movement data in real-time, custom software which controlled tempo of Piotr's music, and another application for live generative visualisations.</p>
<p>Bracelets were powered by Arduino Pro Mini with pulse sensor, accelerometer, and 868MHz radio. They communicated between each other and "main" radio transceiver via meshing network - even if one of the bracelets didn't "see" the master radio, it could communicate with it using other nodes.</p>
<div class="flex">
  <div class="w-100 mr1">
    <img src="https://szymonkaliski.com/bracelets-arduino.png" width="680" height="679">
  </div>
  <div class="w-100 ml1">
    <img src="https://szymonkaliski.com/bracelets-live.png" width="679" height="679">
  </div>
</div>
<p>Each bracelet was equipped with four RGB LEDs changing color based on a bracelet status - blue indicated that bracelet is working, and red meant connection to the DJ - the tempo from that bracelet is controlling tempo of a song.</p>
<p>Casing was 3D printed, and as straps, we used Apple Watch ones.</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/ballantines-heartbeats/3d-print.mp4" type="video/mp4">
</video>
<p>We wrote a lot of software for this project, it could be divided in main three parts:</p>
<ul>
<li>main transceiver - handling communication between all three computers and all bracelets through radio transceiver</li>
<li>audio controller - receiving data from main transceiver and controlling Ableton Live tempo</li>
<li>generative visuals - receiving the same data from transceiver and generating visuals on the fly</li>
</ul>
<p>Communication between all the machines was handled with OSC through ad-hoc network.</p>
<img src="https://szymonkaliski.com/max4live.jpg" alt="" width="1221" height="687">
<p>An audio controller, created in max4live, was running on Piotr’s machine. It allowed him to easily choose which bracelet currently controls tempo, and showed all data in real-time. While playing, Piotr was switching between active bracelets which were in turn controlling the song tempo.</p>
<p>Live visualas were important part of the whole project, they intended to show people that the actual tempo data is being controlled by the bracelets. We closely collaborated with amazing VJ and graphic/motion designer - <a href="http://uniforma.pl">Michał Mierzwa</a> - to build half-generative visuals.</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/ballantines-heartbeats/visuals.mp4" type="video/mp4">
</video>
<p>Part of them was made with fully geneative code in clojure and quil (processing wrapper), and another part were Michał's video samples created specially for that occasion. Live visuals application was rendering frames through Syphon, which allowed Michał to receive and display them easily as a part of his Modul8 workflow. In addition, Modul8 tempo was also synced to current bracelet tempo, making the whole concert synced to live heartbeat data.</p>]]></description>
            <link>https://szymonkaliski.com/projects/ballantines-heartbeats/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/ballantines-heartbeats/</guid>
            <pubDate>Mon, 18 Jul 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[glsl-auto-ui]]></title>
            <description><![CDATA[<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/glsl-auto-ui/demo.mp4" type="video/mp4">
</video>
<p><code>glsl-auto-ui</code> is an experiment in automatically generating UI components for <a href="https://workshop.chromeexperiments.com/examples/gui/">DAT.GUI</a> using GLSL uniforms.</p>
<p>It's an attempt at drastically shortening iteration time with (almost) immediate feedback.</p>
<p>The code is open sourced: <a href="https://github.com/szymonkaliski/glsl-auto-ui">szymonkaliski/glsl-auto-ui</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/glsl-auto-ui/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/glsl-auto-ui/</guid>
            <pubDate>Wed, 20 Apr 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[GLA London 2050]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/gla-london-2050/map.png" alt="Map screenshot" width="1429" height="804">
<p>I collaborated with <a href="http://variable.io">Variable studio</a> and <a href="http://www.squintopera.com">Squint Opera</a> to build online interactive application showing the next 50 years of London development.</p>
<p>This interactive data visualization includes changes in population, expansion in transportation, energy, education and many other factors that will impact the city growth and change.</p>
<img src="https://szymonkaliski.com/projects/gla-london-2050/main.png" alt="Main screenshot" width="1784" height="1150">
<p>We created map-based tool which allows stakeholders to explore the city growth and change, using data collected by Greater London Authority (GLA). The tool consists of four main parts: interactive map, timeline, filters, and additional data visualizations. The map was built with esri API, and shows the most important information for the users. It also allows them to filter by borough, or hand-drawn polygon.</p>
<img src="https://szymonkaliski.com/projects/gla-london-2050/timeline.png" alt="Timeline screenshot" width="1399" height="801">
<p>Timeline shows the time spans of scheduled projects, and allows to filter years which are interesting to the users, upon selection, map and other filters change.</p>
<img src="https://szymonkaliski.com/projects/gla-london-2050/filters.png" width="876" height="780">
<p>Filters on the right side show the most important information for current view, and adapt to data shown on map.</p>
<img src="https://szymonkaliski.com/projects/gla-london-2050/datavis.png" width="1410" height="627">
<p>Data visualizations on the bottom extend user information on selected view, giving them more context.</p>
<p>This tool is extremely interactive, a change in one filter or selection propagates through the whole application, allowing users to drill down and select the most interesting context for them. It was built with React, Redux, esri map API, and D3.</p>
<p>You can play with the live version of the application here: <a href="http://maps.london.gov.uk/ima/">http://maps.london.gov.uk/ima/</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/gla-london-2050/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/gla-london-2050/</guid>
            <pubDate>Mon, 01 Feb 2016 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Google I/O]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//www.youtube.com/embed/7V-fIGMDsmE?rel=0&#x26;controls=0&#x26;showinfo=0&#x26;start=463" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>I collaborated with <a href="http://variable.io">Variable studio</a> to create visualisation showing all Android device users, for the opening I/O keynote delivered by Sundar Pichai on 2015 Google I/O.</p>
<p>The visualisation was seen by 6000 attendees, and over 1.8M viewers online, and was displayed on 27k curved display, with over 17 million pixels covering 5m x 162m long canvas.</p>
<img src="https://szymonkaliski.com/projects/google-io-android-diversity/frames-1.png" width="1920" height="598">
<img src="https://szymonkaliski.com/projects/google-io-android-diversity/frames-2.png" width="1920" height="360">
<img src="https://szymonkaliski.com/projects/google-io-android-diversity/frames-3.png" width="1920" height="361">
<p>We started by exploring the dataset, using variable in-house pex library, writing a lot of small exploratory apps to test the ideas and see what we are dealing with. We were also researching ways of rendering on such a huge display, in order to keep artifacts away.</p>
<img src="https://szymonkaliski.com/projects/google-io-android-diversity/globe.jpg" alt="Globe screenshot" width="1253" height="705">
<p>We created a lot of custom tools for this project, most important ones being a timeline which helped us to time things properly and multiple views into the final screen, so we could test if element sizes and speeds are working.</p>
<img src="https://szymonkaliski.com/projects/google-io-android-diversity/preview.jpg" alt="Debug preview screenshot" width="1680" height="820">
<p>We were able to run the final code with smaller sample dataset in Google Chrome. Final rendering was done in Plask in less than 4 hours, thanks to JavaScript and WebGL we could quickly iterate and simply share preview visualisation with Google Data Arts team. Almost all of heavy-lifting was done with pixel shaders - including particle movement, using heavily modified flow-field, particles landing on the globe, and final globe unfolding.</p>]]></description>
            <link>https://szymonkaliski.com/projects/google-io-android-diversity/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/google-io-android-diversity/</guid>
            <pubDate>Sat, 28 Nov 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Fonomapa]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//player.vimeo.com/video/144728691?title=0&#x26;byline=0&#x26;portrait=0&#x26;color=ffffff" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>I've built an interactive installation for 20th Kids Art Biennale, for exploring the city of Poznań through field-recordings made by children.</p>
<p>The map became an interface for mixing different sounds together, letting children and grownups create ad-hoc experimental audio compositions.</p>
<img src="https://szymonkaliski.com/projects/fonomapa/table.jpg" alt="Fonomapa on a table" width="1103" height="621">
<p>Installation was created with using web technologies - mainly React and D3 - which allowed us to use the same codebase for on-site hardware (55-inch touchscreen table), and online version: <a href="http://fonomapa.com">fonomapa.com</a></p>
<img src="https://szymonkaliski.com/projects/fonomapa/online.png" alt="Online version" width="1665" height="961">
<p>Software was built entirely from scratch, one of most interesting techniques we used was rendering vector tiles with D3, which allowed us to control the design of map in very fine detail. Map was designed to give only a little help to the user, moving all the attention to the sounds.</p>
<img src="https://szymonkaliski.com/projects/fonomapa/cms.png" alt="CMS screenshot" width="1650" height="907">
<p>We also created custom CMS for easy sound upload and edition, with backend powered by node.js and mongodb.</p>]]></description>
            <link>https://szymonkaliski.com/projects/fonomapa/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/fonomapa/</guid>
            <pubDate>Thu, 08 Oct 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Kinect2OSC]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/kinect2osc/screenshot.png" alt="Application screenshot" width="942" height="764">
<p>Kinect2OSC is a small application for receiving and transmitting data from Kinect 360 through OSC.</p>
<p>It was build with openFrameworks and is available as open source: <a href="https://github.com/szymonkaliski/Kinect2OSC">szymonkaliski/Kinect2OSC</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/kinect2osc/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/kinect2osc/</guid>
            <pubDate>Sun, 20 Sep 2015 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[LoopPI]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//player.vimeo.com/video/108919777?title=0&#x26;byline=0&#x26;portrait=0&#x26;color=ffffff" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>LoopPI is a standalone four track audio looper made with Raspberry PI, ChucK and Node.js.</p>
<p>Each row of controls consists of two buttons and two potentiometers. First button toggles recording on and off, second one clears the loop, first potentiometer controls the loop volume, and second one controls feedback. Each loop is 8 seconds long with independent volume and feedback controls.</p>
<p>Audio processing part is written in ChucK (C-like language for audio), interface (buttons, potentiometers and LCD) in node.js.</p>
<p>This project is available as open source: <a href="https://github.com/szymonkaliski/LoopPI">szymonkaliski/LoopPI</a></p>
<p>In 2016 LoopPI was updated with recent Raspberry PI and Wolfson audio card for better sound quality: <a href="https://github.com/szymonkaliski/LoopPI2">szymonkaliski/LoopPI2</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/loop-pi/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/loop-pi/</guid>
            <pubDate>Sun, 19 Oct 2014 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[EEG2OSC]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/eeg2osc/screenshot.png" alt="Application screenshot" width="348" height="396">
<p>EEG2OSC was created for Rafał Zapała's <a href="https://szymonkaliski.com/projects/sensorium/">Sensorium</a> project. It was used to pass data from Emotiv EPOC EEG Headset to Max/MSP.</p>
<p>This tool was created with Objective-C, and uses Emotiv "Premium" SDK (for access to raw EEG data), and MetatoneOSC for OSC communication.</p>
<p>The code is available as open source: <a href="https://github.com/szymonkaliski/EEG2OSC/">szymonkaliski/EEG2OSC/</a></p>]]></description>
            <link>https://szymonkaliski.com/projects/eeg2osc/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/eeg2osc/</guid>
            <pubDate>Fri, 10 Oct 2014 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sensorium]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//player.vimeo.com/video/109455967?title=0&#x26;byline=0&#x26;portrait=0&#x26;color=ffffff" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>I collaborated with talented <a href="http://www.zapala.com.pl">Rafał Zapała</a> on his Sensorium installation, based on the idea of biofeedback from the viewer.</p>
<p>I created software for combining different signal sources - including EEG, GSR and pulse sensor, which let Rafał build his interactive composition, meant to be played on human emotions.</p>
<p>For EEG data we used <a href="http://emotiv.com">Emotiv</a> EPOC and written a data transceiver which outputs OSC messages - it's open source and available for free: <a href="https://github.com/szymonkaliski/EEG2OSC">szymonkaliski/EEG2OSC</a>.</p>
<img src="https://szymonkaliski.com/projects/sensorium/emotive.png" alt="Emotiv" width="1200" height="600">
<p>Pulse sensor and GSR were using e-Health Arduino platform: <a href="https://www.cooking-hacks.com/documentation/tutorials/ehealth-biometric-sensor-platform-arduino-raspberry-pi-medical">https://www.cooking-hacks.com/documentation/tutorials/ehealth-biometric-sensor-platform-arduino-raspberry-pi-medical</a></p>
<img src="https://szymonkaliski.com/projects/sensorium/pulse.png" alt="Pulse sensor" width="1200" height="600">
<p>Both hardware sensors were outputing OSC at the end of processing pipeline, and Rafał wrote his own Max/MSP code to generate music.</p>]]></description>
            <link>https://szymonkaliski.com/projects/sensorium/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/sensorium/</guid>
            <pubDate>Fri, 10 Oct 2014 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sonic Explorer]]></title>
            <description><![CDATA[<div class="aspect-ratio aspect-ratio--16x9 mb3">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//player.vimeo.com/video/108286932?title=0&#x26;byline=0&#x26;portrait=0&#x26;color=ffffff" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>
<p>I collaborated with talented <a href="http://marekstraszak.com">Marek Straszak</a> on interactive audio art piece, built for Art+Bits festival in 2014, and later exhibited at WRO Biennale 2015, the biggest Polish new-media art biennale.</p>
<p>The installation consists of five steel deconstructed icosahedrons, equipped with Arduinos and solenoids, which can be wirelessly controlled by a touchscreen interface. Solenoids hit the steel frame making sound, and because all of the geometries are different, the frequencies they make differ too.</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/sonic-explorer/ui.mp4" type="video/mp4">
</video>
<p>The heart of the installation was a minimalistic touchscreen-based UI, which allowed visitors to sequence solenoids hits.</p>
<div class="aspect-ratio aspect-ratio--16x9">
  <iframe class="aspect-ratio--object ba b--light-gray br2" style="margin:0!important" src="//player.vimeo.com/video/108286931?title=0&#x26;byline=0&#x26;portrait=0&#x26;color=ffffff" width="1280" height="720" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen>
  </iframe>
</div>]]></description>
            <link>https://szymonkaliski.com/projects/sonic-explorer/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/sonic-explorer/</guid>
            <pubDate>Wed, 08 Oct 2014 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Institut Des Mutations]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/institut-des-mutations/photo.jpg" alt="Photo" width="1200" height="699">
<p>I created a generative logo, working in close collaboration with <a href="http://lamoulade.com">La Moulade</a> design studio. We started from scratch, with an idea of organic movement and simplicity in mind.</p>
<p>First explorations started with metaballs, playing with different styles and ideas:</p>
<img src="https://szymonkaliski.com/projects/institut-des-mutations/metaballs1.jpg" alt="Metaballs" width="1475" height="829">
<p>A brief episode of highly sci-fi looking blobs:</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/institut-des-mutations/metaballs2.mp4" type="video/mp4">
</video>
<p>It appeared that metaballs resolution was a big issue, so we settled on using sphere vertex displacement:</p>
<video loop autoplay muted>
<source src="https://szymonkaliski.com/projects/institut-des-mutations/colors.mp4" type="video/mp4">
</video>
<p>Colors were an important part of final visualization, we experimented a lot with different ways of randomizing, and mixing shades:</p>
<img src="https://szymonkaliski.com/projects/institut-des-mutations/leaflet.png" alt="Mixing colors" width="2336" height="1589">]]></description>
            <link>https://szymonkaliski.com/projects/institut-des-mutations/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/institut-des-mutations/</guid>
            <pubDate>Fri, 28 Mar 2014 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nodation]]></title>
            <description><![CDATA[<img src="https://szymonkaliski.com/projects/nodation/screenshot.png" alt="Screenshot" width="1154" height="871">
<p><a href="http://nodation.herokuapp.com">Nodation</a> is an experimental take on creating music using graphs. It was created during my residency at <a href="http://fabrica.it">Fabrica</a> in Fabruary 2014.</p>
<p>Node distance from center is translated to pitch and connecting nodes creates melodies:</p>
<ul>
<li>To create playing node, click anywhere on the screen.</li>
<li>To connect nodes, hover over one of them, and drag line to another one.</li>
<li>To remove nodes, drag them to bottom red part of the screen.</li>
<li>You can save your creations, and share output URL.</li>
</ul>
<p>Project was created using node.js and mongodb for simple server (saving and loading of graphs), and <a href="https://github.com/vorg/pex">Pex</a> for frontend.</p>
<p>Live version is running on heroku: <a href="http://nodation.herokuapp.com">http://nodation.herokuapp.com</a>, and code is open sourced: <a href="https://github.com/szymonkaliski/nodation">szymonkaliski/nodation</a>.</p>]]></description>
            <link>https://szymonkaliski.com/projects/nodation/</link>
            <guid isPermaLink="true">https://szymonkaliski.com/projects/nodation/</guid>
            <pubDate>Wed, 19 Feb 2014 00:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>