<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Adam Renklint</title>
  <subtitle>Writing on Clojure, music programming, and building software.</subtitle>
  <link href="https://adamrenklint.com/atom.xml" rel="self"/>
  <link href="https://adamrenklint.com"/>
  <updated>2026-07-07T00:00:00+00:00</updated>
  <id>https://adamrenklint.com</id>
  <author>
    <name>Adam Renklint</name>
  </author>
  <entry>
    <id>https://adamrenklint.com/a-decade-of-music-programming-playgrounds</id>
    <link href="https://adamrenklint.com/a-decade-of-music-programming-playgrounds"/>
    <title>A decade of music programming playgrounds</title>
    <updated>2026-07-07T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>For more than ten years, I've been building small music-related libraries and environments. Coming from the iconic sample-based workflow of Akai MPC, I've researched, tried and discarded many attempts at building the music programming environment where I would myself feel most at home in.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/01.mp4"></video></p>
<p>The story starts in 2014, with building a library called <a href="https://github.com/adamrenklint/bap">Bap</a> to code beats with Javascript. At this point, I was still not enlightened and leaned fully into mutable objects and complicated connection graphs. While it may seem like a distant memory now, at that point in time, humans were still writing every single line of code by hand, and keeping the entire context window in their own memory.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/02.mp4"></video></p>
<p>My first deep dive into music programming focused mostly on encoding musical patterns as code with user interfaces borrowed from physical samples and drum machines. As in this example, the classic MPC pands and banks is transformed into a qwerty keyboard to interact with.</p>
<img src="/assets/playgrounds/03.png" alt="trn.gl, music programming playground screenshot, 2015">
<p>In the summer heat 2015, during a cross-country bus ride with broken air-condition, I had a revelation of how one would interact with my music programming libraries. Inspired and amazed by <a href="http://typedrummer.com">Type Drummer</a>, I spent a weekend non-stop coding the first version, and the next few months iterating with a handful of passionate beta testers. The environment was a lot of fun to create small sample-based loops in, but I grew frustrated with the limitations of the DSL, and started sketching on a more comprehensive and flexible music programming language and environment.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/04.mp4"></video></p>
<p>One of the limitations of the 2015 version of <a href="https://trn.gl">trn.gl</a> was that code was just static text, with no feedback about the sounds it produced at all. But solving the feedback problem was put to the side, in favor of going deeper with the programming surface itself: the syntax, the functions and the general concepts would have to be developed first.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/05.mp4"></video></p>
<p>In 2016, while working at Microsoft after the Wunderlist acquisition, I spent my evenings tinkering with different approaches to the environment and syntax.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/06.mp4"></video></p>
<p>I was conflicted between the simplicity of the 2015 version, and the ideal expressiveness I imagined my next environment to have. What is more important - that beginners can get started easily, or trading a higher learning curve for more power and flexibility? I am still searching for an answer to this question.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/07.mp4"></video></p>
<p>In 2017 I left the corporate grind and ended up spending a few months working hard on a version of <a href="https://trn.gl">trn.gl</a> to release to the public. This was my goal, and I came quite far, until at the end of the year I decided to found a new company together with a group of friends from Wunderlist and Microsoft. <a href="https://pitch.com">Pitch</a> was born, and for the next few years, little progress was made with my music programming.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/08.mp4"></video></p>
<p>In 2020 or 2021, I started building new experiments, this time focused on pattern manipulation in the spirit of <a href="https://tidalcycles.org/">TidalCycles</a>.</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/09.mp4"></video></p>
<p>Progress was slow, as my day job demanded most of the creativity and problem solving ability I had. But little did I know that this constraint was about to disappear...</p>
<p><video controls preload="metadata" playsinline src="/assets/playgrounds/10.mp4"></video></p>
<p>Fast-forward to 2026. The world of programming has changed, radically. With expressive prompts, we can generate basic apps and complex user interfaces. &quot;Writing code was never the hard part&quot;, they say, but for this personal side project, the ability to trade a few quick prompts for finished features with no manual effort has been life-changing, and has led to the newest iteration of <a href="https://trn.gl">trn.gl</a>.</p>
<p>Feedback via highlighting chunks of code is back as a first-class primitive, and this version takes the familiar shape of a coding playground like CodePen or JSFiddle. Having processed many iterations of a similar concept, both actively in the foreground but also often passively and completely in the background, writing the next prompt is never hard.</p>
<p>The vision of what <a href="https://trn.gl">trn.gl</a> should become feels effortless and inevitable.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/new-design</id>
    <link href="https://adamrenklint.com/new-design"/>
    <title>New design, again</title>
    <updated>2026-07-06T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>I like redesigning this site. I've done it many times over the years, and it keeps getting simpler. Here's where it's at now:</p>
<figure>
  <img src="/assets/design-history/design-2026.png" alt="The 2026 design of adamrenklint.com">
  <figcaption>adamrenklint.com, 2026</figcaption>
</figure>
<p>The look is modeled closely on <a href="https://shapedbyrobin.com">shapedbyrobin.com</a>, the personal site of designer <strong>Robin Granqvist</strong> (based on his &quot;Mono&quot; template). I'd been circling something Swiss and typographic for a while without quite landing it, and his site was exactly the thing. Full credit to Robin for the design language — I just rebuilt it in my own stack.</p>
<p>What I was after was restraint:</p>
<ul>
<li><strong>One typeface, one weight, one size.</strong> It's all <a href="https://rsms.me/inter/">Inter</a> medium, 16px, everywhere — the name, the body, the dates, the links. Bold shows up only for the rare bit of emphasis.</li>
<li><strong>Hierarchy from colour, not size.</strong> Black for what matters, grey for everything supporting it — my role, the dates. That's the whole system.</li>
<li><strong>Nothing decorative.</strong> No rules, no boxes, no gradients. Early drafts kept sneaking in dividing lines and I kept tearing them out. A strong typeface and simple colours carry it.</li>
<li>Instead of a menu, a single <strong>black triangle</strong> that links home, and a <strong>Contact</strong> link in the top right. No footer.</li>
</ul>
<p>The thing that makes it feel balanced is the uniform weight. Once everything is the same size and weight, the only way to signal importance is colour — and that constraint is what makes it calm.</p>
<h2>Every design before it</h2>
<p>Half the fun of redesigning is that the old versions don't really disappear. The <a href="https://web.archive.org/web/*/adamrenklint.com">Wayback Machine</a> has been quietly snapshotting this domain since 2010, so I can travel back and watch myself change my mind. A tour:</p>
<figure>
  <img src="/assets/design-history/design-2013.png" alt="The 2013 design: grey text on a grey background">
  <figcaption>2013 — grey on grey, and already calling myself a "minimalist in training."</figcaption>
</figure>
<figure>
  <img src="/assets/design-history/design-2015.png" alt="The 2015 design: a serif typeface with a blue band">
  <figcaption>2015 — a serif phase, with a blue streak and beats on the brain.</figcaption>
</figure>
<figure>
  <img src="/assets/design-history/design-2018.png" alt="The 2018 design: bold rounded sans-serif with a portrait">
  <figcaption>2018 — bold, rounded, and a face to go with it.</figcaption>
</figure>
<figure>
  <img src="/assets/design-history/design-2021.png" alt="The 2021 design: clean sans-serif, 'Hey, I'm Adam.'">
  <figcaption>2021 — pared back to a hello and a handful of links.</figcaption>
</figure>
<figure>
  <img src="/assets/design-history/design-2024.png" alt="The 2024 design: the same intro set in a serif">
  <figcaption>2024 — same words, borrowed serif (Neat CSS).</figcaption>
</figure>
<p>The throughline is obvious in hindsight: I keep chasing simpler. This latest one feels like the end of that particular road — though I've thought that before, and I'll probably think it again.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/pitch-agent</id>
    <link href="https://adamrenklint.com/pitch-agent"/>
    <title>Generate on-brand decks with Pitch Agent</title>
    <updated>2026-06-12T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<div class="video-embed"><iframe src="https://www.youtube.com/embed/sFP0JFVk6vs" title="Pitch Agent: On-brand AI presentations, made for professionals" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe></div>
<p>Two weeks ago we launched <a href="https://pitch.com/blog/introducing-pitch-agent">Pitch Agent</a>. The team put an enormous amount of work into this over the last couple of months, and I'm excited it's finally in the hands of our customers. It sets a high bar for what quality humans should expect of AI-assisted deck creation, and I'm proud to see Pitch lead the way in this new era.</p>
<p>Anyone can generate slides with AI now, and that's kind of the problem. The output all looks the same. Generic templates, weird colors, stock-photo filler, LLM-typical gradients. You can spot an AI deck from across the room, and if you're presenting to customers or investors, that's a dealbreaker. Your deck has to look like your company, not like everyone else's.</p>
<p>You give Pitch Agent a prompt or a document and it builds the deck, using your brand system along the way. Not happy with a slide? Keep prompting. And since it all happens inside Pitch, what you get is a real presentation you can edit and present, not a pile of images. Together with the rest of our platform, in particular the collaboration and distribution capabilities, Pitch is the best choice for teams and professionals that use decks to win work and drive their business forward.</p>
<p>Try it yourself at <a href="https://pitch.com">pitch.com</a>.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/screenframes</id>
    <link href="https://adamrenklint.com/screenframes"/>
    <title>screenframes, screen recording and smart frame extraction</title>
    <updated>2026-02-23T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>I built a small CLI tool called <a href="https://github.com/adamrenklint/screenframes">screenframes</a> that records a portion of your screen and extracts a curated set of frames showing only meaningful visual changes. It's designed to give AI coding agents eyes.</p>
<p>The problem is straightforward. When you're working with Claude Code or similar tools, they can't see what's happening on your screen. You can describe what you're looking at, or take manual screenshots. Both are tedious and lossy. What you want is to just record a chunk of your workflow and hand the agent a concise visual summary of what happened.</p>
<p><code>screenframes record</code> opens the native macOS region selector. Pick an area, do your thing, press Escape to stop. You get back the video and a set of deduplicated frames — only the ones where something actually changed.</p>
<p>The pipeline is simple: record with macOS <code>screencapture</code>, sample at 10 fps with ffmpeg, auto-crop to the region where pixels actually changed between frames, run perceptual dedup using phash to throw away near-identical frames, downscale to 1280px wide, and generate a markdown manifest with timestamps. You end up with maybe 9 frames from a 12 second recording instead of 120.</p>
<p>You can also skip the recording step entirely with <code>screenframes extract path/to/video.mov</code> if you already have a video from Cmd+Shift+5 or whatever.</p>
<p>The output is a timestamped directory with the cropped video, the frames, and the manifest. Drop the frames into a prompt and the agent has context it never had before.</p>
<p>Python, MIT licensed, <code>pipx install</code> from the repo. Requires macOS and ffmpeg.</p>
<p><a href="https://github.com/adamrenklint/screenframes">github.com/adamrenklint/screenframes</a></p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/next-evolution-of-programming-and-software</id>
    <link href="https://adamrenklint.com/next-evolution-of-programming-and-software"/>
    <title>The next evolution of programming and software</title>
    <updated>2026-02-10T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>I've been writing code and creating software as a hobby for three decades and professionally for fifteen years. For all of that time, the job has had the same fundamental loop. Humans write code, humans review code, humans deploy code, humans monitor what happens. The tools get better, the frameworks change, but the loop has stayed the same.</p>
<p>I think the loop is ending.</p>
<p>I've been doing AI-assisted programming for a while now and the productivity gains are real. But I keep running into the same wall: the codebases I work in were never designed for this way of working. The AI fights the architecture. The context windows fill up with legacy decisions. You spend half your time explaining the codebase to the machine instead of building.</p>
<p>Which got me thinking. What if you designed a codebase from scratch for a world where AI writes all the code?</p>
<h2>Three layers</h2>
<p>The software I want to build has three properties.</p>
<p><strong>AI-built.</strong> The human writes specifications and reviews visual output. The AI writes all the code, runs the test suite, fixes what breaks, opens a pull request. The human never reads the source. The codebase is optimized for machine comprehension: small files, strict types, explicit boundaries. Code review gets replaced by automated verification. Type checking, linting, security scanning, visual regression, performance budgets, architectural rules. If the machine can't verify it, it doesn't ship.</p>
<p><strong>AI-powered.</strong> AI capabilities are infrastructure, not features. Model routing, prompt management, cost tracking, caching, quality monitoring. Product people iterate on AI behavior through an admin interface, not through code deployments.</p>
<p><strong>AI-operated.</strong> The application monitors itself. Error tracking, anomaly detection, incident analysis. When something breaks, an agent files a bug, another agent fixes it, CI verifies the fix, and it ships. The human sees a summary in the morning.</p>
<p>These three things together create a development loop that can run without human intervention. I haven't built this yet. But I believe it's possible today, with current tools, if you design for it from the start.</p>
<h2>The context engine</h2>
<p>Here's what I think most people building AI features are missing.</p>
<p>Your AI is only as good as what it knows. And right now, most AI features know almost nothing about the user's world. They work with whatever gets typed into a prompt box, maybe the current document.</p>
<p>The real unlock is a context engine. A system that connects to everything the user works with and makes all of it available as context. When you ask the system to create a board presentation, it already knows your financials, your strategic priorities, the key updates from Slack, the metrics from your analytics. It doesn't start from zero.</p>
<p>This changes what a product even is. The editor is a commodity. The accumulated understanding of your world is the product.</p>
<h2>Agents talking to agents</h2>
<p>We build software for humans to click through graphical interfaces. I think that's about to become the minority use case.</p>
<p>Soon, most interactions with most software will be agent-to-agent. Your personal AI talks to your company tools, which talk to external services. The human sets intent and reviews outcomes.</p>
<p>Software needs to be designed for this. Two layers: a structured API for precise operations, and an intent layer where agents describe what they want and the system figures out how. The second layer is what separates software that agents can technically use from software they can use well.</p>
<h2>What changes</h2>
<p>When one person with AI can ship more in a week than a team shipped in a quarter, the bottleneck moves. It stops being about headcount or velocity. It becomes about clarity of vision, rigor of verification, and taste.</p>
<p>I find this genuinely exciting. And a little scary. The ground is shifting under everything I thought I knew about building software, and I'm curious to see where we end up.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/interactive-cheatsheet-for-tidal-cycles</id>
    <link href="https://adamrenklint.com/interactive-cheatsheet-for-tidal-cycles"/>
    <title>Interactive cheatsheet for Tidal Cycles</title>
    <updated>2026-01-27T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p><a href="https://tidalcycles.org/">Tidal Cycles</a> is a Haskell-based language for making music with code. You write patterns, transform them with functions, and out comes generative, evolving music. I've been coding music for over a decade and Tidal is one of my favorite tools, but I don't use it often enough to keep all the functions in my head. The full documentation is thorough, but sometimes you just want to look something up quickly without the surrounding context.</p>
<p>For the last decade my day job has been Clojure, and one of my go-to references is the <a href="https://cljs.info/cheatsheet/">ClojureScript cheatsheet</a> on <a href="http://cljs.info">cljs.info</a>. It's fast, scannable, and gets out of the way. I wanted something like that for Tidal.</p>
<p><a href="https://adamrenklint.github.io/tidalbits">Bits of Tidal</a> is a quick-reference cheatsheet for Tidal Cycles functions, plus a small practice companion that suggests functions to try, to help push me out of my usual patterns when I'm making music.</p>
<p>The entire thing was built with Claude Code. I didn't touch the code at all, just described features and reviewed the result.</p>
<p>Check it out at <a href="https://adamrenklint.github.io/tidalbits">adamrenklint.github.io/tidalbits</a>.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/quickblog-github-pages</id>
    <link href="https://adamrenklint.com/quickblog-github-pages"/>
    <title>Quickblog without .html extension of Github Pages</title>
    <updated>2025-03-16T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>Since rewriting my website with <a href="https://github.com/borkdude/quickblog">Quickblog</a>, one thing has bothered me: all pages are rendered to <code>page.html</code> files and linked together with the <code>.html</code> file extension in the url.</p>
<p>Being biased for making the change I want to see in the world, I decided to build it myself, but when I started to look into how to implement this feature, I came across an undocumented setting for Quickblog: <code>:page-suffix</code>.</p>
<p>If we set <code>:page-suffix</code> to an empty string, then links won't include the <code>.html</code> extension anymore. But this creates a new problem: when running <code>bb quickblog watch</code>, the local server doesn't know to rewrite <code>/page</code> to <code>/page.html</code>.</p>
<p>The solution to this was also quite simple: in <code>bb.edn</code>, I have one quickblog command for developing and another command for building the production version.</p>
<pre><code class="language-clj">{:deps {io.github.borkdude/quickblog
        {:git/sha &quot;caffe692c8d715b30c8851ab8210dbabb19a1785&quot;}}
 :tasks
 {:requires ([quickblog.cli :as cli])
  :init (def opts {:blog-title &quot;My blog title&quot;
                   :blog-description &quot;My blog description&quot;})
  quickblog {:doc &quot;Development mode. Run `bb quickblog help` for details.&quot;
             :task (cli/dispatch opts)}
  quickblog-prod {:doc &quot;Production mode. Run `bb quickblog-prod help` for details.&quot;
                  :task (cli/dispatch (assoc opts :page-suffix &quot;&quot;))}}}
</code></pre>
<p>When I'm developing and writing posts locally, I run the regular <code>bb quickblog watch</code>. In my Github action that builds and deploys the website to Github Pages, I instead use <code>bb quickblog render</code>.</p>
<p>Github Pages comes with out-of-the-box support for extension-less paths, so accessing <code>adamrenklint.com/foo</code> will actually load <code>adamrenklint.com/foo.html</code>.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/preo</id>
    <link href="https://adamrenklint.com/preo"/>
    <title>Preo, function validation in pre/post hooks with readable errors</title>
    <updated>2025-03-09T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>Validating the shape of function arguments and return value with pre/post hooks is a great feature in Clojure/Script, but to get useful context when a validation error occurs, we must manually provide context, in every <code>assert</code> in every hook. We also have the option of using <code>valid?</code> and <code>explain</code> from <code>clojure.spec.alpha</code>, but the output is not easy to quickly parse. What if we could have a tiny library to abstract the tedious ceremony for getting great errors?</p>
<p>Meet <strong>Preo</strong>, a tiny library that combines the expressive power of <code>clojure.spec</code> with the readable errors of <a href="https://github.com/bhb/expound"><code>Expound</code></a>. When I say tiny, that's not an exaggeration - the entire library is 27 lines of code. But having used an earlier version of this library in production at <a href="https://pitch.com">Pitch</a> for a couple of years, I can confidently say that not having to re-type or copy-paste the same boilerplate over and over is a huge improvement.</p>
<h2>Validating arguments</h2>
<p>Imagine we have a function that takes a string <code>s</code> and will do string-things to it. If it doesn't get a string as input, nested string-function calls will throw errors, and we'll have to traverse the stacktrace to find the point of failure.</p>
<p>If we add a pre-hook with a Preo assertion, our program will throw if an invalid argument is provided and show us a contextually rich error so we can quickly find the problem.</p>
<pre><code class="language-clj">(defn my-string-fn [s]
  {:pre [(preo.core/arg! string? s)]}
  (subs s 2))

(my-string-fn 123)

; java.lang.AssertionError: Invalid argument: s
; -- Spec failed --------------------
;
;   123
;
; should satisfy
;
;   string?
;
; -------------------------
; Detected 1 error
;
; at preo.core$throw_error_BANG_.invokeStatic (core.cljc:7)
;    preo.core$throw_error_BANG_.invoke (core.cljc:7)
;    preo.example/my-string-fn (example.cljc:0)
</code></pre>
<p>The stacktrace is truncated here for readability.</p>
<h2>Validating return value</h2>
<p>Similarly, we might want to ensure the shape of the return value.</p>
<pre><code class="language-clj">(s/def ::pos-int (s/and integer? pos?))

(defn ret-example [v]
  {:post [(p/ret! ::pos-int %)]}
  v)

(ret-example &quot;asdf&quot;)

; java.lang.AssertionError: Invalid return value
; -- Spec failed --------------------
;
;   &quot;asdf&quot;
;
; should satisfy
;
;   integer?
;
; -- Relevant specs -------
;
; :preo.example/pos-int:
; (clojure.spec.alpha/and clojure.core/integer? clojure.core/pos?)
;
; -------------------------
; Detected 1 error
;
; at preo.core$throw_error_BANG_.invokeStatic (core.cljc:7)
;    preo.core$throw_error_BANG_.invoke (core.cljc:7)
;    preo.example/ret-example (example.cljc:2)
</code></pre>
<p>Preo takes either predicate functions or keywords resolving to specs, and is written with CLJC to make it work in both Clojure and ClojureScript.</p>
<p>This library is certainly not a ground-breaking discovery, but a useful utility if you like to use pre/post hooks and are tired of manually writing assert messages with enough context.</p>
<p>The code is live on <a href="https://github.com/adamrenklint/preo">Github</a>, the package is published on <a href="https://clojars.org/com.adamrenklint/preo">Clojars</a> and I'm always eager to hear feedback or ideas. But please note: the tiny scope is a feature, not a bug, and I'm unlikely to accept any patches that increases that scope.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/simple-pseudo-random-number-generator</id>
    <link href="https://adamrenklint.com/simple-pseudo-random-number-generator"/>
    <title>Simple pseudo-random number generator</title>
    <updated>2024-08-10T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>Clojure comes with a fine set of functions for generating random numbers, but in the context of music programming, being able to seed the number generator to produce random numbers in a predictable series is critical. There are some capable libraries to solve this, but they mostly use the same interface for reading numbers (lazy sequence) and don't guarantee consistency across host platforms.</p>
<p>A recent exploration of rytmic and melodic patterns as functions of time, inspired by TidalCycles, presented the need for a pseudo-random number generator (PRNG) that takes a seed and the current time, measured on an infinite scale of &quot;cycles&quot;, to produce a value. We need to be able to retrieve a random number at any resolution of this time scale, and the result should feel random and be somewhat uniformly distributed.</p>
<h2>Intuition for randomness</h2>
<p>To get a better feeling for what a &quot;somewhat uniform&quot; distribution looks like, let's first see how Clojure's built-in random number generator performs. Below is the result of generating 1000 random numbers with <code>clojure.core/rand</code> and sorting them by the first decimal. As you can see if you click &quot;Regenerate&quot; multiple times, the ratios change a bit but always remains in the 7-13% range. And if we 10x the sample size, the ratios get closer to an even 10%.</p>
<div id="vanilla-rand"></div>
<script src="https://cdn.jsdelivr.net/npm/scittle@0.6.17/dist/scittle.js" type="application/javascript"></script>
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/scittle@0.6.17/dist/scittle.reagent.js" type="application/javascript"></script>
<script type="application/x-scittle" src="assets/prng.cljs"></script>
<h2>Our version</h2>
<p>Most examples of PRNGs that produce a series of random numbers use a method of bitshifting a continuously mutated state, or multiple. With my hard requirement of having no mutable state, making it a pure function of the <code>seed</code> and <code>time</code> parameters, I instead came up with a version that combines the two parameters and applies a few arithmetic operations to get a predictable random number.</p>
<pre><code class="language-clojure">(defn custom-rand [seed t]
  (-&gt; (inc t)
      (+ seed)
      (* 17.1737)
      (mod 10)
      (/ 10)))
</code></pre>
<p>The &quot;magic numbers&quot; here were just made up on the spot, once and never changed. Seven feels like the most uneven number below ten, so I intuitively used that a lot. The time is increased by one so that multiplication operations always have some effect even though time starts at <code>0</code>. Let's look at the result.</p>
<div id="custom-rand"></div>
<p>Quite good distribution, comparable to <code>clojure.core/rand</code> above. Performance-wise it's about 2-3x slower, which is acceptable for this exercise, but I might want to revisit that topic in the future.</p>
]]></content>
  </entry>
  <entry>
    <id>https://adamrenklint.com/new-website</id>
    <link href="https://adamrenklint.com/new-website"/>
    <title>New website</title>
    <updated>2024-08-04T00:00:00+00:00</updated>
    <content type="html"><![CDATA[<p>Built a new website using <a href="https://github.com/borkdude/quickblog">Quickblog</a> and <a href="https://neat.joeldare.com">Neat CSS</a>. Definitely liking this minimal design.</p>
<p>I wasn't able to easily move over the handful of decades old posts consisting of painful puns and outdated Javascript tricks, so I'm starting over with a blank slate.</p>
<p>While the design is minimal and Quickblog is refreshing in its lack of features and customisability, the new version is not lacking in spice. Using <a href="https://babashka.org/scittle">Scittle</a>, I'm able to sprinkle Clojure in my posts and make them interactive and stateful.</p>
<script src="https://cdn.jsdelivr.net/npm/scittle@0.6.17/dist/scittle.js" type="application/javascript"></script>
<script type="application/x-scittle">
  (set! (.-count js/window) (atom 0))
  (defn update-label []
    (let [count @(.-count js/window)]
      (set! (.-textContent (js/document.getElementById "button"))
            (str "Clicked " count " " (if (= 1 count) "time" "times")))))
  (defn handle-click []
    (swap! (.-count js/window) inc)
    (update-label))
  (set! (.-handle_click js/window) handle-click)
</script>
<button id="button" onclick="window.handle_click()">
  Clicked 0 times
</button>]]></content>
  </entry>
</feed>
