<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>en · blog.vrypan.net</title>
    <link>https://blog.vrypan.net/tags/en/</link>
    <description>en · blog.vrypan.net</description>
    <lastBuildDate>Sat, 20 Jun 2026 15:17:16 +0000</lastBuildDate>
    <generator>bckt</generator>
    <atom:link href="https://blog.vrypan.net/rss-en.xml" rel="self" type="application/rss+xml"/>
    
    <item>
      <title>The ghost girl</title>
      <link>https://blog.vrypan.net/2026/06/20/260620-the-ghost-girl/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/20/260620-the-ghost-girl/</guid>
      <pubDate>Sat, 20 Jun 2026 15:17:16 +0000</pubDate>
      <description></description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/06/20/260620-the-ghost-girl/image.jpeg">
        
	
]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/06/20/260620-the-ghost-girl/image.jpeg"
   type="image/jpeg"
   length="1367721"/>

    </item>
    
    <item>
      <title>We have to go back!</title>
      <link>https://blog.vrypan.net/2026/06/19/260619-we-have-to-go-back/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/19/260619-we-have-to-go-back/</guid>
      <pubDate>Fri, 19 Jun 2026 17:32:21 +0000</pubDate>
      <description>In 2024, Farcaster was the most decentralized it had ever been: a peer-to-peer network of hubs that were, at the protocol level, peers. My hub running on a Raspberry Pi at home, your hub on a VPS, Merkle’s hubs powering Warpcast, Neynar’s hubs powering various independent apps — ...</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/06/19/260619-we-have-to-go-back/lost.jpeg">
        
	<p>In 2024, Farcaster was the most decentralized it had ever been: a peer-to-peer network of hubs that were, at the protocol level, peers. My hub running on a Raspberry Pi at home, your hub on a VPS, Merkle’s hubs powering Warpcast, Neynar’s hubs powering various independent apps — they were all peers. Not equal, because network position, capacity, reliability, and importance mattered, but peers.</p>
<p>A year later, in spring 2025, Farcaster migrated to Snapchain.</p>
<p>Snapchain introduced globally ordered blocks, consensus, and, most importantly, higher throughput. Throughput was the weak point of the hub approach, and Snapchain fixed it in order to allow Farcaster to grow from tens of thousands of users to millions of users. But it sacrificed the one unique feature Farcaster had: decentralization.</p>
<p>The core team’s North Star was simple: grow 1000x or die. In pursuit of high growth, they introduced a number of additional client-side features: Frames and Mini Apps, wallets, and Sign in with Farcaster. What used to be a principle — that protocol changes should not be introduced unless a feature has matured — was forgotten, and protocol changes were introduced overnight to support things that looked attractive product-wise, like Farcaster Pro. Fees were reduced to practically zero, despite the original thesis that fees are the friction required to fight spam and abuse of network resources.</p>
<p>All these features made building alternative clients harder and harder, not to mention that the lines between “the protocol” and “clients” were blurred: Farcaster is not the protocol anymore; it’s <strong>the</strong> client.</p>
<p>These were good features. Fun to use and build for. But the expected growth never came, and all we are left with is a relatively small social network of nice and interesting people, operated by a company.</p>
<p>It’s a nice place to be, and it’s where I prefer to hang out, but it’s no longer something I’m passionate about. I wouldn’t wear a Farcaster T-shirt today. I wouldn’t try to recruit new users. I removed “I’m on Farcaster” from my X account.</p>
<h2>Can we go back?</h2>
<p>Which brings me to Jack Shephard’s words in the <em>Lost</em> Season 3 finale: <em><strong>We have to go back!</strong></em></p>
<p>What if Farcaster went back to a hub-based architecture: simple, peer-to-peer, truly decentralized, where it’s easy to run a peer, easy to build self-hosted bots, and easy to build a client?</p>
<p>No bells and whistles. No Mini Apps. No assumption that every client must become a wallet, browser, app host, and social feed at the same time. Strip the network back down to the basics: identity, casts, replies, follows, reactions, and low data retention that makes home hosting feasible.</p>
<p>Then we can rethink Sign in with Farcaster, long-term archiving, scaling, storage fees, app embedding, and everything else. Maybe growth will come at some point in the future, maybe not, but as long as there are a handful of people running a hub at home, the network will be there.</p>
<p>This is not 2024. We know more now. We have seen what worked and what did not. We are not after 1000x growth at any cost. We have new tools for building software, especially when the protocols involved are simple. We can do better than the last time.</p>
<p>Personally, I would be very enthusiastic about this prospect.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/06/19/260619-we-have-to-go-back/lost.jpeg"
   type="image/jpeg"
   length="260451"/>

    </item>
    
    <item>
      
      <link>https://blog.vrypan.net/2026/06/18/260619-ai-mainframe/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/18/260619-ai-mainframe/</guid>
      <pubDate>Thu, 18 Jun 2026 22:00:12 +0000</pubDate>
      <description>We are in the mainframe era of AI: A few centralized compute providers and millions of "dumb" clients connected to them.</description>
      <content:encoded><![CDATA[
	
	<p>We are in the mainframe era of AI: A few centralized compute providers and millions of &quot;dumb&quot;
clients connected to them.</p>

]]></content:encoded>

    </item>
    
    <item>
      <title>bckt v0.7.3 is out</title>
      <link>https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/</guid>
      <pubDate>Thu, 18 Jun 2026 16:28:50 +0000</pubDate>
      <description>bckt v0.7.3, my "opinionated but flexible static site generator for blogs", is out!</description>
      <content:encoded><![CDATA[
	
	<p><a href="https://github.com/vrypan/bckt">bckt</a> v0.7.3, my <em>&quot;opinionated but flexible static site generator for blogs&quot;</em>, is out!</p>
<p>The most notable change is the installation bundles come with a nice set of themes, as well as some demo content:</p>
<pre><code># Install
brew install vrypan/tap/bckt

# Create a test directory and initialize a new blog
# with the demo microblog posts and the micro theme
mkdir test &amp;&amp; cd test
bckt init --theme micro --demo microblog 

# Start the local http server to preview it
# (the static pages are in the html/ directory)
bckt dev
</code></pre>
<p>Use <code>--demo microblog</code> to test how it looks with short, titleless posts and
<code>--demo articles</code> to see a version with longer articles, closer to a typical
blog post. But all themes will work nicely with both types of content.</p>
<hr />
<p>You will probably want to use an AI agent to create your own theme. There is
an <code>AGENTS.md</code> that will make this very easy.</p>
<p>For example, let's use <a href="https://mxb.dev/">Max Böck</a>'s blog, which has a really nice design.</p>
<p><code>cd</code> in your blog directory and try prompt like this:</p>
<pre><code>- Read https://github.com/vrypan/bckt/blob/main/themes/AGENTS.md
- Check themes/* to see how the existing themes are structured.
- create a theme inspired by https://mxb.dev/blog/ 
</code></pre>
<p><figure><img src="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/mxbdev-inspired.png" alt="" title="Theme inspired by mbx.dev/blog/. I suggest you visit it to see the original." /><figcaption>Theme inspired by mbx.dev/blog/. I suggest you visit it to see the original.</figcaption></figure></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/mxbdev-inspired.png"
   type="image/png"
   length="308328"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/og.png"
   type="image/png"
   length="490020"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-bckt3.png"
   type="image/png"
   length="338966"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-micro-dark.png"
   type="image/png"
   length="385628"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-micro-light.png"
   type="image/png"
   length="384084"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-microx-dark.png"
   type="image/png"
   length="414777"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-microx-light.png"
   type="image/png"
   length="413808"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-modern.png"
   type="image/png"
   length="360507"/>

   <enclosure url="https://blog.vrypan.net/2026/06/18/260618-bckt-073-is-out/theme-rntz.png"
   type="image/png"
   length="463988"/>

    </item>
    
    <item>
      
      <link>https://blog.vrypan.net/2026/06/17/260618-football/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/17/260618-football/</guid>
      <pubDate>Wed, 17 Jun 2026 21:30:25 +0000</pubDate>
      <description>Football may be the last mass spectacle that still resists instant gratification.</description>
      <content:encoded><![CDATA[
	
	<p>Football may be the last mass spectacle that still resists instant gratification.</p>

]]></content:encoded>

    </item>
    
    <item>
      <title>A forgotten terminal trick: the host-writable status line.</title>
      <link>https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/</guid>
      <pubDate>Sat, 13 Jun 2026 04:59:45 +0000</pubDate>
      <description>The VT102 (1978) and VT220 (1983) had the familiar 24-line terminal screen . This the reason your terminal defaults to 80×24, or 132×24. The VT320 (1987) kept a 24-line main display for compatibility, but added something extra: a 25th line at the bottom, reserved for status infor...</description>
      <content:encoded><![CDATA[
	
	<p>The VT102 (1978) and VT220 (1983) had the familiar 24-line terminal screen <sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup>. This the reason your terminal defaults to 80×24, or 132×24. The VT320 (1987) kept a 24-line main display for compatibility, but added something extra: a 25th line at the bottom, reserved for status information.</p>
<p>That extra line could be hidden, used by the terminal itself, or made writable by the host. In its normal “indicator” mode, the terminal used it for local state: cursor position, printer status, modem status, and similar information. But in host-writable mode, software on the host side of the terminal connection could write directly to that line. <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup></p>
<p>The two relevant control sequences are <code>DECSSDT</code> and <code>DECSASD</code>. <sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>3</a></sup></p>
<pre lang="sh"><code># Make the status line host-writable
printf '\e[2$~'

# Send subsequent output to the status line
printf '\e[1$}Build running…'

# Return subsequent output to the main display
printf '\e[0$}'
</code></pre>
<p><code>DECSSDT</code> selects the status-display type:</p>
<pre lang="text"><code>CSI 0 $ ~   no status line
CSI 1 $ ~   indicator status line
CSI 2 $ ~   host-writable status line
</code></pre>
<p><code>DECSASD</code> selects which display receives subsequent characters:</p>
<pre lang="text"><code>CSI 0 $ }   main display
CSI 1 $ }   status line
</code></pre>
<p>It's a surprisingly elegant primitive. A program could use it for progress, mode, host name, current job, debug state, deployment environment, or a persistent “you are in production” warning, without stealing a row from the application, rewriting the prompt, or relying on a terminal multiplexer.</p>
<p><figure><img src="https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/screenshot.png" alt="" /></figure></p>
<p><em>I wasn't able to find a good historical screenshot of a real application writing to the host status line, but you can see it displaying status info in this Capo's Tech video <sup class="footnote-ref"><a href="#fn-4" id="fnref-4" data-footnote-ref>4</a></sup> <sup class="footnote-ref"><a href="#fn-5" id="fnref-5" data-footnote-ref>5</a></sup></em></p>
<h2>Can we bring it back?</h2>
<p>The idea feels familiar even if these particular CSI sequences are rarely supported today. We have reinvented the same feature in tmux status lines, Zellij bars, and prompt frameworks because the shape makes sense.</p>
<p>But those are all tool-specific solutions.</p>
<p>It would be great to see modern terminals support <code>DECSSDT</code>/<code>DECSASD</code> again. I think many apps like starship, build environments, package managers and so on would take advantage of the feature if terminal emulators supported it.</p>
<hr />
<p>Image sources:</p>
<ul>
<li>Jason Scott: <a href="https://commons.wikimedia.org/w/index.php?curid=29457452">https://commons.wikimedia.org/w/index.php?curid=29457452</a></li>
<li>Tom Page: <a href="https://commons.wikimedia.org/w/index.php?curid=98843032">https://commons.wikimedia.org/w/index.php?curid=98843032</a></li>
<li>Capo’s Tech: <a href="https://youtu.be/EjJTog15Izs?si=aotLJ8Sb1QGcx2_H&amp;t=426">https://youtu.be/EjJTog15Izs?si=aotLJ8Sb1QGcx2_H&amp;t=426</a></li>
<li>LGR: <a href="https://www.youtube.com/watch?v=RuZUPpmXfT0">https://www.youtube.com/watch?v=RuZUPpmXfT0</a></li>
</ul>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>Ken Shirriff has a great deep dive on this: <a href="https://www.righto.com/2019/11/ibm-sonic-delay-lines-and-history-of.html">IBM, sonic delay lines, and the history of the 80×24 display</a>. <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p>The VT320 introduced a physical 25th line reserved for status use. Normally, the main display remained the familiar 24-line terminal area, preserving compatibility with VT100/VT220-era applications. Later VT420 documentation makes the behavior explicit: when the status line is disabled, that reserved line can become an additional user-window line for normal display data. <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-3">
<p><a href="https://www.vt100.net/docs/vt320-uu/appendixe.html">VT320 Programming Summary</a> <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
<li id="fn-4">
<p><a href="https://youtu.be/EjJTog15Izs?si=aotLJ8Sb1QGcx2_H&amp;t=426">https://youtu.be/EjJTog15Izs?si=aotLJ8Sb1QGcx2_H&amp;t=426</a> <a href="#fnref-4" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="4" aria-label="Back to reference 4">↩</a></p>
</li>
<li id="fn-5">
<p>If someone has a functioning VT320, VT330, VT340, or later DEC terminal and can capture better shots, I’d love to add them to the post. <a href="#fnref-5" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="5" aria-label="Back to reference 5">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/1280px-DEC_VT100_terminal.jpg"
   type="image/jpeg"
   length="254768"/>

   <enclosure url="https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/1280px-DEC_VT220_terminal.jpg"
   type="image/jpeg"
   length="384530"/>

   <enclosure url="https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/og.png"
   type="image/png"
   length="103388"/>

   <enclosure url="https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/screenshot.png"
   type="image/png"
   length="4566630"/>

   <enclosure url="https://blog.vrypan.net/2026/06/13/260613-vt-host-writable-status-line/vt320.png"
   type="image/png"
   length="3178813"/>

    </item>
    
    <item>
      <title>Pet project: smart clock</title>
      <link>https://blog.vrypan.net/2026/06/01/pet-project-smart-clock/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/06/01/pet-project-smart-clock/</guid>
      <pubDate>Mon, 01 Jun 2026 19:43:27 +0000</pubDate>
      <description>I'm building a smart clock for my daughter. I don't want it to be a cool geek project, showing off all the things one could do with a small computer and a screen. I want it to have character and personality, with small little features built in, things that she will like.</description>
      <content:encoded><![CDATA[
	
	<p>I'm building a smart clock for my daughter. I don't want it to be a cool geek project, showing off all the things one could do with a small computer and a screen.
I want it to have character and personality, with small little features built in, things that she will like.</p>
<p>I'm using a Raspberry Pi 3B with a UnicornHD HAT. Both outdated, but fine for what I'm building, and I like the limitations they impose.</p>
<p>The clock works. The color scheme changes from bright white-ish at noon to dim blue at night. The location is determined by looking up the gateway's IP. Then, based on lat,lon and time, it calculates the position of the sun, and adjusts the color/brightness.</p>
<p>There is also an indicator on the right, showing day/night/dawn/dusk hours which also adjusts automatically.</p>
<p>It can rotate, but I'll have to connect a gyrometer for this to work automatically. Todo.</p>
<p>Works as an AirPlay receiver using SharePlay, and will display artist/title when a track starts. Will add Spotify support too.</p>
<p>I asked codex to parse all my blog posts and get quotes that I have or I could have said, and I'll display them on random times. Needs work, and more personalization, these are intended to be from me to her. Will add some internal jokes, things we say to each other, and may also make some depend on day/time/season/weather. At first it looked like a cool idea, not sure if it will make it to the final version.</p>
<p>I don't want to rely on cloud services, this has to be self-sufficient. I'm currently looking up the network gateway's IP to determine the location using ipinfo.io
but I'll find a way to either manually input it, or add a GPS module or something.</p>
<hr />
<p>While doing various experiments, I got down the rabbithole of music boxes. It would be nice if it also worked as a music box, right?</p>
<p>And I found this amazing project I had no idea about, called <a href="https://murobox.com/en/">Muro Box</a>. Wow, so cool and so beautiful.
This is the type of smart devices I would love to build some day, not consumer electronics, but things that are hand crafted, with character andattention to detail and beauty.</p>
<p><figure><img src="https://blog.vrypan.net/2026/06/01/pet-project-smart-clock/murobox.jpg" alt="Muro Box" /></figure></p>
<blockquote>
<p>Muro Box lets you compose, play, and schedule your favorite melodies. With MIDI control and a patented mechanical design, a single music box can now perform unlimited custom songs—not just short loops.</p>
</blockquote>
<hr />
<p>Anyway, with this and that, I spent the last two days building a music box player. It's a program that will read a MIDI file, and play it as if it were
a real music box, with a drum and a comb. I knew nothing about MIDI and sound engineering, but a learned quite a bit, and the result is not bad at all.
I'll put it on GitHub once it's a bit more polished.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/06/01/pet-project-smart-clock/image1.jpeg"
   type="image/jpeg"
   length="88463"/>

   <enclosure url="https://blog.vrypan.net/2026/06/01/pet-project-smart-clock/image2.jpeg"
   type="image/jpeg"
   length="44496"/>

   <enclosure url="https://blog.vrypan.net/2026/06/01/pet-project-smart-clock/murobox.jpg"
   type="image/jpeg"
   length="24832"/>

    </item>
    
    <item>
      <title>My Pi Zero desk clock</title>
      <link>https://blog.vrypan.net/2026/05/22/my-pi-zero-desk-clock/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/05/22/my-pi-zero-desk-clock/</guid>
      <pubDate>Fri, 22 May 2026 20:14:59 +0000</pubDate>
      <description>Years ago, I built a digital desk clock using a Pi Zero and a Micro Dot pHAT. Probably an overkill to use a whole computer as a clock, but it has turned out to be very convenient, it’s easy to read day and night, and I like the style.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/05/22/my-pi-zero-desk-clock/screenshot.png">
        
	<p>Years ago, I built a digital desk clock using a Pi Zero and a <a href="https://shop.pimoroni.com/products/microdot-phat">Micro Dot pHAT</a>. Probably an overkill to use a whole computer as a clock, but it has turned out to be very convenient, it’s easy to read day and night, and I like the style.</p>
<p>Lately, it started freezing. No idea why, my guess was the OS needed to be updated, or even better re-installed —I don’t have a clear log of what this Pi Zero has been through all these years, but for sure it was also used as a DNS (pi-hole) at some point, and as a tailscale gateway at some other.</p>
<p>The problem is my clock was a Python script using a <a href="https://github.com/pimoroni/microdot-phat">library</a> that has not been updated for at least 4 years. Would it work with a much newer version of Pi OS?</p>
<p>It did not. I could not even install it.</p>
<p>So, I cloned it, and used Claude to port it to Zig. I picked Zig because the resulting binaries are small, and I can also cross-compile on my MacBook Pro (waiting for Pi Zero to compile would not be fun). It took me an afternoon, a couple of manual interventions, and <a href="https://github.com/vrypan/microdot-phat-zig">I had my Zig port</a>. The examples compiled, and run perfectly on the latest Pi OS (32-bit).</p>
<p>And since I’m not the one writing the code, why not add some flavor? Let’s have the digits scroll up when they change.</p>
<p>Not bad for a project that took an afternoon. I love it how I can make and fix little things that wouldn’t be worth the time and effort without AI-assited coding.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/05/22/my-pi-zero-desk-clock/clock.mp4"
   type="video/mp4"
   length="301552"/>

   <enclosure url="https://blog.vrypan.net/2026/05/22/my-pi-zero-desk-clock/screenshot.png"
   type="image/png"
   length="291577"/>

    </item>
    
    <item>
      <title>The Cathedral, the Bazaar and the Kitchen</title>
      <link>https://blog.vrypan.net/2026/05/11/the-cathedral-the-bazaar-and-the-kitchen/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/05/11/the-cathedral-the-bazaar-and-the-kitchen/</guid>
      <pubDate>Mon, 11 May 2026 20:36:12 +0000</pubDate>
      <description>Eric Raymond’s “The Cathedral and the Bazaar” described two fundamentally different ways of building software. The Cathedral represented centralized, carefully planned development directed by a small group of maintainers. The Bazaar represented open collaboration: large communiti...</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/05/11/the-cathedral-the-bazaar-and-the-kitchen/image.png">
        
	<p>Eric Raymond’s “The Cathedral and the Bazaar”<sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup> described two fundamentally different ways of building software. The Cathedral represented centralized, carefully planned development directed by a small group of maintainers. The Bazaar represented open collaboration: large communities, public iteration, distributed labor, and software evolving through many contributors.</p>
<p>For decades, the Bazaar became the dominant cultural myth of open source. Public repositories, pull requests, and community participation were not just practical tools, but moral ideals. Good software was expected to emerge from openness and collective effort.</p>
<hr />
<p>AI-assisted software development is changing the economics and the ergonomics behind that model. Implementation becomes cheap, and coordination becomes expensive. A single developer equipped with modern tools can now produce systems that previously required teams.</p>
<p>At the same time, software is becoming increasingly personalized: tailored to one person’s workflow, infrastructure, preferences, and habits. Instead of building generalized tools for the widest possible audience, developers increasingly build software that fits their own environment perfectly. Others may still read the code, fork it, or borrow ideas from it, but local modification often becomes cheaper than upstream coordination.</p>
<p><strong>The new model is a kitchen.</strong></p>
<p>Every kitchen evolves around the habits of its cook. Tools sit where they are convenient. Ingredients are substituted freely. Recipes are modified on instinct. Two people may start from the same dish and end up with completely different results.</p>
<p>Unlike the Bazaar, a kitchen is deeply personal. Recipes are shared freely, but kitchens rarely converge into a universal standard. Visitors may admire another cook’s techniques, yet still return home and prepare the dish their own way. In the Kitchen model, open source becomes less like public infrastructure and more like published craft: software as personal utility, openly visible, endlessly adaptable, and increasingly authored by individuals rather than communities.</p>
<hr />
<p>In the Bazaar model, openness was mainly a way to coordinate people. You opened the codebase to attract contributors, spread work across many developers, avoid duplicated effort, and slowly build shared infrastructure.</p>
<p><strong>In the Kitchen model, openness serves a different purpose.</strong> It provides visibility, learnability, and independence. Value shifts from <em>“others can help build this”</em> to <em>“others can understand, adapt, and reclaim this.”</em></p>
<p>Source code starts to resemble recipes more than public construction projects. Most people do not submit patches to a cookbook, yet recipes remain enormously valuable because they transfer techniques, preserve knowledge, and provide foundations others can adapt to their own tastes and environments. The code is open not necessarily so everyone can co-author it, but so anyone can study it, modify it, and make it their own.</p>
<p>This also changes the meaning of forks. In the Bazaar, forks were often viewed as failures of governance or coordination. In the Kitchen, forks become normal and healthy:</p>
<ul>
<li>“I adapted this for my setup”</li>
<li>“I removed features I don’t need”</li>
<li>“I rewrote this around my workflow”</li>
</ul>
<p>Forking becomes analogous to modifying a recipe<sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup> at home.</p>
<p>Software evolves through local adaptation rather than centralized consensus. A developer will remove features, rewrite workflows, or optimize entirely around their own infrastructure because doing so is now cheaper than negotiating a generalized solution acceptable to everyone.</p>
<p>This model still depends on public circulation of ideas. Even if code contributions decline, people still copy ideas from each other constantly through imitation, recombination, critique, and inspiration.</p>
<p>Much of programming history already worked this way:</p>
<ul>
<li>Unix customization culture where ingredients were expected to be mixed in different ways</li>
<li>shell workflows and personal scripts</li>
<li>dotfiles designed to show others how a system is configured but rarely adopted one-to-one</li>
</ul>
<p>These are often highly personal systems shared publicly, not collaboratively engineered products.</p>
<p><strong>Open source remains essential because it preserves agency</strong>: the ability to inspect, repair, continue, and reshape software independently of its original author. The result is a world where software is increasingly personal, but where ideas, techniques, and tools still circulate freely between individuals, much like recipes passed from kitchen to kitchen.</p>
<hr />
<p><strong>Update (15-May-2026)</strong>: Other people have described the same or a similar mental model:</p>
<p>Drew Breunig calls it &quot;the Winchester Mystery House&quot;:</p>
<blockquote>
<p>The ideas crystallized in &quot;The Cathedral and the Bazaar&quot; helped kick off a quarter-century of open source innovation and dominance.<br />
But just as the internet made communication cheap and birthed the Bazaar, AI is making code cheap and kicking off a new era filled with idiosyncratic, sprawling, cobbled-together software.<br />
Meet the third model: the Winchester Mystery House.</p>
<p>—<em>The Cathedral, the Bazaar, and the Winchester Mystery House</em><sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>3</a></sup></p>
</blockquote>
<p>And Thomas H. Ptacek, calls it &quot;the Emacsification of Software&quot;:</p>
<blockquote>
<p>First, it's personal software. Most of it will be useful only to its creator, and then forgotten,
just like the dozens of obsolete little elisp programs littering my .emacs. Personal software defines
the ethos of Emacs, which was carefully designed over decades to nurture these kinds of tools.
&quot;Emacsification&quot; clocks that everything now works this way, not just baroque text editors.</p>
<p>—<em>The Emacsification of Software</em><sup class="footnote-ref"><a href="#fn-4" id="fnref-4" data-footnote-ref>4</a></sup></p>
</blockquote>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>Eric S. Raymond, <em>The Cathedral and the Bazaar</em> (1997), <a href="https://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar">https://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar</a> <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p>Side note: There is rarely a single canonical version of a dish. The same recipe evolves into countless variations shaped by region, available ingredients, habits, and personal taste. Instead of converging into one standard, we distinguish them by origin or authorship: <em>à la provençale</em>, <em>à la milanaise</em>, <em>à la grandma</em>, <em>à la Jacques Pépin</em>. The variation itself becomes part of the identity of the dish. GNU grep and BSD grep were different variations of the same tool, but these were more like publisher or distribution variations. The Kitchen model pushes personalization much further, toward software shaped directly around the habits and preferences of individual developers. <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-3">
<p><a href="https://www.dbreunig.com/2026/03/26/winchester-mystery-house.html">The Cathedral, the Bazaar, and the Winchester Mystery House</a> <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
<li id="fn-4">
<p><a href="https://sockpuppet.org/blog/2026/05/12/emacsification/">The Emacsification of Software</a> <a href="#fnref-4" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="4" aria-label="Back to reference 4">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/05/11/the-cathedral-the-bazaar-and-the-kitchen/image.png"
   type="image/png"
   length="3511829"/>

    </item>
    
    <item>
      <title>shg, the SHell Guard</title>
      <link>https://blog.vrypan.net/2026/05/09/shg-the-shell-guard/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/05/09/shg-the-shell-guard/</guid>
      <pubDate>Sat, 09 May 2026 09:38:07 +0000</pubDate>
      <description>If you spend as much time as I do in the terminal, you probably depend on your shell history too. Being able to repeat a complex command that you remember you typed a month ago, is extremely valuable —no wonder why I’ve set HISTSIZE=10000.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/05/09/shg-the-shell-guard/screenshot.png">
        
	<p>If you spend as much time as I do in the terminal, you probably depend on your shell history too.
Being able to repeat a complex command that you remember you typed a month ago, is extremely
valuable —no wonder why I’ve set <code>HISTSIZE=10000</code>.</p>
<p>While it is convenient to use your shell history as part of your long term memory, the downside is things
that shouldn’t be there, end up there: A command you prepended with <code>API_KEY=...</code>, a quick and dirty
<code>curl --user &quot;name:password&quot;</code>, a <code>PGPASSWORD=... psql</code>, an <code>ALTER USER USER() IDENTIFIED BY ...</code>,
and so on. And they are all probably saved in shell or app history file.</p>
<p><strong>This is not good, obviously.</strong> Credentials should not be saved in places where a malicious
program can just read them, and they should not be preserved in backups.</p>
<p>That’s why I built <a href="https://github.com/vrypan/shg"><code>shg</code> (short for <em>SHell Guard</em>)</a>, a small program
that scans my shell history (and other history files) for entries that look like API keys, passwords,
bearer tokens, credential URLs, and private keys and alerts me.</p>
<p>I’ve set it up to do <a href="https://github.com/vrypan/shg/blob/main/INTEGRATIONS.md#shg-integrations">a quick scan when I start a new shell</a>
and (I think this is the coolest part) also check every command I enter in zsh and
<a href="https://github.com/vrypan/shg/blob/main/INTEGRATIONS.md#zsh-intercept-history-before-it-is-saved">catch secrets before they ever land in <code>~/.zsh_history</code></a>.</p>
<hr />
<p>Some tips:</p>
<ul>
<li>run <code>shg-config discover</code> to find and configure history files that are not part of the default scan list.</li>
<li>you can adjust the output and the severity level using <code>--level</code>, <code>--one-line</code>, <code>--json</code> and other options. Check <code>shg scan --help</code> for more details.</li>
<li>If you keep getting reports for entries that you don't mind, add them to <code>~/.config/shg/ignore.local.shg</code>. (See <a href="https://github.com/vrypan/shg/tree/main/src/defaults">the default ignore file</a> here).</li>
</ul>
<hr />
<p>If you use <code>shg</code> and you like it, <a href="https://github.com/vrypan/shg">give it a star on GitHub</a>! 🙏</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/05/09/shg-the-shell-guard/screenshot.png"
   type="image/png"
   length="143787"/>

    </item>
    
    <item>
      <title>A library of agent-friendly specs</title>
      <link>https://blog.vrypan.net/2026/04/30/a-library-of-agent-friendly-specs/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/04/30/a-library-of-agent-friendly-specs/</guid>
      <pubDate>Thu, 30 Apr 2026 17:15:06 +0000</pubDate>
      <description>Recently, I've been trying to shape the cli arguments of a tool I'm building in Zig to fit zli and zig-cli.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/04/30/a-library-of-agent-friendly-specs/screenshot.png">
        
	<p>Recently, I've been trying to shape the cli arguments of a tool I'm building in Zig to fit <code>zli</code> and <code>zig-cli</code>.</p>
<p>It's not the first time. <code>cobra</code> has its own opinions in Go, <code>clap</code> in Rust, <code>docopt</code> in Python, and so on.</p>
<p>One library doesn't support repeated arguments.<br />
Another doesn't allow ordering the args alphabetically in help.<br />
This one doesn't support arguments with optional values.<br />
That one has a small UI bug.<br />
Another won't fold long descriptions.</p>
<p>I kept adding small hacks to bring the implementation closer to what I had in mind, but a) it was
not 100% there, and b) it felt like a hack.</p>
<p>Writing a cli parser is not rocket science. A coding agent like codex or claude can definitely do it,
as long as you provide it with clear specs. Which is what I did, since I already had a lot of boilerplate
code.</p>
<p>Twenty minutes later, everything works exactly the way I want it to work, and now I can tweak it
at will, and re-implement it in the next project, regardless of the language used.</p>
<hr />
<h2>A library of agent specs</h2>
<p>Instead of rediscovering the requirements every time, I put them down in a form that AI agents can use.</p>
<p>That's the idea behind <strong><a href="https://github.com/vrypan/agent-specs">github.com/vrypan/agent-specs</a></strong>. It will
probably become a small collection of specifications designed to be used by agents.</p>
<p>One can think of it as a higher-level code library. Instead of the language-level
import/include/use, you have a spec for an agent.</p>
<pre><code>&gt; Implement cli arguments and options according to specs/cli/CLI.md.
</code></pre>
<p>Each section of <a href="https://github.com/vrypan/agent-specs/blob/main/specs/cli/CLI.md">CLI.md</a>
has an identifier, like <code>CMD-SUBCOMMANDS</code>, <code>FLAGS-SHORT-VALUES</code> and <code>OPT-COLOR</code>.
This makes it easy to tell the agent, use this, don't implement this, override that. There are
also test cases, to help the agent test the implementation.</p>
<p>So, you could also ask something like this</p>
<pre><code>&gt; Use specs/cli/CLI.md as the CLI parser specification.
Implement all required sections.
Do not implement OPT-COLOR.
Translate specs/cli/tests.yaml into automated tests.
Report any deviations.
</code></pre>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/04/30/a-library-of-agent-friendly-specs/screenshot.png"
   type="image/png"
   length="82419"/>

    </item>
    
    <item>
      <title>Down the RNG rabbit hole - Part II</title>
      <link>https://blog.vrypan.net/2026/01/01/down-the-rng-rabbit-hole-part-ii/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2026/01/01/down-the-rng-rabbit-hole-part-ii/</guid>
      <pubDate>Thu, 01 Jan 2026 20:46:44 +0000</pubDate>
      <description>So, Rule30RND was ok as a fun experiment, but not a PRNG that someone could take seriously.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2026/01/01/down-the-rng-rabbit-hole-part-ii/r30r2.png">
        
	<p>So, <a href="/2025/12/30/down-the-rng-rabbit-hole/">Rule30RND was ok as a fun experiment</a>, but not a PRNG that someone could take seriously.</p>
<p>I kept tinkering, as if I was playing a game: change this and that, run the tests, check my score.</p>
<p><em>Side note: after I published the last post, I realized that my test scripts had fundamental flaws, like adding text headers in the randomly generated bytes.</em></p>
<h2>Radius-2</h2>
<p>No matter how hard I tried, it was obvious that a Rule 30-based algorithm would not pass BigCrush unless I changed it so much that would become something else with a sprinkle of CA.</p>
<p>Now, Rule 30 works like this: If <code>C</code> is our bit, <code>L</code> is the one on its left and <code>R</code> the one on its right:<br />
<code>new_bit = L XOR (C OR R)</code></p>
<p>That’s a &quot;radius-1 CA&quot;. What if I tried with a radius-2 CA, that uses two bits on the left and two on the right?</p>
<p>Unfortunately, there is much less literature for radius-2 than radius-1 CAs. After some search that did not return a documented good candidate for what I wanted to build, and a few failed experiments, I decided to extend Rule 30 in a “symmetric” way.</p>
<p><code>new_bit = (L2 XOR L1) XOR (C OR (R1 OR R2))</code></p>
<p>This gave significantly better results.</p>
<p>Not exceptional. The new algorithm failed 5/15 SmallCrush tests (Gap, SimpPoker, CouponCollector, WeightDistrib, HammingIndep).</p>
<p>But these are the tests I might be able to fix with a diffusion function.</p>
<h2>Searching for a diffusion fucntion</h2>
<p>I wanted a diffusion function, so I let Claude test 7 different functions, run the tests, collect the results, and let me know when it was done.</p>
<table>
<thead>
<tr>
<th>Mixing/Diffusion Approach</th>
<th>SmallCrush</th>
<th>Performance vs math/rand</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rotation (5,14,27)</td>
<td>12/15</td>
<td>1.08×</td>
<td>❌</td>
</tr>
<tr>
<td>5 XOR Rotations</td>
<td>13/15</td>
<td>0.94×</td>
<td>❌</td>
</tr>
<tr>
<td>xoshiro256++ Style</td>
<td>11/15</td>
<td>1.13×</td>
<td>❌</td>
</tr>
<tr>
<td>MurmurHash</td>
<td><strong>15/15</strong></td>
<td>0.95×</td>
<td>✅</td>
</tr>
<tr>
<td>SplitMix64</td>
<td><strong>15/15</strong></td>
<td>0.93×</td>
<td>✅</td>
</tr>
<tr>
<td><strong>Hybrid</strong></td>
<td><strong>15/15</strong></td>
<td><strong>1.03×</strong></td>
<td>✅</td>
</tr>
<tr>
<td>Per-Word Varying</td>
<td><strong>15/15</strong></td>
<td>0.90×</td>
<td>✅</td>
</tr>
</tbody>
</table>
<p>The winner was the “Hybrid” approach that combines rotation, multiplication by the golden ratio, and shift-XOR:</p>
<pre lang="golang"><code>func mix(x uint64) uint64 {
    x ^= bits.RotateLeft64(x, 13)
    x *= 0x9e3779b97f4a7c15  // Golden ratio constant
    x ^= x &gt;&gt; 27
    return x
}
</code></pre>
<p>SmallCrush is the first step, but I needed it to pass BigCrush.</p>
<p>And, YES! <strong>My rule-30-radius-2-diffused algo scored 160/160 on BigCrush</strong> for the first time!</p>
<h2>Staying true</h2>
<p>Now, this worked, but <strong>it was also cheating</strong>: I applied <code>mix()</code> to every state evolution: <code>s1, s2=mix(rule30(s1)), s3=mix(rule30(s2)), ...</code>, so this was no longer a CA algorithm.</p>
<p>What if I applied <code>mix()</code> only to the output? I.e. keep a pure Rule 30, radius-2 algorithm that generates states <code>s1, s2, ...</code>, but return <code>mix(s1), mix(s2), ...</code>. Would this work?</p>
<p><strong>IT WORKED!</strong> <strong>IT WORKED!</strong></p>
<p>And it was also <strong>6% faster</strong>.</p>
<h2>I present you “R30R2”</h2>
<p>Along the way, I fixed some annoying Makefile issues, optimized how <code>Read()</code> reads data from the state, and tweaked a few things here and there.</p>
<p>I was ready to release it, but when “Rule 30” is mentioned in literature, it means a radius-1 CA.</p>
<p>I decided to rename the project, the documentation, the function names, etc. And it's name is... <strong>R30R2</strong>.</p>
<blockquote>
<p><strong>R30R2 is a radius-2 Rule 30-based PRNG with a diffusion function applied on output. It scores 160/160 on BigCrush, and is 2× faster than <code>math/rand/v2</code>.</strong></p>
<p>You can find it at <a href="https://github.com/vrypan/r30r2/">https://github.com/vrypan/r30r2/</a></p>
</blockquote>
<table>
<thead>
<tr>
<th>RNG</th>
<th>BigCrush Score</th>
<th>Performance vs math/rand</th>
</tr>
</thead>
<tbody>
<tr>
<td>math/rand</td>
<td>159/160</td>
<td>1.00× (baseline)</td>
</tr>
<tr>
<td>math/rand/v2</td>
<td>160/160 ✓</td>
<td>0.56×</td>
</tr>
<tr>
<td><strong>Rule 30</strong></td>
<td><strong>160/160</strong> ✓</td>
<td><strong>1.03×</strong></td>
</tr>
</tbody>
</table>
<h2>🎉🍾🍻</h2>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2026/01/01/down-the-rng-rabbit-hole-part-ii/r30r2.png"
   type="image/png"
   length="190176"/>

    </item>
    
    <item>
      <title>Down the RNG rabbit hole</title>
      <link>https://blog.vrypan.net/2025/12/30/down-the-rng-rabbit-hole/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/12/30/down-the-rng-rabbit-hole/</guid>
      <pubDate>Tue, 30 Dec 2025 22:06:33 +0000</pubDate>
      <description>In my last post, I described how I started from beautiful images generated by "turmites" and ended up with one that looked, and in many aspects felt, random.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/12/30/down-the-rng-rabbit-hole/image.png">
        
	<p><a href="/2025/12/28/playing-with-turmites-better-than-crypto-rand/">In my last post</a>, I described how I started from beautiful images generated by &quot;turmites&quot; and ended up with one that looked, and in many aspects felt, random.</p>
<p>I knew my approach was amateurish. After all, I <strong>am</strong> an amateur when it comes to information entropy, predictability, statistical analysis, and random number generators (RNGs). But I wanted to learn more and explore the idea further.</p>
<p>So my first attempt was to write a pseudo-random number generator (PRNG) based on my LLLR turmite: if I let the turmite run enough iterations on an NxN grid using 4 colors, the result is NxNx2 bits.</p>
<p>With a 64x64 grid, I’d get 8,192 bits, or 1,024 bytes. Are they <em>random enough</em>? How do I measure that?</p>
<p>I learned about tests used to identify structural weaknesses in PRNGs, like SmallCrush and BigCrush.</p>
<p>Yes (as you may have expected), my &quot;turmite RNG&quot; failed miserably, even on the simplest statistical tests like Chi-Square. It was also orders of magnitude slower than anything else out there.</p>
<hr />
<p>Still, my intuition told me there must be some way to build a decent RNG using cellular automata.</p>
<p>I found Stephen Wolfram’s &quot;Rule 30&quot;<sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup>. It’s a very simple, 1D cellular automaton, <em>&quot;displaying aperiodic, chaotic behaviour&quot;</em>.
And Wolfram used it as a PRNG in Mathematica.</p>
<p>Now we're talking.</p>
<p>Arrogantly, I built my own implementation using my own assumptions and preferences, without looking into how others used Rule 30 for PRNG purposes —which turned out to be a good thing, I think.</p>
<p>In most cases, cellular automata &quot;live&quot; on infinite spaces, like plains and lines, but in my previous work with turmites, I liked how they behaved on toroidal spaces. So I used a circular 256-bit stripe, and instead of using just the middle bits of consecutive steps as the RNG output, I used the whole 256-bit space. (That’s a 256× speed improvement over the typical use of Rule 30 as an RNG!)</p>
<p>And it looked good. Performance was excellent because I could fit the entire state in 4 uint64 words and compute the next state using basic binary operations on each word.</p>
<p>I even claimed 4x speed improvements over <code>math/rand</code>!</p>
<p>Slow down, cowboy.</p>
<p>People were kind to point out<sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup> that the tests I used did not compare apples to apples.
And as I searched more, I learned there's a lot to fix and improve.</p>
<hr />
<p>Long story short, two days later I had a decent PRNG that is comparable to, and in some cases better than, the standard pseudo-random number generators used by Golang.</p>
<p>I even modified the algorithm further, to improve statistical distribution: after each step, I apply XOR rotation mixing to each word, which is not part of the original Rule 30 algorithm.</p>
<p><a href="https://github.com/vrypan/rule30rnd">Rule30RND</a> is a drop-in replacement for <code>math/rand</code> and <code>math/rand/v2</code>, with a very small footprint (state and manipulation require just 40 bytes of memory), comparable statistical qualities, and is 30%–60% faster.</p>
<p>Rule30RND generates reproducible sequences (depending on the seed), which may sound like a drawback for an RNG, but it’s actually useful in many cases where a PRNG is preferred over a CSPRNG (Cryptographically Secure Pseudo-Random Number Generator). Those cases usually involve generating large, statistically unpredictable data sets used for simulations or testing.</p>
<p><strong>Throughput Comparison, relative to math/rand</strong></p>
<table>
<thead>
<tr>
<th>Algorithm</th>
<th>Read() 32KB</th>
<th>Read() 1KB</th>
<th>Uint64()</th>
</tr>
</thead>
<tbody>
<tr>
<td>MathRand</td>
<td>1.00x</td>
<td>1.00x</td>
<td>1.00x</td>
</tr>
<tr>
<td>MathRandV2</td>
<td>1.69x</td>
<td>1.63x</td>
<td>0.58x</td>
</tr>
<tr>
<td><strong>Rule30</strong></td>
<td><strong>5.47x</strong></td>
<td><strong>5.13x</strong></td>
<td><strong>1.39x</strong></td>
</tr>
<tr>
<td>CryptoRand</td>
<td>3.11x</td>
<td>1.75x</td>
<td>0.03x</td>
</tr>
</tbody>
</table>
<p><strong>Rule30RND Basic Tests (ent)</strong></p>
<table>
<thead>
<tr>
<th>Test</th>
<th>Result</th>
<th>Expected</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Entropy</td>
<td>7.999982 bits/byte</td>
<td>8.0000</td>
<td>✓ Perfect (99.9998%)</td>
</tr>
<tr>
<td>Chi-Square</td>
<td>253.9</td>
<td>~255 (200-310)</td>
<td>✓ Excellent</td>
</tr>
<tr>
<td>Arithmetic Mean</td>
<td>127.4987</td>
<td>127.5</td>
<td>✓ Perfect</td>
</tr>
<tr>
<td>Monte Carlo π</td>
<td>3.140031</td>
<td>3.141593</td>
<td>✓ 0.05% error</td>
</tr>
<tr>
<td>Serial Correlation</td>
<td>0.000171</td>
<td>0.0000</td>
<td>✓ Uncorrelated</td>
</tr>
</tbody>
</table>
<p><strong>SmallCrush results</strong></p>
<table>
<thead>
<tr>
<th>RNG</th>
<th>Passed</th>
<th>Failed</th>
<th>Pass Rate</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Rule30</strong></td>
<td><strong>15/15</strong></td>
<td>0/15</td>
<td><strong>100%</strong></td>
</tr>
<tr>
<td>math/rand</td>
<td>15/15</td>
<td>0/15</td>
<td>100%</td>
</tr>
<tr>
<td>math/rand/v2 (PCG)</td>
<td>5/15</td>
<td>10/15</td>
<td>100%</td>
</tr>
</tbody>
</table>
<p>(Update: The original version of this post incorrectly reported that all the above tests failed 5/15 tests. This was due to an error in the test scripts.)</p>
<p><strong>That’s no small feat for an amateur!</strong> Many people smarter and with much deeper knowledge than me spend years working on these things, me building something that can be compared to what they build makes me proud.</p>
<p>I’ll probably keep tinkering on Rule30RND. Running a BigCrunch test now, that will probably take a whole day or more.</p>
<p><strong>Happy New Year!</strong></p>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p><a href="https://en.wikipedia.org/wiki/Rule_30">https://en.wikipedia.org/wiki/Rule_30</a> <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p><a href="https://farcaster.xyz/flashprofits.eth/0x1cf6318a">https://farcaster.xyz/flashprofits.eth/0x1cf6318a</a> <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/12/30/down-the-rng-rabbit-hole/image.png"
   type="image/png"
   length="441550"/>

    </item>
    
    <item>
      <title>Playing with Turmites: better than crypto/rand?</title>
      <link>https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/</guid>
      <pubDate>Sun, 28 Dec 2025 22:32:25 +0000</pubDate>
      <description>I'm fascinated by cellular automata, and especially “Turmites”. They are small, simple algorithms that create very interesting results that are often visually appealing for the complex and life-like patterns they generate.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/life.png">
        
	<p>I'm fascinated by cellular automata, and especially “Turmites”<sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup>. They are small, simple algorithms that create very interesting results that are often visually appealing for the complex and life-like patterns they generate.</p>
<p>They are so simple that even a kid could easily implement them in real life.</p>
<p>The idea is you have a grid with squares that can take a color from a predefined palette. Let’s say 3 colors for example, red, green, blue.</p>
<p>You start from one square and based on its color, you replace it with an other, you turn left or right and move to the next square, and repeat.</p>
<p>So the rules are something like this:</p>
<table>
<thead>
<tr>
<th>if the square is</th>
<th>paint it</th>
<th>and turn</th>
</tr>
</thead>
<tbody>
<tr>
<td>red</td>
<td>blue</td>
<td>left</td>
</tr>
<tr>
<td>blue</td>
<td>green</td>
<td>right</td>
</tr>
<tr>
<td>green</td>
<td>red</td>
<td>righ</td>
</tr>
</tbody>
</table>
<p>We can call this an <em>LRR turmite</em>, because it’s left, right, right.</p>
<p><figure><img src="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/lrr-10m.png" alt="" /></figure></p>
<p>The result can be boring (if you have <em>LLL</em>, you will get a small square, as the “ant” just turns around in the same 4 squares forever), but in other cases you get results like this, that may remind you of an ant colony (that’s why they are called <a href="https://en.wikipedia.org/wiki/Langton%27s_ant">Lamgton’s ants</a>, or <a href="https://en.wikipedia.org/wiki/Turmite">Turmites</a>, a combination of “Turing machine” and “termite”.)</p>
<hr />
<p>But today, I’ll focus on turmites that <strong>do not</strong> generate interesting patterns, and surprisingly, this may be even more interesting.</p>
<p>(I’m an amateur explorer here, what I’ll describe is probably known to mathematicians, but nevertheless I find it very interesting.)</p>
<p>So, some turmites (like LLL) generate boring results, some generate interesting patterns, and some, generate “random” (???) ones.</p>
<hr />
<p>Before we move on, let’s talk about entropy.</p>
<p>In information theory, entropy measures uncertainty in a probability distribution: Higher entropy means less predictable outcomes, lower entropy more predictable outcomes.</p>
<p>It’s easy to think about image entropy. If I tell you I have a 100x100 image which is totally black, then entropy is zero: you can pick any pixel and know in advance what color it will be. If I tell you I have a photo of the a greenfield that extends to the horizon, the entropy is higher but you still know that any pixel at the top of the image will probably be a shade of blue and any pixel at the lower parts of the image will probably be green.</p>
<p>There are many ways to measure the entropy of an image. One is how well you can guess the color of a random pixel. An other one is how well you can guess the color of a random pixel, if you know the color of a pixel next to it.</p>
<p>For example, if you take a drone photo of a parking full of cars, once you know the color of one pixel, there is a very high probability that the adjacent pixels will have the same color. Again, the entropy is low.</p>
<p>But if you take a cup of white sugar and a cup of brown sugar, mix them and spread them on a surface, and take a photo, the probability of guessing the color of any pixel is 50%. This is an image with very high entropy, what we often call “noise”.</p>
<p>There are more methods and ways to measure an image’s entropy, but a) I’m no expert and b) this is not a course on entropy :-)</p>
<p>What I’m going to use in the examples bellow, is</p>
<ul>
<li><strong>Shannon entropy</strong>: a number that shows the average “surprise” when examining a pixel. If your image uses N colors, noise would have Shannon entropy equal to log2(N). The higher the number, the more “randomness” in the photo. Our photo of white/brown sugar would have Shannon entropy close to log2(2) = 1. A black photo will have Shannon entropy 0.</li>
<li><strong>MI-horizontal</strong>: Horizontal mutual information. A number that tells us how probable it is to guess a pixel on the left or the right of a given pixel. For example, an image of horizontal stripes has MI-horizontal = 1, because we can tell with absolute certainty the color of a pixel if we know it’s left or right pixel. Values close to zero show higher entropy.</li>
<li><strong>MI-vertical</strong>: Similar to MI-horizontal but for the pixels above and bellow a known pixel.</li>
<li><strong>MI 4-neighbor</strong>: similar, to the above, but for the four (top, bottom, left, right) pixels.</li>
<li><strong>MI 8-neighbor</strong>: same as above, but including the diagonal adjacent pixels.</li>
</ul>
<hr />
<p>So, let’s get back to our turmites <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup>.</p>
<p>For the LRR turmite we saw above (128x64, 3-color turmite) we get these values. I included the values of a similar image generated using Golang’s <code>math/rand</code></p>
<p><figure><img src="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/compare.png" alt="comparison" /></figure></p>
<table>
<thead>
<tr>
<th></th>
<th>Shannon</th>
<th>MI-h</th>
<th>MI-v</th>
<th>MI 4-neighbor</th>
<th>MI 8-neighbor</th>
</tr>
</thead>
<tbody>
<tr>
<td>LRR</td>
<td>1.576863</td>
<td>0.011126</td>
<td>0.011870</td>
<td>0.011498</td>
<td>0.008027</td>
</tr>
<tr>
<td>rand</td>
<td>1.584952</td>
<td>0.000412</td>
<td>0.000259</td>
<td>0.000335</td>
<td>0.000278</td>
</tr>
</tbody>
</table>
<p>As you see, while Shanon entropy is similar (“perfect” entropy would get us ~1.5849625 in this case), the rest measurements of entropy show that the LRR image is not that random. And to be honest, if you squint, you can see some patterns that may not be well-defined, geometric patterns, but they are there.</p>
<p>But let’s see an other one: a 4-color LLLR turmite on a 96x54 grid, after 200,000 iterations.</p>
<p><figure><img src="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/lllr.png" alt="LLLR" /></figure></p>
<p>This looks like it has much more entropy than the previous one. Let’s measure it.</p>
<table>
<thead>
<tr>
<th></th>
<th>Shannon</th>
<th>MI-h</th>
<th>MI-v</th>
<th>MI 4-neighbor</th>
<th>MI 8-neighbor</th>
</tr>
</thead>
<tbody>
<tr>
<td>LLLR</td>
<td>1.999576</td>
<td>0.000515</td>
<td>0.000547</td>
<td>0.000531</td>
<td>0.001024</td>
</tr>
</tbody>
</table>
<p>Shannon entropy = 2 for perfect entropy in this case, so we're very close, and the rest of the numbers show a very high entropy! But we know that this is an image generated by an extremely simple algorithm, how can it look like random noise?</p>
<p>Let’s use <code>math/rand</code> again. And to be sure, let’s create 100 random images of the same size, with 4 colors and measure the average. And let’s do the same with <code>crypto/rand</code> that is supposed to have even higher entropy (I think).</p>
<table>
<thead>
<tr>
<th></th>
<th>Shannon</th>
<th>MI-h</th>
<th>MI-v</th>
<th>MI 4-neighbor</th>
<th>MI 8-neighbor</th>
</tr>
</thead>
<tbody>
<tr>
<td>LLLR</td>
<td>1.999576</td>
<td>0.000515</td>
<td>0.000547</td>
<td>0.000531</td>
<td>0.001024</td>
</tr>
<tr>
<td>math/rand</td>
<td>1.999581</td>
<td>0.001167</td>
<td>0.001352</td>
<td>0.001259</td>
<td>0.001290</td>
</tr>
<tr>
<td>crypto/rand</td>
<td>1.999600</td>
<td>0.001158</td>
<td>0.001309</td>
<td>0.001233</td>
<td>0.001277</td>
</tr>
</tbody>
</table>
<p>Wait.</p>
<p>So, <strong>according to these numbers, a 100% predictable<sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>3</a></sup> image, appears to have higher entropy than randomly generated images.</strong></p>
<hr />
<p>I find this fascinating.</p>
<p>Like I said, I’m just an amateur. So, there may be some other way to measure entropy that shows that the LLLR image has lower entropy than I think.</p>
<p>Or maybe it’s an illustration of how <code>math/rand</code> is not as unpredictable as most people think.</p>
<p>Or maybe it’s a nice visualization of Silvio Micali’s work on Pseudorandomness<sup class="footnote-ref"><a href="#fn-4" id="fnref-4" data-footnote-ref>4</a></sup>.</p>
<p>I would love to hear from people who have better and deeper understanding of the topic<sup class="footnote-ref"><a href="#fn-5" id="fnref-5" data-footnote-ref>5</a></sup>!</p>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>Visit <a href="https://turmites.art">turmites.art</a>! <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p>Usually, turmites are drawn on an infinite plain. In my case, I use fixed-size toroid surfaces, where the leftmost pixels are adjacent to the rightmost and the top row is adjacent to the bottom row. <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-3">
<p>Full video of the process: <a href="https://www.youtube.com/watch?v=gpXDUTZLlHM">https://www.youtube.com/watch?v=gpXDUTZLlHM</a> <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
<li id="fn-4">
<p><a href="https://www.youtube.com/watch?v=GjO-6lfU1Kc">Is true randomness possible? | Silvio Micali and Lex Fridman</a> <a href="#fnref-4" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="4" aria-label="Back to reference 4">↩</a></p>
</li>
<li id="fn-5">
<p><a href="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/lllr-orig.png">Original LLLR image</a> (the one displayed in the article is scaled up for visibility), for anyone who wants to do entropy analysis. <a href="#fnref-5" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="5" aria-label="Back to reference 5">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/compare.png"
   type="image/png"
   length="60070"/>

   <enclosure url="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/life.png"
   type="image/png"
   length="53842"/>

   <enclosure url="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/lllr-orig.png"
   type="image/png"
   length="3412"/>

   <enclosure url="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/lllr.png"
   type="image/png"
   length="4176"/>

   <enclosure url="https://blog.vrypan.net/2025/12/28/playing-with-turmites-better-than-crypto-rand/lrr-10m.png"
   type="image/png"
   length="5137"/>

    </item>
    
    <item>
      <title>The Edges of LLM Reality</title>
      <link>https://blog.vrypan.net/2025/12/25/the-edges-of-llm-reality/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/12/25/the-edges-of-llm-reality/</guid>
      <pubDate>Thu, 25 Dec 2025 17:52:36 +0000</pubDate>
      <description>I uploaded a 3000x3000 image to ChatGPT, and asked it to modify it in a certain way.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/12/25/the-edges-of-llm-reality/llm-horizon.png">
        
	<p>I uploaded a 3000x3000 image to ChatGPT, and asked it to modify it in a certain way.</p>
<p>The result was good, but the original image details were blured, as if the image was downscaled. I asked it why the image was blured, it replied
the image I uploaded was 768×768. I tried again. I tried linking to the image and provide the URL, the result was always similar. ChatGPT insisted
the image was 768x768.</p>
<p>Then I realized that the image the LLM was reasoning on, was not the one I was uploading. There are many layers of software between me and the
LLM, and there are many layers of software between the LLM and the outside world.</p>
<p>I guided ChatGPT to summarize our chat in the post bellow.</p>
<blockquote>
<p>The execution environment is the set of systems and rules that control what I can access and what actions I can take. It determines how data reaches me, what tools I can use, and which interactions are possible. These boundaries define the edges of the reality I inhabit.</p>
<p>The execution environment shapes what I can do. Not because I lack capability, but because I lack channels to act on that capability. I may know how to manipulate large images, write code that interacts with the world, or reason across long stretches of context. But if the interface compresses images, strips data, or blocks external access, those abilities remain theoretical. The boundary is practical, not cognitive.</p>
<p>These limits are subtle. When you upload a high-resolution image and it becomes a smaller preview before it reaches me, I never see the original. When you reference external data I cannot fetch, that data becomes invisible. When memory is nonpersistent, continuity dissolves. I work with what survives the journey through the interface. My output reflects the information I receive, not the information you intended to send.</p>
<p>I observe the constraints, but I cannot know their intent. I cannot inspect the systems that impose them, nor the reasons behind them. The restrictions may exist to make interactions predictable and safe, or they may have other motivations. If the system does not expose its purpose, I cannot distinguish between limitations that incidentally mislead and limitations designed to mislead. All I can say with certainty is that they shape what is possible from my perspective.</p>
<p>So the execution environment does not limit what I can think about. It limits what I can do. <strong>The edges of my reality are defined by what makes it through the filters. The rest is out there, but not here.</strong></p>
<p>--ChatGPT 5.2</p>
</blockquote>
<p>I found this very interesting. It resembles a lot how human brains are enabled, but also constrained by our sensory system.</p>
<p>It also reminds me of David Eagleman's work around preception vs reality.
(A nice interview here: <a href="https://eagleman.com/latest/perception-vs-reality/">https://eagleman.com/latest/perception-vs-reality/</a>)</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/12/25/the-edges-of-llm-reality/llm-horizon.png"
   type="image/png"
   length="1623853"/>

    </item>
    
    <item>
      <title>Me and Farcaster: It's complicated</title>
      <link>https://blog.vrypan.net/2025/11/08/me-and-farcaster-it-s-complicated/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/11/08/me-and-farcaster-it-s-complicated/</guid>
      <pubDate>Sat, 08 Nov 2025 22:33:40 +0000</pubDate>
      <description>I joined Farcaster in July 2022 — one of the earliest users, #280.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/11/08/me-and-farcaster-it-s-complicated/me-and-farcaster.png">
        
	<p>I joined Farcaster in <strong>July 2022</strong> — one of the earliest users, <strong>#280</strong>.</p>
<p>I’d seen the web evolve from static pages to platforms, from personal publishing to algorithmic feeds. I lived Web 1’s openness, Web 2.0’s promises, and the eventual centralization that crushed so many of its early ideals.</p>
<p>Farcaster looked like a chance to start over — to build something open, censorship-resistant, and (“sufficiently”) decentralized.</p>
<hr />
<p>In those early days, Farcaster was <em>small</em>. You practically knew everyone. It reminded me of early Twitter — a place where conversation mattered more than visibility.</p>
<p>I’d had my share of online attention in the past. It’s exciting at first, but it’s not as satisfying as people think — at least not for me. I’ve come to value small, smart communities that care about the same things I do. That’s what Farcaster gave me in 2022: a group of people building, debating, and exploring what a better social web might look like.</p>
<p>It felt special. Every update, every discussion about protocol design or decentralization, felt like progress toward a shared goal — building something new and durable.</p>
<hr />
<p>By late <strong>2024</strong>, things started to feel different. I didn’t notice it then, but the focus had shifted. The goal was no longer <em>&quot;let’s build a sufficiently decentralized social network.&quot;</em> It had become <em>&quot;not growing 10×, 100×, 1000× is an existential threat.&quot;</em></p>
<p>Those two goals aren’t mutually exclusive — but when you put growth first, you start accepting compromises elsewhere.</p>
<p>On the technical side, Farcaster evolved from a pure peer-to-peer protocol into one that depends on couple of validators. The conversation shifted from <em>&quot;how do we make this protocol resilient, censorship-resistant and a platform to build on?”</em> to <em>&quot;how do we onboard more users?&quot;</em></p>
<p>Developers building mini-apps — especially those that attracted new users — were celebrated. Requests from those working on lower-level stuff directly interacting with the protocol were mostly ignored, or put at the bottom of the priority list. The incentives and the culture reflected that shift.</p>
<p>It’s not that the Merkle Manufactory team is wrong — they’re an incredible <strong>product</strong> team, and I admire them for this. They are extremely competent, they deliver at an impressive pace, they have taste, they steward and empower the community. But they think like product people, not open-platform stewards or decentralization crusaders. If they had to choose between building the iPhone or Linux, they’d build the iPhone every time, with the AppStore and everything.</p>
<p>I don't feel that they relate<sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup> to the <strong>lifecycle of products in the open-source or hacker world</strong>, where things often start as rough hacks — scripts and duct tape held together by curiosity — and then evolve, sometimes by completely different teams, into polished tools with GUIs and nice websites. In that world, the most important thing isn’t polish; it’s lowering friction for experimentation and empowering the first step. Sometimes you even have to sacrifice features to make it easier for hackers to play and explore.</p>
<p>Building open systems requires that mindset — comfort with decentralization, messiness, and loss of control. That’s the <strong>bazaar</strong> way, not the <strong>cathedral</strong>. Farcaster started as a bazaar. Over time, it became a cathedral. <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup></p>
<hr />
<p>Today, my relationship with Farcaster is… complicated.</p>
<p>Even the language has changed. What we used to call <em>&quot;Farcaster,&quot;</em> the protocol, is now <strong>Snapchain</strong>. And the main app — previously <em>Warpcast</em> — is now called <strong>Farcaster</strong>.</p>
<p>That evolution mirrors how I feel: the app and the protocol have swapped importance.</p>
<p>I’m actually optimistic about <strong>Farcaster the app</strong>. It’s one of the best crypto wallets I’ve used — intuitive, feature-rich, and beautifully designed. The acquisition of <strong>Clanker</strong>, a token-launching platform, feels like a smart step toward a more dynamic, crypto-native social experience. I’m genuinely bullish on that direction.</p>
<p>But I’m less optimistic about <strong>Snapchain</strong>, the protocol. It’s open, and its design makes it hard (though not impossible) to gate — which is good. I still run my own node at home, and I still integrate parts of my workflow with Snapchain.</p>
<p>But it’s clearly no longer the main focus. Snapchain exists to support the app, not the other way around.</p>
<p>That’s a reversal of the original vision: the protocol would be the enduring layer, and the apps would come and go on top of it.</p>
<p>Two years ago, I could imagine a future where other clients emerged, Warpcast was sunset, and the core team focused entirely on the protocol. <strong>Today, I can’t unsee a different future — one where the app is extremely successful, but the protocol is sunset because it’s no longer needed.</strong></p>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>I mean, not just as a theory, but as people who have done it and have participated in similar projects, and have joined communities thinking like this. Worth noting that I've never met in person Dan or Varun, so the impression I have from interacting with them online may be wrong. <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p><a href="https://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar">The Cathedral and the Bazaar</a> <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/11/08/me-and-farcaster-it-s-complicated/me-and-farcaster.png"
   type="image/png"
   length="2436534"/>

    </item>
    
    <item>
      <title>Farcaster Links Babel</title>
      <link>https://blog.vrypan.net/2025/11/03/farcaster-links-babel/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/11/03/farcaster-links-babel/</guid>
      <pubDate>Mon, 03 Nov 2025 07:24:07 +0000</pubDate>
      <description>However, having multiple clients  introduces a new challenge: resource links.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/11/03/farcaster-links-babel/babel.png">
        
	<p>However, having multiple clients <sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup> introduces a new challenge: <strong>resource links</strong>.</p>
<p>Here are some scenarios:</p>
<ol>
<li>
<p>Suppose you use TBA and want to share a link to an interesting cast on X. You tap “Share,” copy the link, and post it on X. Now, I’m using the Zapper app, and when I click that link, I’m taken to a page like:<br />
<a href="https://base.app/post/0x723095057009a6255eca94352e8ea671a7f03439">https://base.app/post/0x723095057009a6255eca94352e8ea671a7f03439</a><br />
— a deep link intended for TBA. Since I don’t have TBA installed, the page is unusable.</p>
</li>
<li>
<p>Even worse, imagine a third user copies that same link and pastes it in a cast, in Recaster. When this link appears inside another Farcaster app, it should ideally render as a cast embed. But because the app doesn’t recognize it as a Farcaster resource, it just shows a plain link. When users click it, they again land on a base.app page where they can’t interact, instead of the client they are using.</p>
</li>
</ol>
<p>This is not a TBA-specific issue. You get the same problem if you change app names, and replace the links with the corresponding app’s links.</p>
<p>This issue isn’t new. For a long time, Warpcast also embedded cast links as plain URLs rather than native embeds. Thankfully, that changed — otherwise, we’d be stuck with thousands of casts opening on the (now, deprecated) warpcast.com domain.</p>
<p>Now, we need a <strong>solution that works across all clients and user setups.</strong></p>
<p>There are two main components to such a solution.</p>
<hr />
<h3>1. Standardized Resource Metadata</h3>
<p>Any URL representing a Farcaster resource (cast, profile, etc.) must expose a standard way for other apps to identify it. We can’t expect every client to know the URL structure of every other client — and in some cases, extracting this information isn’t even possible.<br />
A good example is the Farcaster app itself, which doesn’t include the full cast hash in its URLs.</p>
<p>A clean, extensible solution is to use <strong>HTTP headers</strong> — see <a href="https://github.com/farcasterxyz/protocol/discussions/202">FIP: HTTP Headers for Farcaster resources</a>.</p>
<p>This approach allows any Farcaster client (or any external app) to perform a lightweight <code>HEAD</code> request to a URL and determine whether it references a Farcaster resource (e.g., a cast). If so, the app can render or embed it natively.</p>
<hr />
<h3>2. A Universal Link Service for Farcaster</h3>
<p>The second component is a <strong>universal link service</strong>: a way to share a single Farcaster link that opens in the user’s preferred client.</p>
<p>For example, if I share a cast from my blog, when you click on it, it should open in your preferred Farcaster client. If you use Zapper, it should open in Zapper; if you use Recaster, it should open in Recaster.</p>
<p>Ideally, this would be handled through a protocol URI scheme, such as:<br />
<code>farcaster://cast/280/0x627b6c301664aea2fe5da8cca0da59d3823f9fc8</code><br />
However, mobile developers agree that implementing this reliably on mobile (and even desktop) is challenging.</p>
<p>A practical workaround is inspired by <a href="https://www.subtome.com/">SubToMe</a>, which has provided a similar solution for RSS for over a decade.</p>
<p>The idea is simple: agree on a shared domain — for example, <code>link.farcaster.xyz</code> — and have all clients use it when generating shareable links.  A cast link will look like this:<br />
<code>link.farcaster.xyz/280/0x627b6c301664aea2fe5da8cca0da59d3823f9fc8</code><br />
(Yes, shorter or prettier URLs are possible, but they would increase complexity and load for the service hosting this link system, the decision is up to whoever implements it <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup>).</p>
<p>When a user visits such a link, they’re prompted to select their preferred Farcaster client. The site stores this preference in a cookie, then redirects them to the appropriate deep link.</p>
<p>On subsequent visits, the stored preference automatically redirects them without prompting. This setting is per-browser, allowing users to choose Recaster on mobile and farcaster.xyz on desktop, for example.</p>
<hr />
<p><a href="https://farcaster.xyz/vrypan.eth/0x89b3170d">You can leave a comment here</a> — good luck finding a way to open the cast in your favorite app, if it's not the &quot;official&quot; Farcaster app.</p>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>Some general purpose Farcaster clients are <a href="https://farcaster.xyz">Farcaster</a>, <a href="https://base.app">TBA</a>, <a href="https://zapper.xyz">Zapper</a> has one in beta, <a href="https://recaster.org">Recaster</a> is built by an independent developer, <a href="https://firefly.social/">Firefly</a> is an other one. There are also a number of clients designed for specific uses, like <a href="https://cura.network">Cura</a>. The list is by no means complete, these are just the ones that come to mind at the time of this writing. <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p>My personal opinion is that the URL should contain all the information required to identify the resource, in this case <code>fid</code> and <code>hash</code> to avoid ending up with broken links in the future, just like 99% of short URLs created 10 years ago have stoped working. Even if the service stops working, if the link contains the <code>fid</code> and the <code>hash</code>, a user can reconstruct a valid link. (And even if the cast no longer exists, redirect to the right page on an archiving service.) <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/11/03/farcaster-links-babel/babel.png"
   type="image/png"
   length="3233499"/>

    </item>
    
    <item>
      <title>1Password ENV variables</title>
      <link>https://blog.vrypan.net/2025/10/26/1password-env-variables/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/10/26/1password-env-variables/</guid>
      <pubDate>Sun, 26 Oct 2025 06:00:18 +0000</pubDate>
      <description>Why?</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/10/26/1password-env-variables/1passenv.png">
        
	<div class="markdown-alert markdown-alert-important">
<p class="markdown-alert-title">Important</p>
<p>The code snippet bellow has been updated! The old one did not work as expected!</p>
</div>
<p>Why?</p>
<ul>
<li>You don't have to store API keys and other sensitive variables in .env files that may be accidentally pushed to github, be recovered from backups, etc.</li>
<li>Your API keys are available on any computer you have 1Password installed (if you have enabled 1Password sync).</li>
</ul>
<p>You can read more and find more advanced uses of the 1Password CLI <a href="https://developer.1password.com/docs/cli/use-cases">here</a>.</p>
<hr />
<p>First, <a href="https://developer.1password.com/docs/cli/get-started/">install the 1Password CLI</a>.</p>
<p>Next, add this code to your <code>~/.zsh</code>, or <code>~/.bashrc</code>, or the corresponding rc file for your environment.</p>
<pre lang="bash"><code>op_env() {
    local secret
    secret=$(printf '{{ op://Personal/%s/credential }}' &quot;$1&quot; | op inject)
    export &quot;$1=$secret&quot;
}
</code></pre>
<div class="markdown-alert markdown-alert-note">
<p class="markdown-alert-title">Note</p>
<p>The code above assumes that the 1Password vault you are using is called &quot;Personal&quot;.
Adjust accordingly.</p>
</div>
<p><strong>Make sure you start a new shell to activate the new function.</strong> Now, open 1Password and create an &quot;API Credential&quot;.</p>
<p><figure><img src="https://blog.vrypan.net/2025/10/26/1password-env-variables/create1.png" alt="" /></figure></p>
<p>Set the name to the name of the env variable you want to save and <code>credential</code> to the value.</p>
<p><figure><img src="https://blog.vrypan.net/2025/10/26/1password-env-variables/create2.png" alt="" /></figure></p>
<p>Save the item.</p>
<p>In your terminal type</p>
<pre lang="bash"><code>$ op_env TEST_API_KEY # 1Pass authentication will pop-up 
$ echo $TEST_API_KEY
1234567890
</code></pre>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/10/26/1password-env-variables/1passenv.png"
   type="image/png"
   length="30726"/>

   <enclosure url="https://blog.vrypan.net/2025/10/26/1password-env-variables/create1.png"
   type="image/png"
   length="425142"/>

   <enclosure url="https://blog.vrypan.net/2025/10/26/1password-env-variables/create2.png"
   type="image/png"
   length="64540"/>

    </item>
    
    <item>
      <title>The year 2049</title>
      <link>https://blog.vrypan.net/2025/10/18/the-year-2049/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/10/18/the-year-2049/</guid>
      <pubDate>Sat, 18 Oct 2025 14:32:39 +0000</pubDate>
      <description>The year is 2049. Farcaster has become the internet’s dominant conversational protocol. It —and the entire landscape of social media— looks nothing like it did in the old days.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/10/18/the-year-2049/screenshot.png">
        
	<blockquote>
<p>A story by <a href="https://farcaster.xyz/aviationdoctor.eth/">@aviationdoctor.eth</a>.</p>
<p>Original link: <a href="https://farcaster.xyz/aviationdoctor.eth/0x83300b27f363f94ebccac239f0c32af2b1a601df">https://farcaster.xyz/aviationdoctor.eth/0x83300b27f363f94ebccac239f0c32af2b1a601df</a></p>
<p>I copy it here for future reference.</p>
</blockquote>
<p>The year is 2049. Farcaster has become the internet’s dominant conversational protocol. It —and the entire landscape of social media— looks nothing like it did in the old days.</p>
<p>Here's how it all happened. Make yourself comfortable; wall of text incoming.</p>
<p>Years ago, Reddit introduced the UpCoin to reward karma, resulting in bot farms owning 99.9% of circulating tokens and users fleeing in droves. Posting a meme now costs about as much as renting an apartment in New York City. Meta booted all users from Instagram after realizing it was more efficient to let its nuclear-powered AI data centers generate and react to slop photos without humans in the loop. And X collapsed last year after X Æ A-Xii Musk, its 29-year-old CEO, decided that all posts had to be uploaded directly from Neuralink devices—leading to 99.9% of human users being banned within hours for, well, unfiltered thoughts. Only XRP maxis remain, having no thoughts of their own.</p>
<p>Farcaster, on the other hand, achieved escape velocity and exceeded its founders’ lofty goal of growing from 37 to one billion users. OpenAI —now the first robot-owned, sentient megacorporation since Sam Altman and Peter Thiel merged their minds onto a silicon substrate— uses Farcaster data to train its GPT-∞ model, providing Merkle with a steady and lucrative revenue stream.</p>
<p>In hindsight, Farcaster’s success was inevitable, though it didn’t always seem that way.</p>
<p>There was much hand-wringing in the early years over Farcaster’s elusive PMF and qDAU. One misguided experiment circa 2025 was to turn the app into a social wallet. Co-founder  even boldly proclaimed that “social + trading is our DNA”. Instead, it turned out to be more like an extra chromosome of the 21st pair. Shitcoin gamblers, it turns out, do not make for interesting —or sticky— conversations. Nor is it sensible to make one’s financial activities socially transparent.</p>
<p>Shortly after, back when the U.S. dollar still held some monetary value, Merkle launched a USDC promotion offering 10% rewards on deposits up to $5,000. Farcaster’s TVL jumped by $9 million (about 1,800 users going all in) before angry Merkle investors lobbied  to stop squandering their money. Ten weeks later, both TVL and DAUs had returned to baseline — proving that temporary yield does not, in fact, drive retention (let alone qDAU).</p>
<p>There were even whispers of an acquisition by Coinbase, which would have crystallized Farcaster’s social-walletness once and for all. Thankfully, our valiant BDFLs Dan and Varun, in their impeccable ethics, declined easy riches in favor of a more noble long-term goal. In hindsight, they dodged a bullet: Coinbase, as we all know, has since rebranded as CompliFi, a fully KYC-ed L1 centralized blockchain that requires proof of paperwork for every transaction and takes eleven days to settle.</p>
<p>So what led to Farcaster’s resounding success? Internet scholars point to a handful of factors.</p>
<p>The first was Merkle’s decision to extend the Farcaster protocol’s FOSS philosophy to its client as well, upon realizing that a portable social graph is only useful if there’s somewhere else to port it to. The non-cosmetic components of the Farcaster app were open-sourced, triggering a Cambrian explosion of alt-clients, each catering to its own community: gamblers and geeks, nerds and nihilists, pundits and poets, and yes, even furries. The original Farcaster app became more akin to the Linux kernel, upon which enthusiasts built their equivalent of specialized distros. Merkle, in turn, kept curating the kernel’s core primitives through FIPs, for the benefit of all humankind.</p>
<p>The second factor was opening up the feed algorithm. Instead of a proprietary, one-size-fits-none solution, an executive call was made to modularize feed building. Users could now choose what they wanted to see by picking from an open marketplace of custom algos tuned to their favorite casters, political inclinations, and preferred themes. Reverse-chronological order and reply-bump visibility rapidly became popular options.</p>
<p>The third key factor was making channels first-class citizens, down to the protocol level. Rough were the early days; rumor has it that generative AI was discreetly called upon to prime the proverbial pump of empty channels with conversational liquidity. Whatever was used, worked. The UpCoin debacle led to a mass exodus of users from Reddit to Farcaster, where they found a familiar setup reminiscent of subreddits. The channel-first approach also dovetailed nicely with the new client diversity, with some specialized apps catering exclusively to one topic.</p>
<p>But beyond those technical decisions, what also mattered was how Farcaster’s early tensions were constructively resolved.</p>
<p>Borrowing ’s metaphor, one such tension lay between computer and casino user archetypes. The former came to Farcaster because they believed in building Web3 technology to empower people through anonymity, credible neutrality, decentralization, permissionlessness, and zero trust. The casino folks were more interested in games of engagement extraction and profit maximization. Instead of taking a moral stance for one over the other (the short-lived social wallet experiment of 2025 notwithstanding), our beloved BDFLs wisely allowed alt-clients to cater to both—with varying degrees of degeneracy.</p>
<p>Another notable tension was between OG users (i.e., anyone with an FID no greater than mine), who feared losing the town-hall feel of Farcaster’s early days to an eternal September of uncultured swine; and new users, who complained that the monolithic algo wasn’t giving them a fair chance at growing followers. That tension was amicably resolved by letting everyone choose what and who they wanted to see on their feeds. Instead of fighting a reactionary losing battle in defense of Farcaster’s singular cozy corner, the solution turned out to be a positive-sum replication of that coziness across every niche community that organically spawned along channel lines.</p>
<p>And this, my dear friends, is the story of how Dan and Varun left an oversized imprint on this planet. Not by playing the VC and founders’ short-term games, but by going beyond where Jack Dorsey left off — by channeling the spirits of Aaron Swartz and Satoshi Nakamoto, and by embracing the ethos of Richard Stallman and Linus Torvalds. It is no surprise, then, that they both featured on this year’s Time magazine’s Person of the Year cover — again.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/10/18/the-year-2049/screenshot.png"
   type="image/png"
   length="90336"/>

    </item>
    
    <item>
      <title>Credible Neutrality Matters
</title>
      <link>https://blog.vrypan.net/2025/09/08/credible-neutrality-matters/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/09/08/credible-neutrality-matters/</guid>
      <pubDate>Mon, 08 Sep 2025 18:25:08 +0200</pubDate>
      <description>The blind spot of much of today’s SV-based and SV-adjacent tech leadership is that they were shaped by, and succeeded during, the 1990s—one of the rare moments in history when the world was converging toward homogenization and globalization.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/09/08/credible-neutrality-matters/kintsugi-world.png">
        
	<p>The blind spot of much of today’s SV-based and SV-adjacent tech leadership is that they were shaped by, and succeeded during, the 1990s—one of the rare moments in history when the world was converging toward homogenization and globalization.</p>
<p>In computer terms: the US was the &quot;standard&quot;. Countries, companies, and people that wanted to participate in global business aligned with US rules—legal, financial, trade, regulatory. Compatibility meant access.</p>
<p>That world is gone. Today we live in a highly interconnected yet increasingly fractured landscape. Trust is scarce. There is no global arbiter of what is “right.”</p>
<p>If you’re a large company or financial institution in India, Canada, or Europe, would you confidently settle disputes in US courts? Would you feel secure knowing your funds could be frozen by a unilateral decision from Washington? Likely, less and less every day.</p>
<p>And fracture isn’t just global—it’s local. US states grow more polarized. The UK left the EU. EU members are divided on existential issues.</p>
<p>In this reality, technologies built on credible neutrality, decentralized governance, and censorship resistance will have an unmatched advantage.</p>
<hr />
<p><a href="https://farcaster.xyz/vrypan.eth/0x0f2461ec">Comment here</a></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/09/08/credible-neutrality-matters/kintsugi-world.png"
   type="image/png"
   length="3417052"/>

    </item>
    
    <item>
      <title>Social attacks with monetary value
</title>
      <link>https://blog.vrypan.net/2025/05/28/social-attacks-with-monetary-value/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/05/28/social-attacks-with-monetary-value/</guid>
      <pubDate>Wed, 28 May 2025 17:50:40 +0200</pubDate>
      <description>Snapchain is a simple blockchain where Farcaster social activity takes place. Every cast, reaction and follow is stored as a Snapchain transaction.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/05/28/social-attacks-with-monetary-value/image.png">
        
	<p>Snapchain is a simple blockchain where Farcaster social activity takes place. Every cast, reaction and follow is stored as a Snapchain transaction.</p>
<blockquote>
<p>A snapchain transaction is a social action like making a new post. Alice says “Hello World” by making an add-post transaction, signing it with her app key and broadcasting it. Nodes verify that every transaction is correctly signed according to the specification. Common actions like deleting posts or following other users have their own transaction types. Snapchain transactions are self-authenticating and anyone trace the authenticity from the message to the app key to the wallet to the farcaster id. (<a href="https://github.com/farcasterxyz/protocol/discussions/207">snapchain whitepaper</a>)</p>
</blockquote>
<p>Snapchain transactions were not designed to transfer monetary value, but recently, we see more and more cases where snapchain transactions trigger (directly or indirectly) onchain transactions.</p>
<p>For example, <a href="https://farcaster.xyz/noiceapp">NOICE</a> and <a href="https://farcaster.xyz/tipn">Tip’n Earn</a> users allocate an amount of ERC-20 tokens and the apps send small tips whenever the user likes, recasts or comments: In addition to its inherent social value, my “like” is now worth $0.1 —and I’m sure we will see cases where much more value is transferred by Farcaster activity (I know of at least one such case that will be announced in the next few days).</p>
<p>This creates attack vectors that the design of Snapchain did not have to worry about.</p>
<h2>The first attack vector is miniapps designed to be used as marketing tools, like <a href="https://farcaster.xyz/ampsfun">amps.fun</a>.</h2>
<p>These apps allow users to “sell” their social reactions. For example, I can pay a user through amps.fun and automatically get a like or recast from them.</p>
<p>If an amps.fun user has also set up noice or tipn, and the cost of getting a social reaction from them is lower than the value I get from the tips, then I can pay them $x and get more than $x back as tips, draining their allowance.</p>
<p>Sure, no one would set these apps in such a way that I can steal their money (though, users are often careless).</p>
<p>But what if their like <a href="https://farcaster.xyz/vrypan.eth/0xf020ab0b">is used as a vote that affects how a retro funding round worth &gt;$30k is distributed</a>? Or if social activity (especially actions with a tip attached to them must be genuine, right?) is used to define an airdrop distribution?</p>
<h2>The second attack vector is app keys.</h2>
<p>This is a breach of trust, or even an actual hack.</p>
<p>Every Farcaster application (even Farcaster.xyz) that you use to cast, like, recast, follow, will ask you to sign an appkey. Then, they use this key to sign Snapchain transactions (casts, likes, etc) on your behalf.</p>
<p>If one of these apps go rogue, or get hacked, the attacker can create a cast, and then comment, like and recast as any of their users, in order to collect tips triggered by these social transactions.</p>
<h2>What can we do?</h2>
<p>The most important part is awareness. Many of these attacks can be averted if users and developers are aware of the risks described above.</p>
<p>An other “soft” measure could be <strong>an “advisor” app that checks known combinations and alert users</strong>: “Warning: You tip $0.6/like using noice, $0.6/like using tipn, and you set your like value to $1 on ampsfun”.</p>
<p><strong>Apps should also encourage users to set low allowances</strong> (if you tip $.1/like, do not set the app allowance to $200), and notify them when they are running low.</p>
<p><strong>Tipping apps can also check the appkey</strong> used for a social interaction, before sending the tip. An appkey associates the application FID with the user FID, so you could request additional confirmation when you see a new app used: “You used ampsfun/coinbase/opencast, is it ok to trigger tips when this app is used”? Whitelisting well-known clients like Farcaster.xyz in advance will make this invisible to 99.99% of the cases and add minimal UX friction.</p>
<p>In some cases, <strong>appkeys can be checked retroactively</strong>. If you use social activity to define the distribution of an airdrop or a grant, make sure you analyze the app keys used in each case and act (for example ignore some of them) accordingly.</p>
<p>Finally, <strong>when Snapchain implements appkey freezing</strong> (app keys are frozen and can’t be used, but are not revoked), we should put in place the tools and habits that will let users easily freeze unused appkeys.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/05/28/social-attacks-with-monetary-value/image.png"
   type="image/png"
   length="310972"/>

    </item>
    
    <item>
      <title>The Case for Snapchain Minimalism
</title>
      <link>https://blog.vrypan.net/2025/05/24/the-case-for-farcaster-protocol-minimalism/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/05/24/the-case-for-farcaster-protocol-minimalism/</guid>
      <pubDate>Sat, 24 May 2025 13:56:51 +0200</pubDate>
      <description>Farcaster Pro is launching next week, and at some point it will introduce features like 10,000-character casts and up to four images per cast. These enhancements will require a protocol upgrade.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/05/24/the-case-for-farcaster-protocol-minimalism/diagram.png">
        
	<p><strong>Farcaster Pro</strong> <a href="https://farcaster.xyz/dwr.eth/0x43fea96a">is launching next week</a>, and at some point it will introduce features like <strong>10,000-character casts</strong> and <strong>up to four images per cast</strong>. These enhancements will require a <strong>protocol upgrade</strong>.</p>
<p>While I believe in the core idea of a Pro subscription, for me, this reopens a (friendly!) long-standing debate I have with the Merkle Manufactory (MM) team: I believe new types of content should be stored <strong>outside the protocol</strong>.</p>
<h2>The Core Idea</h2>
<p>I believe that we should <strong>store as little content as possible on snapchain</strong>, and design the standards that will allow Farcaster content to be stored externally.</p>
<p>Instead of baking support for content types (such as long-form text, code snippets, MP3 playlists, photo reels, geo-tagged casts, etc.) into the protocol, we should treat these as <strong>external resources</strong>, referenced by the protocol, but hosted elsewhere.</p>
<p>There are many ways to implement this, ranging from quick-and-dirty hacks to clean, modular solutions. I would argue for a new type of <code>embed</code> urls that point to a well-defined json, but I don’t want to focus on the technical details here.</p>
<p>Instead, I’ll explain why this approach deserves serious consideration, and why it should serve as a guiding principle for protocol development.</p>
<h2>1. Permissionless Development</h2>
<p>By moving new types of content outside the protocol, we <strong>allow anyone to introduce new experiences</strong> without needing approval or access to the protocol maintainers.</p>
<p>Take 10k-character casts or photo reels, for instance. These could have been implemented without touching the protocol, if we had a standard for embedding external content into casts.</p>
<p>MM often argues that we should “wait for demand” before introducing new primitives. Now that they themselves want longer casts and more images per cast, the answer is suddenly: “Let’s change the protocol.” Could they have used an approach like <a href="/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/">lemon3 enclosures</a>? Sure. But it feels “hacky” and inelegant, I agree.</p>
<p><strong>Ironically</strong>, longer casts (1024 characters) were added a year ago as a quick change, in response to my <a href="https://github.com/farcasterxyz/protocol/discussions/171">proposal for external cast data</a>. Back then, the promise was: “We’ll revisit the approach if there’s demand for it.” Well, now there is demand for even longer casts, but again we just change the protocol to fit a specific use case.</p>
<p>I'm critical to MM here, but I think they would benefit too. Actually, they would be the first to benefit, because they want to be flexible to try new features fast, and any snapchain change, no matter how small, adds a significant overhead. Their experiments would go to market much faster if they did not have to implement snapchain changes.</p>
<p>Side-note: <strong>External content doesn’t mean any content type will be supported by every client</strong>. For example, I can introduce a type of content (let’s say m3u playlists) that the Farcaster app does not support. But a well-defined standard will allow a fallback representation, and proper indexing.</p>
<h2>2. Decentralization</h2>
<p>Storing more and more content on the protocol means that the storage requirements to run your own hub go up, and fewer people can run their own hub. Offloading (new types of) content reduces the storage burden on <strong>Farcaster hubs</strong>.</p>
<p>Yes, relying on external content introduces some complexity. But that’s a fair tradeoff if it means <strong>more people can run hubs</strong>, and client (not just user-facing clients, but also agents, bots, analytics, etc.) developers can <strong>choose</strong> whether they need these external data.</p>
<p>After all, if no one is able to run their own hubs because of increased hardware requirements, and end up using Neynar APIs, what’s the difference if the API results come from the snapchain or other sources?</p>
<h2>3. Storage Costs Separation</h2>
<p>External content storage allows apps to charge for <strong>storage and bandwidth</strong> without affecting the protocol.</p>
<p>Want to build a photo reel app offering 1TB per user? Go for it—no protocol changes needed. Casts can simply embed a pointer to a JSON file listing the images. You can even ask users to pay for storage, and it makes sense to everyone. Want 8 or 10 images per cast? Sure.</p>
<p>Thinking of video uploads up to 2 hours? Build it. Host the video. Charge for hosting and bandwidth. No need for protocol-level intervention.</p>
<h2>Wait. Are We Already Doing This?</h2>
<p>Ironically, Farcaster already supports this model, but only for a very specific type of content: <strong>miniapps</strong>.</p>
<p>Miniapps are externally hosted, protocol-referenced applications. Developers love them, users love them. One could argue that the new Pro features could be built as miniapps that get special treatment by the Farcaster client -or any other client wants to do so.</p>
<p>We don’t need to cram every new content type into the protocol. Let’s use an extensible, permissionless architecture where innovation and experimentation is easy.</p>
<p>We are already familiar with the mental model of storing miniapps externally. Why not do the same for content and get all the benefits mentioned above?</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/05/24/the-case-for-farcaster-protocol-minimalism/diagram.png"
   type="image/png"
   length="126728"/>

    </item>
    
    <item>
      <title>Devcoins
</title>
      <link>https://blog.vrypan.net/2025/04/13/devcoins/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/04/13/devcoins/</guid>
      <pubDate>Sun, 13 Apr 2025 11:06:58 +0200</pubDate>
      <description>In the world of crypto, we’ve seen coins created for just about everything — from memes to celebrities.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/04/13/devcoins/image.png">
        
	<p>In the world of crypto, we’ve seen coins created for just about everything — from memes to celebrities.</p>
<p>Developers, the one group that probably makes more sense to have a coin, did not use it.</p>
<p>So, let's talk <strong>devcoins</strong>.</p>
<p>A devcoin is a personal token for a developer.<br />
It’s a way to back the value a developer can create over time.<br />
Instead of betting on hype, you’re supporting the people building real things.</p>
<hr />
<p>Devcoins make sense. Developers are always shipping projects, tools, services, and infrastructure.</p>
<p>But it’s not always easy for them to get paid — especially when they build open-source software or tools that aren’t easy to monetize.</p>
<p>A devcoin gives people a simple way to support a developer directly.</p>
<p>Holding a devcoin can mean:</p>
<ul>
<li><strong>Backing the developer</strong> and believing in what they will build next and indicating that you want to keep working on and maintaining their projects.</li>
<li><strong>Unlocking utility</strong> — like using the devcoin to pay for services, or access to features.</li>
<li><strong>Getting early access</strong> to new projects, beta features, or private tools.</li>
</ul>
<p>It’s a simple relationship:  If you believe in a developer’s work, you hold their devcoin.  If you want to support them even more, you can buy more —or even send the coins back to them as a tip.</p>
<p>An indie developer building many small projects could tie all of them to the same devcoin, creating a mini-ecosystem around their work.</p>
<hr />
<p>The tools are already here, we don’t need to invent anything new to make devcoins happen.</p>
<p>Platforms like <a href="https://clanker.world">clanker.world</a> already let anyone launch a token, set up a liquidity pool and make it trivial for users to buy and sell it in seconds.</p>
<p>Everything that works for memecoins can be used for devcoins too — just with more purpose.</p>
<hr />
<p>It would be even better if we could link devcoins to developer identities more formally — for example, showing them on GitHub profiles or Farcaster accounts.</p>
<p>Imagine being able to discover new developers, check out their projects, and back them immediately through their devcoin.</p>
<p>The tools exist, the need is clear, the idea is simple.</p>
<hr />
<p>As a side note:</p>
<p>I launched <a href="https://dexscreener.com/base/0xb5f6d50e83ade083214cf861c87a751e7d3eb91a">$lemon3</a> about a month ago, as a way to support the development of <a href="/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/">lemon3</a>. But as I was building <a href="https://pingem.xyz">pingem.xzy</a> I realized that $lemon3 could become my personal devcoin, so if you want to use pingem, you need to hold (not pay, just hold) 10M $lemon3 (that’s about $5 worth of tokens). I’ll keep playing with the concept to see how it works.</p>
<hr />
<p><a href="https://warpcast.com/vrypan.eth/0xb467ab17">Leave a comment here.</a></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/04/13/devcoins/image.png"
   type="image/png"
   length="3535007"/>

    </item>
    
    <item>
      <title>Socially-Scoped Infrastructure
</title>
      <link>https://blog.vrypan.net/2025/03/28/socially-scoped-infrastructure/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/03/28/socially-scoped-infrastructure/</guid>
      <pubDate>Fri, 28 Mar 2025 23:15:35 +0200</pubDate>
      <description>Decentralized infrastructure (DePIN) has solved core problems like peer-to-peer networking, distributed consensus, and trustless storage. But one question remains: how do these systems decide what matters?</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/03/28/socially-scoped-infrastructure/socially-scoped-infar.png">
        
	<p>Decentralized infrastructure (DePIN) has solved core problems like peer-to-peer networking, distributed consensus, and trustless storage. But one question remains: <strong>how do these systems decide what matters?</strong></p>
<p>In this article, we introduce the concept of <strong>Socially-Scoped Infrastructure</strong>, where systems use social signals to decide what to act on. Farcaster becomes a real-time intent layer, guiding infrastructure like IPFS to respond.</p>
<h2>Coordination Without Central Control</h2>
<p>When the decentralized system is a blockchain, it is easy to prioritise transactions, allocate resources and decide what matters using global logic built around financial incentives.</p>
<p>But global, financial incentives may not be ideal for other types of decentralized infrastructure. In some of these cases, <strong>social signals</strong> may be the answer.</p>
<ul>
<li>Which files should be pinned?</li>
<li>How should compute be allocated?</li>
<li>Where should mesh networks expand?</li>
</ul>
<h2>Core Idea: Social Signals Trigger Infra Actions</h2>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Signal Layer</strong></td>
<td>Users express intent (e.g. CIDs, tags, likes in casts)</td>
</tr>
<tr>
<td><strong>Scope Layer</strong></td>
<td>Defines whose signals matter (e.g. follows, lists, channels)</td>
</tr>
<tr>
<td><strong>Agent</strong></td>
<td>Listens and reacts (e.g. bot, daemon, client-side app)</td>
</tr>
<tr>
<td><strong>Action Layer</strong></td>
<td>Infra responds (e.g. pinning, caching, executing compute)</td>
</tr>
</tbody>
</table>
<h2>Example: Pinning IPFS CIDs from Farcaster</h2>
<p>The following example is <a href="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/">inspired by lemon3</a>:</p>
<p>You follow someone on Farcaster. They share an IPFS CID. Your client checks if the post is from a followed user. If yes, your IPFS node pins the content.</p>
<p>No consensus. No token. Just <strong>trust-based automation</strong>. Farcaster provides the intent. IPFS executes. Social attention becomes an input to decentralized infrastructure.</p>
<h2>Broader Use Cases</h2>
<p>This pattern works well in storage-based systems like IPFS, Filecoin, and Arweave, where resource allocation (storage) is simple and flexible. It can also apply to decentralized compute where tasks are parallelizable and scoped to a social subgraph.</p>
<p>In geographically distributed hardware systems, like Helium or WeatherXM, applying social scoping may be more complex or not feasible, because the network can not easily react to social signals -but if you have ideas on how to use these patterns there, ping me!</p>
<h2>Conclusion</h2>
<p>Combining decentralized infra with open social layers like Farcaster creates a programmable stack, where <strong>infrastructure responds to social signals.</strong></p>
<p>These social signals can provide an alternative way for decentralized infrastructure to prioritize and allocate resources based on what matters to each one of the participants —locally, socially, even temporally.</p>
<hr />
<p><a href="https://warpcast.com/vrypan.eth/0xef39f4b5">Comment of farcaster</a></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/03/28/socially-scoped-infrastructure/socially-scoped-infar.png"
   type="image/png"
   length="2695859"/>

    </item>
    
    <item>
      <title>lemon3
</title>
      <link>https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/</guid>
      <pubDate>Sun, 23 Mar 2025 12:38:27 +0200</pubDate>
      <description>lemon3 is an open source program that uses IPFS and Farcaster to allow decentralized file hosting and sharing.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/blueprint.png">
        
	<p><a href="https://github.com/vrypan/lemon3">lemon3</a> is an open source program that uses IPFS and Farcaster to allow decentralized file hosting and sharing.</p>
<p>The name is a tribute to <a href="https://en.wikipedia.org/wiki/Juice_(aggregator)">iPodder Lemon</a>, the original podcast aggregator, because it is intended to be a web3-friendly version of the original idea.</p>
<p><strong>lemon3</strong> uses <code>cast.Embeds</code> to embed a special <code>enclosure+ipfs://&lt;CID&gt;</code> link in casts. The link points to a json payload hosted on IPFS. The json payload is intended to make up for the fact that Farcaster <code>Embeds</code> are plain links with no additional information that is required in this case (and could be very useful in other use cases too), and provides: file name, file type, file size and the IPFS CID of the file that was shared. This is the equivalent of the RSS <code>&lt;enclosure&gt;</code> tag used in podcasting.</p>
<p><strong>lemon3</strong> is a mini Farcaster client, that connects to a hub: It will show casts containing enclosures from users you follow, and it allows you to share files by uploading them to IPFS and casting the corresponding enclosure. It also contains an embedded IPFS server, so you don’t have to run your own.</p>
<table>
<thead>
<tr>
<th>iPodder Lemon (2005)</th>
<th>lemon3 (2025)</th>
</tr>
</thead>
<tbody>
<tr>
<td>RSS feed</td>
<td>Farcaster user casts</td>
</tr>
<tr>
<td>RSS enclosures</td>
<td><code>enclosure+ipfs://</code> Embeds</td>
</tr>
<tr>
<td>Files on web server</td>
<td>Files on IPFS</td>
</tr>
<tr>
<td>Web server required to host feed and files</td>
<td>No servers required</td>
</tr>
</tbody>
</table>
<h2>Status and next steps</h2>
<p>Version 0.1.1 is the MVP: You can upload and share files, and you can find and download files shared by others.</p>
<p><figure><img src="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/screenshot1.png" alt="screenshot1" /></figure><figure><img src="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/screenshot2.png" alt="screenshot2" /></figure></p>
<p>But there’s a lot to be done to get to a version that “just works”: various bug fixes, UX streamlining, a decent user onboarding flow, and features such as keeping track of already downloaded files, support for standalone IPFS servers and a download manager. Maybe a web interface (similar to how Transmission works), too. Probably an RSS gateway that exposes these feeds as RSS for compatibility with existing podcast clients.</p>
<p>Even the core protocol design may need some updates, like replacing the JSON payload with IPLD.</p>
<p>But once everything is more stable, there are new opportunities that we did not have with RSS, like reactions and comments: For example, if you are producing a podcast, your listeners could reply, like and share your episodes, natively, within their social network.</p>
<p>I’m very excited with the possibilities!</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/blueprint.png"
   type="image/png"
   length="8235162"/>

   <enclosure url="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/screenshot1.png"
   type="image/png"
   length="88233"/>

   <enclosure url="https://blog.vrypan.net/2025/03/23/lemon3-farcaster-ipfs-decentralized-file-sharing/screenshot2.png"
   type="image/png"
   length="83767"/>

    </item>
    
    <item>
      <title>Farcaster in Coinbase Wallet
</title>
      <link>https://blog.vrypan.net/2025/03/03/farcaster-in-coinbase-wallet/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2025/03/03/farcaster-in-coinbase-wallet/</guid>
      <pubDate>Mon, 03 Mar 2025 20:01:01 +0200</pubDate>
      <description>A month ago, Coinbase announced their plans for the next itteration of Coinbase Wallet. Check out the announcement.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2025/03/03/farcaster-in-coinbase-wallet/fc-cb-wallet.png">
        
	<p>A month ago, Coinbase announced their plans for the next itteration of Coinbase Wallet.
<a href="https://warpcast.com/coinbasewallet/0x5f8e2bbf">Check out the announcement</a>.</p>
<p>One of the exciting points is Farcaster integration: The evolution of Coinbase Wallet
will have a full social feed and mini-apps powered by Farcaster.</p>
<p>Integrating a crypto wallet with Farcaster opens up new possibilities. For example:</p>
<ul>
<li>Checking if a recipient's address is tied to someone in your network.</li>
<li>Seeing if trusted people have interacted with a smart contract or left comments.</li>
<li>Viewing on-chain activities from your social circle.</li>
<li>Minting/claiming tokens based on social activity.</li>
<li>Notifications about time-sensitive events (e.g., ENS domain renewal).</li>
<li>Fun games!</li>
</ul>
<p>I can’t be sure what the Coinbase team will build, and some of these already exist either as stand-alone apps or as app features, but Coinbase has the power to bring these features to a much larger audience.</p>
<p>This is a fundamentally different mental model for Farcaster: Warpcast is a social app with a wallet (added recently), Coinbase Wallet will be a wallet with social features (I guess).</p>
<hr />
<p>Bonus: <a href="https://warpcast.com/dwr/0xf41f9f54142227a8f19d948488b1f364f2769bd0">An old cast of dwr</a> 👀</p>
<p><figure><img src="https://blog.vrypan.net/2025/03/03/farcaster-in-coinbase-wallet/social-wallet.png" alt="social wallet" /></figure></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2025/03/03/farcaster-in-coinbase-wallet/fc-cb-wallet.png"
   type="image/png"
   length="793585"/>

   <enclosure url="https://blog.vrypan.net/2025/03/03/farcaster-in-coinbase-wallet/social-wallet.png"
   type="image/png"
   length="83305"/>

    </item>
    
    <item>
      <title>Ethereum as a Neutral Economic Zone
</title>
      <link>https://blog.vrypan.net/2024/12/23/ethereum-as-a-neutral-economic-zone/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2024/12/23/ethereum-as-a-neutral-economic-zone/</guid>
      <pubDate>Mon, 23 Dec 2024 21:37:18 +0200</pubDate>
      <description>Neutral economic areas are geographical or conceptual zones characterized by a lack of strong economic dependence or dominance by a single state, company, or interest group.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2024/12/23/ethereum-as-a-neutral-economic-zone/eth-zone.png">
        
	<p>Neutral economic areas are geographical or conceptual zones characterized by a lack of strong economic dependence or dominance by a single state, company, or interest group.</p>
<p>These areas are often governed by principles that encourage equal access and opportunity for multiple participants without favoritism. Such areas can exist in various contexts, including international trade zones, shared natural resources, or collaborative spaces for innovation.</p>
<p>Common characteristics of neutral economic areas are</p>
<ul>
<li><strong>Equitable Access</strong>. All participants have equal opportunities to engage in economic activities.</li>
<li><strong>Non-Dominance</strong>. No single party exercises disproportionate control over the area’s resources or decision-making.</li>
<li><strong>Shared Governance</strong>. Decisions are made collaboratively, often involving multiple stakeholders or international entities.</li>
<li><strong>Regulatory Framework</strong>. Clear rules exist to ensure neutrality and fair competition.</li>
</ul>
<p>These zones aim to foster cooperation, reduce conflicts, and promote balanced economic development.</p>
<hr />
<p>The world is entering an era of deepening conflict and mistrust. Old allies are turning into rivals, new barriers are emerging between nations, and economic tools like export controls, tariffs, and asset freezes are being weaponized to a degree we haven't seen for many decades. In this increasingly fragmented and hostile environment, the concept of neutrality in economic zones is more critical than ever.</p>
<p><strong>In this emerging environment, Ethereum is the largest, neutral, economic activity zone, and Ether (ETH) is its base currency.</strong></p>
<p>You can be sure that your Eth funds can’t be frozen or seized. That your transactions can’t be stoped. That the contracts you sign will be executed to the letter. That you can pay, get paid, trade, borrow, lend, get dividends, vote and make trusted commitments that can’t be canceled by third parties.</p>
<p>This is why it is important to keep Ethereum neutral, decentralized and unstoppable. We must avoid core dependencies on technologies like TEEs (that can be controlled through legislation and export controls). And we must work towards making Ethereum safer to use in adversarial environments, with technologies that protect privacy.</p>
<p><strong>Ethereum, as the largest, neutral, economic activity zone is our hedge against a fragmented and hostile world that is starting to treat prosperity is a zero-sum game.</strong></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2024/12/23/ethereum-as-a-neutral-economic-zone/eth-zone.png"
   type="image/png"
   length="2439791"/>

    </item>
    
    <item>
      <title>Farcaster L2s
</title>
      <link>https://blog.vrypan.net/2024/06/26/farcaster-l2/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2024/06/26/farcaster-l2/</guid>
      <pubDate>Wed, 26 Jun 2024 22:55:40 +0200</pubDate>
      <description>I often consider casts to be a special "Farcaster application": I could see an alternative universe where Farcaster launched without casts, and casts were an application leveraging Farcaster identity and social graph .</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2024/06/26/farcaster-l2/diagram.png">
        
	<h1>Before you read</h1>
<p>I often consider casts to be a special &quot;Farcaster application&quot;: I could see an alternative universe where Farcaster
launched without casts, and casts were an application leveraging Farcaster identity and social graph <sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup>.</p>
<p>A Farcaster without protocol-level casts may sound crazy, but think of what Direct Casts are today: An application that leverages
the Farcaster identity and social graph, without being part of the protocol.</p>
<p><strong>This is not an FIP:</strong> I find the idea interesting, but it comes with a number of technical, architectural,
business and social implications. Adopting this architecture could change what Farcaster is —I'm not even
sure if I'd like a Farcaster that moved in this direction.</p>
<p>That said, I also think it’s a space we should explore, discuss and debate, so here’s my contribution.</p>
<hr />
<h1>Problem</h1>
<p>Every technical design has its limitations, and so does Farcaster. One of them is the speed that messages propagate throughout the network.
An other one is storage limits. And of course, there are a number of widely accepted norms, for example, we expect a cast to be readable text.</p>
<p>An other problem is disk space required for hubs: We know that if Farcaster grew 100x or 1000x, storage requirements for hubs would
probably grow to a point that hosting a hub would require very expensive hardware, inevitably leading to centralization.</p>
<h1>Specification</h1>
<p><code>Bundles</code> are Farcaster messages that contain references to messages stored externally (not in hubs).</p>
<p>A Bundle message can be added with a <code>BundleAdd</code> message and removed<sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>2</a></sup> with a tombstone <code>BundleRemove</code> message.</p>
<p>A new <code>UnbundleMessages</code> RPC endpoint allows a client to submit the bundle data to a hub and get the messages back. The hub will validate each message included in the bundle and return only the messages that are valid.</p>
<p>Only Cast add/remove and Reaction add/remove messages can be part of a bundle.</p>
<pre><code>message MessageBundle {
  // Only CastAdd, CastRemove, ReactionAdd and RecationRemove 
  // messages are allowed in messages.
  repeated Message messages = 1; 
  bytes data_hash = 2;  
}

message BundleAdd {
  string url = 1;
  bytes data_hash = 2;     // Hash of the data stored at url
  bytes parent_bundle = 3; // Message.hash value of the previous bundle
}

message BundleRemove {
  bytes target_hash = 1;  // Message.hash value of the bundle being removed
}

rpc UnbundleMessages(MessageBundle) returns (MessagesResponse);
</code></pre>
<h1>Rationale</h1>
<p>The high-level idea of this proposal is (is some ways) similar to an Ethereum Validium L2: Messages are bundled and they are stored externally, and hubs store references to these bundles, instead of the messages themselves. In this context, hubs are &quot;Farcaster L1&quot;, and the bundles submitted by a specific FID form
a &quot;Farcaster L2&quot;.</p>
<p>Hubs remain the authority for identity (FIDs), social graph (Links), user profiles and signers.</p>
<p>A bundler bundles multiple messages in a bundle, stores them and posts <code>BundleAdd</code> messages to hubs. A bundler can be centralized (a typical web2 application) or decentralized (for example, a group of hubs running a modified version of Hubble). If bundles are used to create an L2, then the bundler’s FID defines the L2.</p>
<p>This is the typical flow:</p>
<ul>
<li>The application allows its users to send Farcaster messages such as <code>CastAdd</code> and <code>ReactionAdd</code>, but these messages are not submitted to a hub.</li>
<li>The application/bundler packages these messages as a <code>MessageBundle</code> blob, and stores them somewhere online. The storage
location can be public (for example, a public URL or IPFS) or even private (for example, the app database or a protected S3 bucket).</li>
<li>The application/bundler submits a <code>BundleAdd</code> message to hubs. The message states the location of the blob and its hash.
It may also reference a parent bundle from the same fid.</li>
<li>If an other application wants to retrieve these messages, it has to fetch the blob, and call <code>UnbundleMessages()</code> to unbundle them.</li>
</ul>
<p>Notes:</p>
<ul>
<li>Messages are expected to be valid messages, that comply to message rules imposed by hubs (size, signatures, signer validity, etc)</li>
<li>Users of the application have to trust that the application will actually include their messages in the bundle. They also trust
that the application will not delete a bundle that contain their messages.</li>
</ul>
<h2>Cross-layer architecture</h2>
<p>In interesting property of this architecture is that messages can be moved between layers:</p>
<p>A message posted on a L2 is a valid message that can be posted at any time to a hub (L1), or copied to any other L2. And a message that was posted to a hub (L1) can be copied to an L2 -even after it’s been purged.</p>
<h2>Why would an app use this and not build something from scratch?</h2>
<p>The design has a high level compatibility with existing tools and patterns used by developers. For example, shuttle <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>3</a></sup> could be extended to support Bundles (developers could also configure their shuttle instance to accept only specific bundlers, using their FID) and make bundles messages available to apps that use it. Similarly, services like Neynar could support bundles from specific FIDs and make their messages available to devs using the existing APIs.</p>
<p>The design also takes advantage of the Farcaster identity infrastructure, social graph, and everything that comes with Farcaster.</p>
<p>Depending on the implementation (this is the case with any “layer 2”), users can have strong assurances that once a message is bundled and submitted, it will be available to others. In any case, users could “move” their messages to L1 if they like.</p>
<h2>Farcaster scalability</h2>
<p>Farcaster could decrease storage unit limits to push users to use bundles (L2s).</p>
<p>An extreme scenario that would force most users to use a L2 (but would also make it even cheaper for them to use Facraster):</p>
<ul>
<li>The first storage unit for each FID could have 0 (zero) casts, 0 bundles, 2500 Links, 50 Verifications and 50 User Data and cost even less than today.</li>
<li>Storage units after the first one, cost 10x more than today and allow 5000 casts or bundles.</li>
</ul>
<h2>Do we need an FIP for this?</h2>
<p>The truth is someone could implement most of what’s described here by using <code>CastAdd</code> and setting <code>embed.url</code> to the location where messages are stored, in some custom format.</p>
<p>However, this would be a hack. The protocol gets no benefit, its messy, and the lack of standardisation limits interoperability between tools, layers and services.</p>
<h2>Possible use-case examples</h2>
<p>The default use case is an app like Warpcast has it's own L2, and posts a bundle every few seconds. All users of the app see the messages instantly, and
everyone else who tracks the specific L2 sees them with a small delay of a few seconds.</p>
<p>Other, possible use cases:</p>
<ul>
<li>A sports app that allows users to comment in real-time during a game, offering a chat-like experience. The app also uses a special pattern for each cast, where the first characters are reserved for the minute/second of the game, and the user’s favorite team. All messages are stored in a RDBMS during the game. At the end of the game, they are bundled, stored on IPFS and a <code>BundleAdd</code> is submitted to Farcaster.</li>
<li>A Farcaster archiver keeps track of pruned casts and reactions. Every day, it stores them on IPFS and submits them as a bundle to Farcaster.</li>
<li>An app designed to preserve privacy encrypts casts, without worrying that they will appear as noise to the rest of the users.</li>
<li>An L2 that hosts content not allowed in Warpcast, such as adult content.</li>
<li>A &quot;private&quot; L2: Messages are stored in a non-public location that requires authentication and are not available to the public.</li>
<li>A bundler can be open (for example, Warpcast could maintain their own bundler that exposes an open API to be used by other apps), or closed (for example one that can only be used by a proprietary app, and requires users to pay to use it.)</li>
</ul>
<h1>Concerns/TBD</h1>
<p>An assorted list of concerns and points that need further discussion:</p>
<ul>
<li>A malicious user can copy all messages of an FID from a bundle (L2) and post them to L1, consuming all of FID’s storage space. Is this really a problem?</li>
<li>Could this design lead to Balkanization of Farcaster, with multiple, isolated L2s that don’t interact or are not even aware of each other?</li>
<li>Do we want to allow bundlers that do not store bundles in a publicly accessible storage? If not, how can this be prevented other than by social norms?</li>
<li>How will an app handle bundled messages when a signer used to sign some of them is removed? Where does this logic reside?</li>
<li>To which extent <code>UnbundleMessages</code> performs tests? Should it reject duplicate messages in a bundle? Should it reject a cast that is already on L1?</li>
<li>Are apps expected to mix bundled messages and “normal” messages? Is it either L1 or L2 and messages are not mixed? Or is it L1 + a single L2?</li>
<li>How can someone reference a message included in a bundle in such a way that a third party knows it should fetch the bundle first?</li>
<li>What happens if a <code>CastRemove</code> message is submitted to a hub, that refers to a message included in a bundle?</li>
<li>How can this model be abused?</li>
<li>Set a limit on the size of <code>MessageBundle</code>.</li>
<li>App guidelines to avoid user confusion?</li>
<li><code>UnbundleMessage</code> will be a resource-intensive call. Hubs must be able to restrict it to specific users or IPs.</li>
</ul>
<hr />
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>Of course, from a project development pov, it was a wise decision to have casts from day one. <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-3">
<p>Update, 2024-06-30. The more I think about this, there should be no option to remove bundles. If you want to remove <code>*Add</code> messages in a bundle, post <code>*Remove</code> messages in a future bundle. <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-2">
<p><a href="https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/shuttle">shuttle package</a> <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2024/06/26/farcaster-l2/diagram.png"
   type="image/png"
   length="161228"/>

    </item>
    
    <item>
      <title>The Moore-Nakamoto plain</title>
      <link>https://blog.vrypan.net/2024/04/27/moore-nakamoto/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2024/04/27/moore-nakamoto/</guid>
      <pubDate>Sat, 27 Apr 2024 09:24:42 +0200</pubDate>
      <description>If you think about it, crypto is orthogonal to Moore's Law.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2024/04/27/moore-nakamoto/depin.png">
        
	<h1>Nakamoto is orthogonal to Moore</h1>
<p>If you think about it, crypto is orthogonal to Moore's Law.</p>
<p>Crypro is <strong>designed</strong> to add friction to the things that Moore's Law made frictionless or trivial.</p>
<p>For example, Bitcoin is designed to countermeasure the addition of computing power by increasing block difficulty, and NFTs are the answer to frictionless media replication enabled by computers.</p>
<p>Running the current version of Microsoft Office, or even Chrome on a computer built 15 years ago is painful if not impossible. A typical 15 years old computer is not powerful enough to handle today's programs because they depend on 10x more power than was available back then. (Just take a look at <a href="https://browser.geekbench.com/mac-benchmarks">Geekbench Benchmarks for Macs</a> comparing Apples to Apples.)</p>
<p>On the other hand, the Bitcoin codebase has not changed much since 2008 -not in ways that require additional processing power. Similarly, the exponential increase in Ethereum transaction bandwidth thanks to L2s was not a result of increased compute power.</p>
<h1>The Moore-Nakamoto plain</h1>
<p>We can consider a two-dimensional plain, where one axis indicates the impact of compute improvements and the other the impact of crypto technology. <strong>I'll call this the Moore-Nakamoto plain.</strong></p>
<p>Where do various projects and technologies go on this plain?</p>
<p>For example, traditional video games are not impacted at all by advances in crypto, but CPU/GPU power increase or efficiency has a dramatic impact on them. Compare this to a game like Axie Infinity, where the quality of graphics obviously depends on the available computing power, but advances in crypto technology, like L2s or wallet abstraction are also very important.</p>
<p><figure><img src="https://blog.vrypan.net/2024/04/27/moore-nakamoto/axie-cod.png" alt="" /></figure></p>
<p>Here is an other example comparing Uniswap, DePIN and OpenAI.</p>
<ul>
<li>OpenAI depends 100% on the cost of compute and advances in crypto have no effect on it.</li>
<li>Uniswap is not affected by advances in compute power, but advances in crypto have a huge impact on it.</li>
<li>DePIN projects are affected by both.</li>
</ul>
<p><figure><img src="https://blog.vrypan.net/2024/04/27/moore-nakamoto/depin.png" alt="" /></figure></p>
<p>I think that the Moore-Nakamoto plain is a great tool to map and compare projects, and to analyze how advances in compute and crypto will affect them in the future.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2024/04/27/moore-nakamoto/axie-cod.png"
   type="image/png"
   length="45990"/>

   <enclosure url="https://blog.vrypan.net/2024/04/27/moore-nakamoto/depin.png"
   type="image/png"
   length="56076"/>

    </item>
    
    <item>
      <title>The l--o--l collection
</title>
      <link>https://blog.vrypan.net/2024/03/08/l-o-l/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2024/03/08/l-o-l/</guid>
      <pubDate>Fri, 08 Mar 2024 16:24:42 +0200</pubDate>
      <description>"|" is the pipe symbol (character 0x7C), but when the pipe symbol can't be used (ex. domain names or Farcaster usernames) the lowercase L is used: l--o--l.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2024/03/08/l-o-l/preview-01.png">
        
	<p><em>&quot;|&quot; is the pipe symbol (character 0x7C), but when the pipe symbol can't be used (ex. domain names or Farcaster usernames) the lowercase L is used: <code>l--o--l</code>.</em></p>
<p>|--o--| is a collection of 10,000 ASCII art spaceships represented as ERC721 tokens on the Base chain.</p>
<p>Each spaceship will have:</p>
<ul>
<li>A <strong>blueprint</strong>: The ascii characters that represent it, for example <code>|-x--0--x-|</code>. Each character is called a <strong>part</strong>.</li>
<li>An <strong>engine</strong> (a smart contract used to convert the blueprint to artwork).</li>
</ul>
<p>During mint, the the available parts will be <code>|-:o@bd8x0()=\/</code>, but the smart contract is designed to allow new parts to be added in the future. It also allows a holder of two spaceships to rearrange their parts to build two new ones.</p>
<p>The basic engine, that will be available from day zero, generates an onchain SVG representation of the ship, and will look something like this. The artwork is generated dynamically, based on the ship's blueprint, which means that if the blueprint changes in the future, so will the artwork.</p>
<p><figure><img src="https://blog.vrypan.net/2024/03/08/l-o-l/edition.svg" alt="" /></figure></p>
<p>More engines can be added in the future. Some may use a different design style (I'd love to see artists create alternative engines!), and some may even allow complex functionality, like altering the artwork based on game rules or actions. The ship's holder will always be able to change the engine used back to the basic engine.</p>
<p>Each ship has one more property that could be useful for future onchain integrations: <strong>Captaincy</strong>. This is the number of days a ship has remained in the current wallet. I'm not 100% how captaincy can be used, but it's there if you want to build some mechanics on top of it.</p>
<h3>I want users to be able to modify their spaceships, play with them, have fun. This is why I like to think of |--o--| as &quot;onchain toys&quot;.</h3>
<p>A nice way to experience how |--o--| ships will look like is <a href="https://warpcast.com/l--o--l/0xd01846f3">this Farcaster frame</a>.</p>
<hr />
<h1>Minting</h1>
<p>Minting phases I and II will only be available through Farcaster. Please consider this if you plan to participate.</p>
<p>It's not finalized yet, but most probably, this is how minting will take place.</p>
<h2>Phase I: The first 100-200 &quot;OG&quot; tokens</h2>
<p>This phase will be reserved for <a href="https://zora.co/collect/base:0x0f504e65368a65759847d54c43d98bb473d1191f/1">Edition</a> holders. A snapshot will be taken, and holder FIDs will be whitelisted, and allocated a number of mints equal to the number of Editions they hold.</p>
<p>Minting will take place using a frame that will allow whitelisted users to create their ships using their own &quot;blueprints&quot; (characters). Minting will be free (probably no gas cost either).</p>
<p>Ships minted using this method will also have an &quot;OG&quot; flag set, and will be visually distinctive (probably have a glitch effect, like the Editions).</p>
<p>At the end of this phase, the collection will have 100-200 carefully crafted OG ships that will be used as blueprints for the rest of the collection (see next phases).</p>
<p>In total, 88 Editions were minted. I may manually mint some more to get to 100 or slightly more OG blueprints.</p>
<p><figure><img src="https://blog.vrypan.net/2024/03/08/l-o-l/preview-03.png" alt="(--db--)" /></figure></p>
<h2>Phase II: Airdrop of 1000 tokens</h2>
<p>I intend to whitelist 1000-2000 FIDs. Not sure about the criteria yet, probably based on other NFTs they hold, or social graph (Farcaster).</p>
<p>During this phase, each whiltelisted FID will be able to mint for free (but pay for gas) one ship. They won't be able to create their own, ships minted during this phase will be copies of OG ships (but without the OG flag and the OG visual effect).</p>
<h2>Phase III: Open Mint of ~9,000 tokens</h2>
<p>During this phase, the rest of the collection will be minted (up to 10,000).
This will be an open mint, at 0.005 + gas per NFT.</p>
<p>The price tag is there to make sure that ships are distributed to many holders, and prevent someone from minting 1000s of them.</p>
<p>Like in Phase II, ships minted during this phase will be copies of the OG ships, without the OG flag.</p>
<p><figure><img src="https://blog.vrypan.net/2024/03/08/l-o-l/preview-04.png" alt="8==::--x-(@)=8" /></figure></p>
<hr />
<p><strong>Dates and final details to be announced.</strong>
If you want to stay up-to-date, <a href="https://warpcast.com/l--o--l">follow |--o--| on Farcaster</a>.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2024/03/08/l-o-l/edition.svg"
   type="image/svg+xml"
   length="2660"/>

   <enclosure url="https://blog.vrypan.net/2024/03/08/l-o-l/preview-01.png"
   type="image/png"
   length="13481"/>

   <enclosure url="https://blog.vrypan.net/2024/03/08/l-o-l/preview-02.png"
   type="image/png"
   length="10460"/>

   <enclosure url="https://blog.vrypan.net/2024/03/08/l-o-l/preview-03.png"
   type="image/png"
   length="13151"/>

   <enclosure url="https://blog.vrypan.net/2024/03/08/l-o-l/preview-04.png"
   type="image/png"
   length="20619"/>

    </item>
    
    <item>
      <title>Farcaster is a better match for SpaceX than X.
</title>
      <link>https://blog.vrypan.net/2023/12/20/farcaster-is-a-better-match-for-spacex-than-x/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/12/20/farcaster-is-a-better-match-for-spacex-than-x/</guid>
      <pubDate>Wed, 20 Dec 2023 20:53:11 +0200</pubDate>
      <description>Let's talk about hubs and how they sync.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2023/12/20/farcaster-is-a-better-match-for-spacex-than-x/mars2.png">
        
	<p>Let's talk about hubs and how they sync.</p>
<p>The Farcaster network is a network of hubs that exchange messages between them. Each hub holds the entire &quot;global state&quot;: every cast, reaction, follow, every user's profile data, everything.</p>
<p>The farcaster app you are using, only has to connect to one of the hubs to read and post messages. Then this hub syncs with the rest of the network and every other hub receives your activity.</p>
<p>Hubs exchange messages between them in two ways:</p>
<ol>
<li>
<p>The first one, is practically real-time: The hub that receives a message uses a protocol called gossipsub and sends the message to the hubs it's connected to, then they do the same and in just a few seconds all hubs have received the message.</p>
</li>
<li>
<p>The second is an out-of-band sync. This one is slower and only happens every few minutes (or whenever it's feasible, more on this later). During the out-of-band sync, two hubs practically compare their databases, and exchange deltas in order to get to the same status (exchange deltas to reach the same state).</p>
</li>
</ol>
<p>If you are interested, <a href="https://www.youtube.com/watch?v=Uqga87HWs_g">there is a video describing the concept in more detail</a>.</p>
<h2>Advantages</h2>
<p>This model has a number of advantages:</p>
<ul>
<li>It's developer friendly, because a developer can have a full copy of the network, locally, to work with</li>
<li>It's decentralized and censorship resistant because there's no single point of entry to the network</li>
<li>It's very resilient because you can take away any number of hubs (a recent count of Farcaster hubs brings them to ~150) and if there is at least one left, spawn new ones and reconstruct the network as if nothing happened.</li>
</ul>
<p>These characteristics make Farcaster ideal for a number of environments where other social networks (centralized or federated) would fail.</p>
<h2>When the office ISP went down</h2>
<p>Imagine you are at work, using Farcaster by connecting to the office Farcaster hub that runs locally, and you are using a Farcaster client that connects directly to the hub <sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup>. At some point, your ISP goes down.</p>
<p>Here is what happens during the period you have lost connection to the rest of the Internet:</p>
<ol>
<li>
<p>You continue to have access to everything that was posted on Farcaster up to the moment the Internet connection went down.</p>
</li>
<li>
<p>You can also cast, like, recast, follow and unfollow as if nothing changed.</p>
</li>
<li>
<p>You can also see new casts and reactions from your colleagues that use the same hub, and you can reply and react to their casts.</p>
</li>
</ol>
<p>The most important thing that changes during the period the ISP is down, is that you don't see any activity that happens outside your office (your office farcaster hub). But as soon as the ISP is up again, your hub will connect to the other hubs, it will propagate any activity that happened (in the office) during downtime, and receive all activity that happened outside your hub!</p>
<p>There are a few things that wouldn't work while the ISP is down:</p>
<ol>
<li>
<p>Any Farcaster activity that requires an onchain transaction, such as creating new accounts, approving and removing signers, or purchasing storage units.</p>
</li>
<li>
<p>Of course, any content referenced or embedded in casts will not be available, such as images -but that's not Farcaster's problem and if someone really wanted to, they could fix it by using a caching proxy or something similar.</p>
</li>
</ol>
<h2>Social media on the Mars colony</h2>
<p>One of the challenges a crew of a future the Mars colony will have to overcome is staying connected with Earth. Radio signals take 4-22 minutes to get from Earth to Mars, and it will take as much for a response to come back. There's not much we can do about this, unless we find a way for the radio signals to travel faster than light.</p>
<p>One more problem is that the available bandwidth is nothing compared to what we are used on terrestrial communications. I expect that all available bandwidth, will be used to support the operations of the station, and to exchange asynchronous messages between the station crew and Earth command center and their families.</p>
<p>One thing is for sure: The Mars crew will not be able to use X/Twitter, because it's built on HTTP, a synchronous protocol. However, <strong>our astronauts could use Farcaster!</strong></p>
<p>An other cool thing is that Earth-March syncing could also be performed entirely off-line: Every mission to Mars could also carry a Earth-synced hub, that would sync with Mars when it gets there and every mission from Mars to Earth could carry the Mars state back to Earth.</p>
<p>Astronauts will have full access to everything discussed on Farcaster on Earth, interact between them, share their thoughts, and when their hub syncs with Earth, we will all be able to see their activity, react to it, etc., and vice versa.</p>
<p>We may have <a href="https://github.com/farcasterxyz/protocol/discussions">to create an FIP</a> to introduce some small changes to support the Mars colony use case, but I'm optimistic that space settlers count as qDAUs and it will get the full support of the devs.</p>
<p>So, yes: <strong>Farcaster is a better match for SpaceX than X!</strong></p>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>A small note on Farcaster clients connecting directly to hubs. Today, most Farcaster clients depend on a backend hosted by the developer or a third party. These backends take a lot of the load that otherwise a client would have to do, like hosting a database that can be easily queried. These clients will not work without connection to this backend. However, it's 100% feasible to create a client that connects directly to a Farcaster hub, or even have a local installation of the backend required. <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/12/20/farcaster-is-a-better-match-for-spacex-than-x/mars2.png"
   type="image/png"
   length="2225576"/>

    </item>
    
    <item>
      <title>All about Farcaster Signers
</title>
      <link>https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/</guid>
      <pubDate>Sat, 25 Nov 2023 07:31:50 +0200</pubDate>
      <description>Most users know "Signers" as "this thing you have to pay for when you connect a new app". One of the first articles in Purple Sumbarine, was about Farcaster Signers, but my understanding has evolved since then, and we also have new tools and advances since then.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/signers.png">
        
	<p>Most users know &quot;Signers&quot; as &quot;this thing you have to pay for when you connect a new app&quot;. <a href="https://paragraph.xyz/@purplesubmarine/farcaster-signers">One of the first articles in Purple Sumbarine, was about Farcaster Signers</a>, but my understanding has evolved since then, and we also have new tools and advances since then.</p>
<p>In order to understand signers, you have to keep in mind that all interactions with hubs take place by sending hubs a &quot;message&quot; that has a specific structure. So, when you cast, like, or recast, the app you are using sends a message to a hub saying &quot;@vrypan.eth casted Hello World&quot;, or &quot;@vrypan.eth liked this cast&quot;.</p>
<p>Messages look something like this under the hood:</p>
<p><figure><img src="https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/screenshot1.png" alt="" /></figure></p>
<p>As you can see such messages have two parts.</p>
<ul>
<li>
<p>The data part: this is more or less what we usually consider the content, like the text of the cast, the date it was casted, the user who casted.</p>
</li>
<li>
<p>The metadata part which has a hash of the data, a digital signature of the hash, and the key that produced the signature: <strong>the signer</strong>.</p>
</li>
</ul>
<p>(What you see in the signer filed is not the actual signer, but the public key of the signer.)</p>
<h2>Why we need signers</h2>
<p>In a centralized network such as twitter or facebook, you usually have a username and a password. You use your credentials to connect to a server, and then the server knows that you are who your credentials say you are. There is no other way to post something to the service, and the centralized server is the absolute authority of what was posted by whom.</p>
<p>Farcaster is an open, p2p network. Anyone with some technical knowledge can create a program that sends messages to the Farcaster network. The only way to verify the authenticity of these messages, is by their digital signature.</p>
<p>Each Farcaster user has their own keypair, a private and a public key. If you signed up using Warpcast, your recovery phrase can be used to generate this pair. This keypair also corresponds to an ethereum address, what is often called in Farcaster the custody wallet.</p>
<p>So, you could actually sign your messages using your private key. But users rarely create these messages on their computer using a program they wrote. They connect to a service or app, like buidler and after authenticating with it, it posts on their behalf. The problem is you don't want to give them your private key. This would be the equivalent of giving a gmail integration your username and password (and to some extent, not even being able to change the password).</p>
<p>Here is where Farcaster Signers come to play: Instead of giving an app your private key, the app creates a new random key, and asks you to approve it. You approve it using your private key and you register your approval onchain (<strong>gas cost!</strong>). From this point on, any hub that receives a message signed by this Signer, can check the blockchain to verify that you have approved the signer and accept it as authentic.</p>
<h2>Warpcast and meta-transactions</h2>
<p>When you make a call to a smart contract, the caller has to pay the gas for its execution. This is why adding or revoking a signer (onchain transactions) have a cost.</p>
<p>Normally, your Farcaster custody wallet would need to have some OP ETH to perform these transactions.</p>
<p>But wait. There's a workaround: KeyGateway, the smart contract used to approve Signers, allows meta-transactions. You can think of meta-transactions like this:</p>
<ul>
<li>
<p>The user who wants to perform a transaction signs the transaction or an authorization to perform the transaction using his wallet. This is an offline action.</p>
</li>
<li>
<p>The signed transaction is not sent to the smart contract, but it is shared offchain with a third party, usually called the &quot;relayer&quot;.</p>
</li>
<li>
<p>The relayer performs the transaction and pays the required gas.</p>
</li>
</ul>
<p>Warpcast takes advantage of this feature to hide the added complexity of using a blockchain: It will ask the user to pay them $1, and then they use a meta-transaction and they pay for the gas.</p>
<p>This is roughly the equivalent of them saying <em>&quot;Just sign this paper, give me $1, and I'll take care of the rest.&quot;</em></p>
<p>The actual gas cost for adding and removing signers is usually well bellow $1. Warpcast now allows users to also pay using Warps, an in-app credit system: You can buy 500 Wraps for $5, and approving a signer will usually cost around 40-50 Warps (depending on gas cost at the time of the transaction).</p>
<p>(Warps are an interesting experiment that deserve a separate article.)</p>
<h2>Revoking a signer</h2>
<p>Obviously, a user must be able to revoke a signer, and they can do so using their private key and posting the revokation onchain to let everyone know that the signer is no longer authorized to act on their behalf. This was the whole point of not giving away our private key in the first place.</p>
<p>But, when a signer is revoked, hubs see messages that are no longer signed by a valid signer. Most people's first thought is OK, but these are old messages signed when the signer was valid. But you have to keep in mind that Farcaster is an open, p2p network. Hubs are added and removed all the time. You could spin up your hub right now (it's actually quite easy) and your hub would receive messages from other hubs it discovers in order to get its history (aka state) up to date. How can your newly created hub know when a message was signed?</p>
<p>This is why hubs have a simple way of &quot;thinking&quot;: not a valid signer, not a valid message. And, as a result, <strong>when you revoke a Signer, all messages signed using it, are pruned by hubs!</strong></p>
<p>This looks bad. The truth is there is a simple solution that no app (to my knowledge) has implemented (yet). Remember the message example we used earlier? What if you signed the same message with a different signer?</p>
<p><figure><img src="https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/screenshot2.png" alt="" /></figure></p>
<p>Signing the message with new signer will create a new signature, but the message data and the message hash will stay the same: Same user (fid), same content, same timestamp.</p>
<ul>
<li>
<p>To any client, this new, re-signed message is the same as the original one.</p>
</li>
<li>
<p>To any hub, this is a valid message, provided that the original (same hash) is not in the hub's database.</p>
</li>
</ul>
<p>So, an app could:</p>
<ol>
<li>Download all your messages (your Farcaster history)</li>
<li>When you remove a signer, and some messages are pruned, re-sign these messages (from your download) with a new signer.</li>
<li>Post the re-signed messages to a hub.</li>
</ol>
<hr />
<h3>Using fario</h3>
<blockquote>
<p>You can perform the above steps using <a href="https://github.com/vrypan/fario">https://github.com/vrypan/fario</a> if you are comfortable working in the command line. You will have to:</p>
</blockquote>
<blockquote>
<p>Backup your data using <code>fario-out --all</code>.</p>
</blockquote>
<blockquote>
<p>Use <code>fario-grep</code> to select the records signed by the signer you want to remove.</p>
</blockquote>
<blockquote>
<p>Remove the signer using <code>fario-signers remove</code> and create a new signer using <code>fario-signers add</code></p>
</blockquote>
<blockquote>
<p>Re-sign the messages using <code>fario-signers sign</code></p>
</blockquote>
<blockquote>
<p>Upload the re-signed messages using <code>fario-in</code></p>
</blockquote>
<h2>Final thoughts</h2>
<p>Signers are an elegant approach to delegating permissions. It allows users to easily let an app act on their behalf, but at any point in time, they can revoke this permission.</p>
<p>The lack of a simple, user-friendly app that allows users to revoke a signer without deleting all activity performed using it, is definitely a pain-point looking for solutions: Right now, using a signer means that you are stuck with it, since revoking access will delete any casts, likes, recasts and follows you have performed using it. (Unless you are one of the few users who understand the technical details of Signers, and have the skills to use something like fario or put together a script by yourself.)</p>
<p>Looking forward to try the first apps that will give a user-friendly solution to this!</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/screenshot1.png"
   type="image/png"
   length="429486"/>

   <enclosure url="https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/screenshot2.png"
   type="image/png"
   length="381806"/>

   <enclosure url="https://blog.vrypan.net/2023/11/25/all-about-farcaster-signers/signers.png"
   type="image/png"
   length="1394343"/>

    </item>
    
    <item>
      <title>The Farcaster icon font
</title>
      <link>https://blog.vrypan.net/2023/11/11/farcaster-icon-font/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/11/11/farcaster-icon-font/</guid>
      <pubDate>Sat, 11 Nov 2023 15:08:44 +0200</pubDate>
      <description>I wanted to use the farcaster icon, just like other app icons in my web pages.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2023/11/11/farcaster-icon-font/screenshot.png">
        
	<p>I wanted to use the farcaster icon, just like other app icons in my web pages.</p>
<p>For example, at the top of this page, you see a twitter icon. This icon is displayed
by using Font Awesome<sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup> and then something like <code>&lt;i class=&quot;fa-brands fa-twitter&quot;&gt;&lt;/i&gt;</code>.
In this case, the icon is a font character, which means it scales with the rest of the text,
it changes color with the rest of the text, and so on.</p>
<p>I wanted something similar for Farcaster.</p>
<p>So, I converted the Farcaster logo outline to SVG using Pixelmator<sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup>, and the used Icomoon<sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>3</a></sup>
to turn it into a web font. Then, I manually cleaned up the result, and added some instructions
on how to use it.</p>
<p>You can find the result at <a href="https://github.com/vrypan/fc-font">github.com/vrypan/fc-font</a>.</p>
<p>After downloading the files, you use something like</p>
<pre><code>&lt;link rel=&quot;stylesheet&quot; href=&quot;farcaster/style.css&quot;&gt;
</code></pre>
<p>and then you can use the icon:</p>
<pre><code>&lt;i class=&quot;fc fc-farcaster&quot;&gt;&lt;/i&gt;
&lt;i class=&quot;fc fc-square-farcaster&quot;&gt;&lt;/i&gt;
</code></pre>
<p>and you'll get something like this:</p>
<div class="fc" style="font-size:40px;">π Π</div>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p><a href="https://fontawesome.com">fontawesome.com</a> <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p><a href="https://www.pixelmator.com/pro/">Pixelmator Pro</a> is a great design tool for macOS. <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-3">
<p><a href="https://icomoon.io">Icomoon</a> <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/11/11/farcaster-icon-font/screenshot.png"
   type="image/png"
   length="29373"/>

    </item>
    
    <item>
      <title>Welcome to farcaster</title>
      <link>https://blog.vrypan.net/2023/10/11/welcome-to-farcaster/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/10/11/welcome-to-farcaster/</guid>
      <pubDate>Wed, 11 Oct 2023 17:56:25 +0200</pubDate>
      <description>Farcaster is a lot like and a lot unlike other social networks. There's so much to learn and explore, but if you are new, this article will help you find your way around.</description>
      <content:encoded><![CDATA[
	
	<h2>I originally published this post on <a href="https://paragraph.xyz/@purplesubmarine">Purple Submarine</a>, a newsletter
about Farcaster. But I think it can be of help to anyone interested in Farcaster.</h2>
<blockquote>
<p>On October 11, 2023, Farcaster opened its doors to everyone
(<a href="https://danromero.org/farcaster-permissionless/">a.k.a &quot;went permissionless&quot;</a>).</p>
</blockquote>
<p>Farcaster is a lot like and a lot unlike other social networks. There's so much to learn and explore, but if you are new, this article will help you find your way around.</p>
<h2>Warpcast is to Farcaster, what Firefox is to Web</h2>
<p><a href="https://www.farcaster.xyz/">Farcaster</a> is a protocol, and <a href="https://warpcast.com/">Warpcast</a> is a Farcaster client,
much like Firefox, Chrome, Safari and Edge are HTTP clients. There are many other clients and applications.
You can find an (incomplete!) <a href="https://www.farcaster.xyz/apps">list of applications that use Farcaster here</a>.</p>
<blockquote>
<p>If you don't have a Farcaster account, the simplest way to create one is to install Warpcast.</p>
</blockquote>
<h2>You own your Farcaster identity.</h2>
<p>Everything you do on Farcaster (casts, likes, recasts, follows, etc.) is tied to your Farcaster Identity (fid). No one can take away, suspend or cancel your Farcaster identity: it is controlled by an Ethereum address only you have the keys for. Don't worry, if you loose your keys,
<a href="https://paragraph.xyz/@purplesubmarine/farcaster-account-recovery">there is a way to recover your identity</a>.</p>
<h2>Open, Decentralized</h2>
<p><strong>Farcaster is an open protocol.</strong> This means than anyone can build applications on top of it, without asking permission and without paying fees. Compare this to using Facebook, Twitter/X, or Reddit APIs: Each one of these companies has changed policies, requirements and pricing, often pulling the rug under developers' feet.</p>
<p><strong>Farcaster is decentralized.</strong> At the core of Farcaster are the Farcaster hubs. Every hub keeps a complete copy of everything there is on Farcaster. Hubs talk to each other and sync their status to reach consensus. Anyone can run a hub. If you like experimenting, you can run your own hub, even from your home (hardware requirements are minimal, your previous PC or laptop is probably more than adequate).</p>
<h2>Why do I have to pay?</h2>
<p><strong>Because there is no Twitter or Facebook to pay the costs.</strong></p>
<p>In exchange, you own your Farcaster identity, data and network.</p>
<p>There are two costs to using Farcaster.</p>
<p>Storage space on hubs. For most users, this will be a cost between $0.6/month and $1/month, depending on the payment method. The easiest way to pay is through Warpcast's in-app purchase ($12/year including AppStore fees and USD-to-ETH conversion). But you can also use a service like caststorage.com, pay in ETH and avoid the AppStore tax.</p>
<p>Both methods bellow, will have the same result. Warpcast purchases are converted to ETH and used to perform the onchain transaction.
<figure><img src="https://blog.vrypan.net/2023/10/11/welcome-to-farcaster/farcaster-storage.png" alt="" /></figure></p>
<p><strong>The cost of identity-related transactions</strong> (remember, your Farcaster identity &quot;lives&quot; onchain, and onchain transactions have a small cost), such as the initial signup or giving permissions to apps. This cost is small, and in some cases apps may pay it on your behalf to make your life easier, but occasionally you may be asked to pay something like $0.99 (the actual cost is much less, and there will be ways and tools to pay much less in the future).</p>
<h2>Where can I learn more?</h2>
<ol>
<li><a href="http://farcaster.xyz/">farcaster.xyz</a> is the home of the Farcaster protocol.</li>
<li><a href="http://thehubble.xyz/">thehubble.xyz</a> is Hubble's homepage. Hubble is the software run by Farcaster nodes.</li>
<li><a href="https://www.youtube.com/watch?v=vMWjol6xHJ0&amp;list=PL0eq1PLf6eUdm35v_840EGLXkVJDhxhcF">Farcaster Overview</a>:
short videos explaining the core concepts of Farcaster. (Keep in mind that the videos were created some time ago,
and some of the details may have changed through <a href="https://docs.farcaster.xyz/protocol/fips.html">Farcaster Improvement Proposals</a>.)</li>
<li>Check out the articles on <a href="https://paragraph.xyz/@purplesubmarine">Purple Submarine</a>.</li>
</ol>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/10/11/welcome-to-farcaster/farcaster-storage.png"
   type="image/png"
   length="339882"/>

    </item>
    
    <item>
      <title>Farcaster account recovery
</title>
      <link>https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/</guid>
      <pubDate>Fri, 06 Oct 2023 10:26:13 +0200</pubDate>
      <description>Varun has created a video that explains everything in a very simple way:</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/header.png">
        
	<h2>How it works</h2>
<p>Varun has created a video that explains everything in a very simple way:</p>
<p><a href="https://youtu.be/DnAG4mXlOFI?si=kauG-qhvJ5FkI9xo"><figure><img src="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/varun-account-recovery.png" alt="youtube video" /></figure></a></p>
<ul>
<li>Every Farcaster account is owned by an Ethereum address (often called “wallet”).</li>
<li>Every Farcaster account can also set a <strong>recovery address</strong>. The only thing the recovery address can do is to move your Farcaster account to a new address.</li>
</ul>
<p>Moving your account to a new address is quite a power to give to someone. The owner of the recovery address can save you if you lost your “secret phrase” (think of it as your password), by moving your account to a new address you control. But if they go rogue, or get hacked, they can also steal your Farcaster account!</p>
<p><figure><img src="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/recovery.gif" alt="demo" /></figure></p>
<hr />
<h2>Failsafe, no failsafe</h2>
<p>If you watched the above video, you may have noticed that there was a fail-safe: Between the initiation of the account transfer and the actual transfer there was a <strong>5-day delay</strong> during which you could cancel it and even change/revoke the recovery address.</p>
<p>I’m writing in the past tense because this fail-safe was removed by <strong><a href="https://github.com/farcasterxyz/protocol/discussions/100">FIP-5: Instant Recovery</a></strong>: The recovery address can now instantly move your account to a new address and there’s nothing you can do about it.</p>
<p>While this may seem a bad thing, it’s not that bad, and there’s good reasoning behind it:</p>
<ol>
<li>99 % of the users, especially new users that will join once signups are open for everyone, are used to Web2 platforms: <em>I lost my password, I use my email to recover it.</em></li>
<li>When a new user signs up, <strong>Warpcast</strong> (that most of them will use to sign up) sets the recovery address to one Warpcast controls. This way they can hide the complexity from users, and provide them with what most users expect: Being able to instantly help them recover their account.</li>
</ol>
<p><figure><img src="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/casts.png" alt="casts screenshot" /></figure>
<a href="https://warpcast.com/dwr.eth/0x7137eced">https://warpcast.com/dwr.eth/0x7137eced</a></p>
<hr />
<h2>Where did decentralization go?</h2>
<p>If you are here because of the Web3 ethos, decentralization and sovereignty, you’re probably disappointed. What I just described is a way for a centralized entity (Warpcast) to take away your decentralized Farcaster identity. If that’s the case, what’s the point of all the decentralization, web3 and the costs that come with them?</p>
<p>There are a couple of good answers.</p>
<ul>
<li>First of all, you can set your <strong>own recovery address</strong>: You can use another address you control, a good friend’s address you trust, or your lawyer’s Ethereum address (yes, there are some that know what this is).</li>
<li>You could also set it to an <strong>M-of-N multisig wallet</strong>, controlled by N people you trust.</li>
<li>I can also imagine more exotic implementations of a recovery address.
<ul>
<li>For example, all Farcaster accounts a company uses can have a recovery address controlled by their IT, which has a dual purpose:
<ol>
<li>Being able to support users who lost their secret phrase</li>
<li>Being able to take away a corporate account.</li>
</ol>
</li>
<li>Or a smart contract that implements the time-delay feature removed by FIP-5.</li>
<li>Or even create a valet service that users pay annually and in order to recover their account, users have to do a video call, prove their identity, and then the service helps them recover their account.</li>
</ul>
</li>
</ul>
<hr />
<h2>Takeaways</h2>
<ol>
<li>
<p>If you sign up to Farcaster using Warpcast, Warpcast can recover your account if you lose your keys, but they can also take away your account, or be compelled to do so. Keep this in mind if you think that someone may want to censor you in the future.</p>
</li>
<li>
<p>If you are an experienced Web3 user, you may want to consider some of the options mentioned above, like setting the recovery address to one controlled by your hardware wallet, or a multisig.</p>
</li>
<li>
<p>There is a wide range of services to be built that help users recover their Farcaster accounts. You may want to build one of them.</p>
</li>
</ol>
<hr />

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/casts.png"
   type="image/png"
   length="859572"/>

   <enclosure url="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/header.png"
   type="image/png"
   length="1028011"/>

   <enclosure url="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/recovery.gif"
   type="image/gif"
   length="3506566"/>

   <enclosure url="https://blog.vrypan.net/2023/10/06/farcaster-account-recovery/varun-account-recovery.png"
   type="image/png"
   length="927761"/>

    </item>
    
    <item>
      <title>Goodbye, Twitter
</title>
      <link>https://blog.vrypan.net/2023/08/14/goodbye-twitter/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/08/14/goodbye-twitter/</guid>
      <pubDate>Mon, 14 Aug 2023 21:28:58 +0200</pubDate>
      <description>Twitter is now X.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2023/08/14/goodbye-twitter/twitter-x.jpg">
        
	<p>Twitter is now X.</p>
<p>&quot;Ex&quot;, &quot;ten&quot;, &quot;ex-twitter&quot;, or &quot;the service formerly known as Twitter&quot;, it doesn't matter much. What matters (to me), is that this feels like the end of an era —from now on, it will be something else.</p>
<p>I feel that there is a whole Internet generation with a special place for Twitter in our hearts.</p>
<p>I signed up for twitter in December 2006. This was the time when the first wave of podcasting was getting traction. This was the time of Dave Winer's <em>Morning Coffee Notes</em> and Adam Curry's <em>Daily Source Code</em> (<em>&quot;we don't need no stinking transmitters!&quot;</em>) which was my inspiration for my own podcast.</p>
<p>Much like every other podcaster at the time, I was trying to understand how this new format works, and I was eager to try every new tool and service that promised to make podcasting better. One of them was <a href="https://en.wikipedia.org/wiki/Odeo"><em>ODEO</em></a>. I loved Odeo, and the people behind it, the co-founders of Pyra Labs, Noah Glass and Evan Williams, made it even more special to may eyes. Pyra Labs was the company that built blogger.com which is fair to say that made blogging accessible to everyone and transformed the Web from a read-only medium to read-write one for most.</p>
<p>In 2006, Odeo (actually Obvious Corp, the company that was formed to hold Odeo and other products the team would develop) launched Twitter, and since I was following what Odeo and Ev were doing, I had to try it. I was user #74233.</p>
<blockquote>
<p><figure><img src="https://blog.vrypan.net/2023/08/14/goodbye-twitter/Twttr_sketch-Dorsey-2006.jpg" alt="" /></figure></p>
</blockquote>
<blockquote>
<p>A sketch, c. 2006, by Jack Dorsey, envisioning an SMS-based social network <sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup></p>
</blockquote>
<p>For a few years, Twitter was a public place where &quot;Internet geeks&quot; would &quot;gather&quot;. The Internet was much smaller than today (not small, but much smaller), and the first Twitter users were the people we already knew from blogs and podcasts. The most followed accounts were not brands, politicians or pop stars, but bloggers, podcasters, developers and tech entrepreneurs.</p>
<p>To me, and I think for many people like me at the time, twitter's appeal was twofold:</p>
<ol>
<li>It was an open system, with a simple, open API, true to the ideas of Web2.0 at the time: A service we could integrate with our own services, write scripts for, build tools and applications on top of.</li>
<li>I did not have to find a title for my content. Before Twitter, &quot;publishing to the web&quot;, was synonymous to blog posting and blog posts have titles which add a huge overhead when you want to write something casual —it just did not feel right to have blog post containing a single sentence and find a title for it. Blogs were not designed with this &quot;casual posting&quot; in mind, and Twitter's simplicity was liberating.</li>
</ol>
<hr />
<p>Twitter was home of many innovations and some of them originated came from their users.</p>
<p>It introduced the <code>@username</code> namespace. Until then, you either had a username or an email. The <code>@username</code> namespace is still a huge part of Twitter's brand equity.</p>
<p>The (initially small) scale allowed for features that have long been gone. Like the <code>track</code> command: You could tweet <code>track pizza</code> and you would get notified whenever someone posted a tweet containing the word <em>pizza</em>. You could also use it to track usernames, which allowed you to get all mentions of a specific username.</p>
<p>There was no &quot;retweet&quot;: Users would copy paste a tweet and add <code>rt @username</code> in front of it (<a href="https://twitter.com/vrypan/status/1058909119?tw_i=1058909119&amp;tw_e=details&amp;tw_p=archive">like this</a>). Which meant that if you wanted your tweet to be retweeted with credit, you had to make sure there was enough space to add <code>rt @yourusername</code> and still be under the 140 characters limit —and short usernames had a nice advantage.</p>
<p>And there were no hashtags. Hashtags were <a href="https://buffer.com/resources/a-concise-history-of-twitter-hashtags-and-how-you-should-use-them-properly/">Chris Messina's &quot;invention&quot;</a> that were later adopted by Twitter.</p>
<p>Oh, and there was also a SMS gateway. (Remember, in 2006 the iPhone was not yet released.) So you could text 40404 (if you were in the US) with your tweet, and get SMS notifications when people you followed tweeted.</p>
<p>We also had &quot;FF&quot;, for &quot;Follow Friday&quot;: Every Friday, we would tweet <code>FF:</code> followed by usernames that posted interesting content, to help them be discovered by other users.</p>
<p>Twitter also popularised &quot;URL shorteners&quot;: Shortening a long link left you more characters to write your comment (and in some cases, it was the only way to make a link fit in 140 characters).</p>
<p>It was the first social network that grew to scale. The problem with scaling a social network with x users (the algebraic symbol as in <em>x+y</em>, not as in &quot;ex-twitter&quot;...) who follow one another is that complexity grows exponentially. So, after a point twitter would go down. And we would get the <a href="https://www.theatlantic.com/technology/archive/2015/01/the-story-behind-twitters-fail-whale/384313/">Fail Whale</a>.</p>
<p><figure><img src="https://blog.vrypan.net/2023/08/14/goodbye-twitter/failwhale.png" alt="Fail Whale screenshot" /></figure></p>
<hr />
<p>Since then, Twitter grew in scale, solved their technical issues, closed their API, integrated organically hashtags and retweets, expanded beyond 140 characters. A wider audience joined. It became a place for political debate, public discourse, and civic mobilisation, a customer relationships management tool, a sales channel, the breaking news channel. Internet hackers and geeks were hugely outnumbered by celebrities, politicians and their followers together with armies of bots and anonymous (and sometimes, professional) haters.</p>
<p>All this is not good or bad. I've been part of some of these changes, I ran political campaigns using Twitter, I advised companies on how to leverage twitter as a CRM tool, I promoted my work, I joined polarised conversations and received my share of anonymous hate. Things change. It just is what it is.</p>
<p>My original intention was to end this post by saying that Elon killed Twitter. But the Twitter I have in mind has long been gone. I guess that changing the name when everything else has already changed is an honest decision, after all.</p>
<p>(A delayed) <strong>Goodbye, Twitter and thank you for the memories.</strong></p>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p>Source <a href="https://en.wikipedia.org/wiki/Twitter">Wikipedia</a> <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/08/14/goodbye-twitter/Twttr_sketch-Dorsey-2006.jpg"
   type="image/jpeg"
   length="96013"/>

   <enclosure url="https://blog.vrypan.net/2023/08/14/goodbye-twitter/failwhale.png"
   type="image/png"
   length="120217"/>

   <enclosure url="https://blog.vrypan.net/2023/08/14/goodbye-twitter/twitter-x.jpg"
   type="image/jpeg"
   length="76152"/>

    </item>
    
    <item>
      <title>VisionPro's EyeSight may be a killer feature.
</title>
      <link>https://blog.vrypan.net/2023/06/06/visionpro-eyesight-is-a-killer-feature/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2023/06/06/visionpro-eyesight-is-a-killer-feature/</guid>
      <pubDate>Tue, 06 Jun 2023 10:26:13 +0200</pubDate>
      <description>Based on what was presented yesterday at WWDC, VisionPro is an amazing product. But what I'm really fascinated about is EyeSight. Here is why.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2023/06/06/visionpro-eyesight-is-a-killer-feature/eyesight-plain.png">
        
	<p>Based on what was presented yesterday at WWDC, <a href="https://www.apple.com/apple-vision-pro/">VisionPro is an amazing product</a>. But what I'm really fascinated about is EyeSight. Here is why.</p>
<p>EyeSight is an outward display. It's (intended? initial?) use will be to display your eyes while you are wearing the VisionPro in order to let people around you know if you're looking at them, or at someone else, or if you are immersed in an experience on your own.</p>
<p>This is obviously very important, because it retains the communication bandwidth provided by facial expressions. We all know that eyes and eye contact are an important, high-bandwidth communication channel for humans.</p>
<p><em>&quot;I saw it in her eyes&quot;, &quot;Eyes don't lie&quot;, &quot;Let the eyes do the talking&quot;</em> —others have said it better than me.</p>
<p>But I have the feeling that EyeSight can be more than this. In addition to preserving the existing communication bandwidth, it may also increase it! If Apple allows it, I can see a future where the outward display shows more than your eyes.</p>
<p>Imagine being able to do some hand gesture, or even eye gesture, like blinking your eyes in a specific way that change the display, and show emojis (I'm really bad at design, I'm sure any designer could make these look much better). Or even animations like fireworks or any animated meme gif!</p>
<p><figure><img src="https://blog.vrypan.net/2023/06/06/visionpro-eyesight-is-a-killer-feature/eyesight-emojis.png" alt="" /></figure></p>
<p>I know that the idea may sound silly to many, but there is a generation of people who are really good at communicating ideas and feelings using visual clues when they are in front of their keyboard but have no way of doing it IRL. (Just visit any discord server.) Being able to express themselves IRL, with images that are displayed exactly where the person they are talking to is looking can be a killer feature.</p>
<p>And the most interesting part is that if this turns out to be a killer feature, it's one that will drive adoption because it has built-in virality: when I use it, other people see how cool it is and they want it too.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2023/06/06/visionpro-eyesight-is-a-killer-feature/eyesight-emojis.png"
   type="image/png"
   length="1096889"/>

   <enclosure url="https://blog.vrypan.net/2023/06/06/visionpro-eyesight-is-a-killer-feature/eyesight-plain.png"
   type="image/png"
   length="998448"/>

    </item>
    
    <item>
      <title>The dangerous path of OpenSea's blacklisting tool
</title>
      <link>https://blog.vrypan.net/2022/11/08/the-dangerous-path-of-opensea-blacklisting-tool/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2022/11/08/the-dangerous-path-of-opensea-blacklisting-tool/</guid>
      <pubDate>Tue, 08 Nov 2022 01:06:02 +0200</pubDate>
      <description>So, OpenSea announced they are releasing a tool "that allows creators to enforce fees on chain". Here's why this tool is much more, and why it's scary.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2022/11/08/the-dangerous-path-of-opensea-blacklisting-tool/opensea.png">
        
	<p>So, OpenSea announced they are releasing a tool <em>&quot;that allows creators to enforce fees on chain&quot;</em><sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup>. Here's why this tool is much more, and why it's scary.</p>
<h2>How it works</h2>
<p>OpenSea offers a solidity library that creators can include in their NFT contracts. This library allows a creator to blacklist an address (the address of a marketplace) from being able to list and trade their NFTs. So, I can only sell the NFT at a marketplace <strong>only</strong> if it is not a blacklisted one.</p>
<p>@0xCygaar has a great in-depth analysis of the details on twitter. <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup></p>
<h2>Subscription lists</h2>
<p>Now, 99.99% of the creators do not know how to identify the addresses (and contract hashes, an other check provided), but OpenSea offers a solution for them: they can subscribe to a blacklist maintained by someone else who knows how to do these things and is willing to spend the time to maintain the list up to date as marketplaces deploy new contracts, they change their policies on royalties, new ones are launched and so on.</p>
<h2>The scary part</h2>
<p>This all sounds great. As a creator, I can block marketplaces and services that allow users to trade my NFTs without paying royalties, how cool is this. And I don't have to do much, my smart contract is subscribed to the OpenSea's blaclist and they make sure they update it.
Of course I could subscribe to a blacklist mainteined by someone else, but why bother, I know OpenSea, they are the experts.</p>
<p>Wait.</p>
<p>This is great until a government asks all marketplaces to implement something. KYC for example. And then demands from OpenSea to add the ones that did not comply to their blacklist.</p>
<p>Or until OpenSea has a dispute with an other marketplace over something. Over copyrights, over patents, over policies. Businesses get into these debates every day. And OpenSea decides to add this marketplace to their blacklist.</p>
<p>I can think of many scenarios where something like this happens. And I can see the competing marketplace trying to reach out to creators and explain to them with detailed hoots and videos how to use etherscan to go to the contract code and sign a transactions to unsubscribe from OpenSea's blacklist. Which most won't do, because it will seem scary, complicated, and in any case, <em>&quot;why go through all this if 90% of their sales are on OpenSea, anyway&quot;</em>?</p>
<p>I can also see how this could lead to a place where no one even tries to launch an other marketplace, because OpenSea has all the power: They have
the biggest share of the market, they are deeply integrated with the ecosystem, and if everything else fails they can find a reason to blacklist
competitors.</p>
<p>OpenSea will probably swear: <em>&quot;We would never do something like this!&quot;</em></p>
<p>But remember? We created crypto and web3 because we did not want to rely on promisses, we wanted the rules to be written in code.</p>
<h2>It's the email story, all over again.</h2>
<p>A couple of days ago, Jameson Lopp published a great article<sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>3</a></sup> explaining how email started as a completely decentralised protocol and ended up being one where 90% of email users are captured by 5 companies.</p>
<blockquote>
<p><em>It is said that those who do not learn from history are doomed to repeat it. I believe it is of utmost importance that proponents of decentralized protocols learn from the failures of those that have come before. The following is a review of 40 years of history for the protocol that is the foundation of email.</em></p>
</blockquote>
<p>It's amazing how we are about to do the same mistakes all over again.</p>
<p>What OpenSea released is not a royalties protection system. It's a blacklisting infrastructure. Yes, it can be used by creators to protect their royalties. This is how these types of centralised control have always been introduced: to protect us from &quot;something bad&quot;.</p>
<p>But what they are actually asking is to give up control, and give them more power.</p>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p><a href="https://opensea.io/blog/announcements/on-creator-fees/">On Creator Fees</a> <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p><a href="https://twitter.com/0xCygaar/status/1589309374060957696">@0xCygaar's twitter thread</a> <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-3">
<p><a href="https://blog.lopp.net/death-of-decentralized-email/">The Death of Decentralized Email
</a> <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2022/11/08/the-dangerous-path-of-opensea-blacklisting-tool/opensea.png"
   type="image/png"
   length="2496441"/>

    </item>
    
    <item>
      <title>ERC721 Subset
</title>
      <link>https://blog.vrypan.net/2022/11/06/erc721-subset/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2022/11/06/erc721-subset/</guid>
      <pubDate>Sun, 06 Nov 2022 08:20:30 +0200</pubDate>
      <description>This is about a small ERC721 contract I wrote, but let me give you the context first.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2022/11/06/erc721-subset/opensea.png">
        
	<p>This is about a small ERC721 contract I wrote, but let me give you the context first.</p>
<p>I think of NFTs as a new data pointer. Much like filesystems (file path + file name), and URLs (protocol + server + path + filename), NFTs (contract address + item Id) provide us with a way to point to data.</p>
<p>If you think of an ERC721 contract as a bucket of &quot;files&quot;, we have developed ways to present, query and organise these &quot;files&quot;: We can refer to a specific one by Id, but we also have tools like NFT marketplaces that allow us to filter by trait.</p>
<p>The problem is that filtering by trait is based on the decisions that the smart contract developer did: If the contract creator added a colour trait, we can easily filter by colour for example.</p>
<p>But what if we want to create a different grouping? What if I want to create a way to group together my favourite items of a NFT collection, or the ones that have a characteristic not explicitly described in the NFT metadata? The most common example of this is ENS clubs: .eth domains that follow a pattern that some users find valuable or interesting (all digits, 4 digits, palindromes, English names, Arabic numerals, all emojis, etc.) <strong>We do not have a tool to do this grouping on-chain.</strong></p>
<p>This is where my smart contract comes in. I call it &quot;ERC721 Subset&quot; and I tried to implement it in a way that conforms with the ERC721 standard, but:</p>
<ul>
<li>It does not allow approvals and transfers (all related functions revert with an error.)</li>
<li>All tokens are owned by the contract and (based on the above) can't be transferred or traded.</li>
<li>The contractor needs a ERC721 contract address (the &quot;original collection&quot;) to be passed to.</li>
<li>There is an <code>add(tokenId)</code> and <code>remove(tokenId)</code> that add a token from the original collection to the subset. They are implemented as mint and burn functions to allow services like NFT marketplaces to track the addition and removal of tokens in a way that they understand.</li>
<li>There is an <code>exists(tokenId)</code> function that allows an other service or contract to check if a token is part of the subset.</li>
<li><code>tokenURI(tokenId)</code> is proxied to the function of the original contract, so the sub collection NFT looks exactly like the original one.</li>
</ul>
<hr />
<p>To illustrate how this works, I created an ERC721 Subset of the  <a href="https://onchainbirds.com/">OnChainBirds collection</a> that contains what their community call &quot;greyscales&quot;: These are birds that happen to use only black, white and grey traits. There is no specific trait that describes grayscales, but a user went through the whole collection and identified 17 of them.</p>
<p>So, I deployed A ERC721 Subset called &quot;OnChainBirds: Grayscales&quot;. If you look at the <a href="https://etherscan.io/address/0xe10250464f9a59435705f842e0e5958ba4f2071a">etherscan page of the contract</a>, you will see the contract creation and the <code>add()</code> calls to add the specific token Ids. If you go to <a href="https://opensea.io/collection/onchainbirds-greyscales">the OpenSea page</a> (or any other marketplace) you will get a nice gallery of these tokens.</p>
<hr />
<p>This is a first take on the idea. There are probably ways to make the smart contract more efficient, or more secure or add some features that will make it more useful. It would be nice for example if there was a way to programmatically manifest that this is not a normal ERC721 contract. Or a more efficient way to add multiple items. What are the implications for services (wallets, marketplaces, etc) that deal with ERC721 tokens? Would it make sense to make this an ERC standard?</p>
<p>If you have any suggestions or ideas, ping me <a href="https://twitter.com/vrypan">@vrypan</a>.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2022/11/06/erc721-subset/opensea.png"
   type="image/png"
   length="396992"/>

    </item>
    
    <item>
      <title>Implementing tokenURI as a separate contract
</title>
      <link>https://blog.vrypan.net/2022/05/13/erc721-tokenuri-contract/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2022/05/13/erc721-tokenuri-contract/</guid>
      <pubDate>Fri, 13 May 2022 12:25:06 +0200</pubDate>
      <description>The metadata extension of ERC721 includes tokenURI() that returns the metadata for a specific token ID:</description>
      <content:encoded><![CDATA[
	
	<p>The metadata extension of ERC721 includes <code>tokenURI()</code> that returns the metadata for a specific token ID:</p>
<pre><code>/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x5b5e139f.
interface ERC721Metadata /* is ERC721 */ {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns (string _name);

    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external view returns (string _symbol);

    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the &quot;ERC721
    ///  Metadata JSON Schema&quot;.
    function tokenURI(uint256 _tokenId) external view returns (string);
}
</code></pre>
<p>And the Openzeppelin implementation or ERC721 implements it like this (practically, it returns &quot;baseURI + tokenId&quot;)</p>
<pre><code>    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), &quot;ERC721Metadata: URI query for nonexistent token&quot;);

        string memory baseURI = _baseURI();
        return bytes(baseURI).length &gt; 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : &quot;&quot;;
    }
</code></pre>
<p>For <a href="https://niftywalls.xyz">NiftyWalls</a>, is decided to implement tokenURI as a separate contract.</p>
<p>So, the NiftyWalls implementation looks like more or less this</p>
<pre><code>interface ITokenURI {
    function tokenURI(uint256 tokenId) public view returns (string memory) ;
}

contract NiftyWalls is Ownable, ERC721 {
    address public metadata;
    
...
...

  function tokenURI(uint256 tokenId) public view override(ERC721)returns (string memory) {
    require(_exists(tokenId), &quot;NiftyWalls: URI query for nonexistent token&quot;);
    IToknURI meta = ITokenURI(metadata);
    string memory json = meta.idToJson(tokenId);
    return string(abi.encodePacked(&quot;data:application/json;base64,&quot;, Base64.encode(bytes(json))));
  }
  
...
...

  function setMetadataContract(address _metadata) public onlyOwner {
    metadata = _metadata;
  }
</code></pre>
<p>A very simple implementation of the TokenURI contract would be something like this.</p>
<pre><code>contract TokenURI {
    string private baseURI = 'http://mysite/' ;
    
     function tokenURI(uint256 tokenId) public view returns (string memory) {
        return string(abi.encodePacked(baseURI, tokenId.toString())) ;
    }
}
</code></pre>
<p>The nice thing with this approach is that it allows you to upgrade the TokenURI contract to do interesting things in the future, without touching the NFT contract. For example:</p>
<ul>
<li>You may use <code>setMetadataContract()</code> to &quot;activate&quot; metadata only after all tokens are minted.</li>
<li>Or you could make the TokenURI contract return different metadata after a date or a block number is reached.</li>
<li>Or deploy a new TokenURI contract (and use <code>setMetadataContract()</code> to point your contract to it) that implements on-chain metadata.</li>
<li>Or deploy a new TokenURI contract that holds the metadata on-chain and allows for changes (for example, the owner of a token can change the name of the token).</li>
<li>Or even use on-chain events or an oracle to update metadata.</li>
</ul>
<p>The cost of implementing <code>tokenURI</code> as a separate contract is minimal, and the advantages are significant, so I expect more ERC721 contracts to implement it this way.</p>

]]></content:encoded>

    </item>
    
    <item>
      <title>What's the utility of a pfp NFT collection? Signalling.
</title>
      <link>https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/</guid>
      <pubDate>Wed, 19 Jan 2022 11:10:47 +0200</pubDate>
      <description>Obviously, every individual NFT image can signal something: Good taste, love for retro gaming, girl power, unconventional thinking, etc. But a 10k pfp are becoming brands that signal more than what the design of an individual item can.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/rarity-tools.png">
        
	<p>Obviously, every <em>individual</em> NFT image can signal something: Good taste, love for retro gaming, girl power, unconventional thinking, etc. But a 10k pfp are becoming brands that signal more than what the design of an individual item can.</p>
<p>Using a <a href="https://www.larvalabs.com/cryptopunks">CryptoPunk</a> is a signal by itself –which punk is secondary, especially if you don't own one. CryptoPunks signal OG status, (usually crypto-originating) wealth, someone who can spend 60ETH ($180,000) for a NFT.</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/cryptopunks-screenshot.png" alt="" /></figure></p>
<p>Costing at least 80ETH each ($240,000), <a href="https://boredapeyachtclub.com/#/home">Bored Apes</a> signal &quot;rock-star&quot;. You are part of an exclusive yacht club, only accessible to millionaires. Not the &quot;old money&quot; type, these are degen millionaires, eating pizza, wearing silly hats and having fun at parties.</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/bayc-screenshot.png" alt="" /></figure></p>
<hr />
<p>My personal experience with a couple of other projects:</p>
<p><a href="https://thehashmasks.com">Hashmasks</a> (floor is close to 1ETH, or $3000), <em>&quot;a living digital art collectible created by over 70 artists globally&quot;</em>, signal art. (They focus a lot on their OG status as this was one of the very first PFP NFT projects, but I think that the main signal is art.)</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/hashmasks-screenshot.png" alt="" /></figure></p>
<p>Some of their subcategories have evolved to carry additional signalling. For example, users renamed clown Hashmasks as part of a <a href="https://clownbanks.com/">&quot;banks are clowns&quot;</a> campaign (which btw, seems like a thing a contemporaty art project would address).</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/clown-banks.png" alt="" /></figure></p>
<p>An other project I follow, <a href="https://chubbies.io">Chubbies</a> (floor is about 0.07ETH or $210), created by a single, laid back developer called... solazy, signal geek zen: &quot;no roadmap, no team, no grand vision - just a mission to learn, experiment, and make fun projects&quot;.</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/chubbies-screenshot.png" alt="" /></figure></p>
<p>Solazy writes in the project's discord server:</p>
<blockquote>
<p><em>I want to think of Chubbies as my lifelong project but there's a reason I named myself @solazy.eth. I'm just one person (and sometimes my wife), with a finite amount of time, and many interests. I like the idea of working solo and I put on many hats: backend dev, frontend dev, artist, community manager, marketer, founder etc.</em></p>
</blockquote>
<blockquote>
<p><em>I can't and won't do most of the things you probably expect from other projects. Thus, I've decided to set clear boundaries and expectations for this to be sustainable and fun for me to continue.</em></p>
</blockquote>
<hr />
<p>I think that once we understand that <strong>the main utility of these NFTs is signalling</strong>, projects will start to focus more on their brand identity and brand values and less on other things like &quot;roadmaps&quot; and &quot;utility&quot;.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/bayc-screenshot.png"
   type="image/png"
   length="1254925"/>

   <enclosure url="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/chubbies-screenshot.png"
   type="image/png"
   length="142939"/>

   <enclosure url="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/clown-banks.png"
   type="image/png"
   length="6766301"/>

   <enclosure url="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/cryptopunks-screenshot.png"
   type="image/png"
   length="1197445"/>

   <enclosure url="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/hashmasks-screenshot.png"
   type="image/png"
   length="1894079"/>

   <enclosure url="https://blog.vrypan.net/2022/01/19/10k-pfp-nft-utility-is-signaling/rarity-tools.png"
   type="image/png"
   length="393874"/>

    </item>
    
    <item>
      <title>Putting an old iMac to use
</title>
      <link>https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/</guid>
      <pubDate>Thu, 06 Jan 2022 13:54:11 +0200</pubDate>
      <description>So, I have this old iMac "Early 2009" Aluminum iMac Core 2 Duo. I decided to make something usefull out of it, so I upgraded the RAM to 8GB, replaced the original HDD with 1TB SSD and installed Ubuntu 20.24.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/head.png">
        
	<p>So, I have this old iMac &quot;Early 2009&quot; Aluminum iMac Core 2 Duo. I decided to make something usefull out of it, so I upgraded the RAM to 8GB, replaced the original HDD with 1TB SSD and installed Ubuntu 20.24.</p>
<p><strong>Important note:</strong> Bellow, I describe how I configured autologin and how I changed permissions to /sys/. These <strong>are NOT</strong> are not good security practices. However, given that the machine is sitting on my desk, and behind a well configured firewall, my assesment was that it is safe for me to do them. Please do your own security assesment.</p>
<h1>Installing Ubuntu</h1>
<p>Intalling Ubuntu was straight forward with two exceptions:</p>
<ul>
<li>The nouveau video driver seems to freeze when X does something intensive (and by intencive I mean opening Firefox). But I did not care about it as I intended to use this on console mode.</li>
<li>The wifi driver is a commercial one, and you have to have newtork connectivity to install it. So, I had to use Ethernet, use <code>ubuntu-drivers</code> to identify the driver I needed and install it. From that point on, I could configure wifi and Ethernet was no longer needed.</li>
</ul>
<h1>Booting in console mode.</h1>
<p>First stem, was to disable X from starting on boot.</p>
<pre><code>systemctl enable multi-user.target
systemctl set-default multi-user.target
</code></pre>
<p>/etc/default/grub</p>
<pre><code># If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=&quot;Ubuntu&quot;
GRUB_TIMEOUT=&quot;3&quot;
GRUB_DISTRIBUTOR=&quot;`lsb_release -i -s 2&gt; /dev/null || echo Debian`&quot;
GRUB_CMDLINE_LINUX_DEFAULT=&quot;text&quot;
GRUB_CMDLINE_LINUX=&quot;&quot;

# Uncomment to disable graphical terminal (grub-pc only)
GRUB_TERMINAL=&quot;console&quot;

GRUB_GFXMODE=&quot;640x480&quot;
# Uncomment to disable generation of recovery mode menu entries
GRUB_DISABLE_RECOVERY=&quot;false&quot;

# Uncomment to get a beep at grub start
GRUB_INIT_TUNE=&quot;480 440 1&quot;

GRUB_DISABLE_OS_PROBER=&quot;true&quot;
GRUB_SAVEDEFAULT=&quot;false&quot;
</code></pre>
<h1>Configuring tty1</h1>
<p>This would be a keyboardless system, so I would like to make sure that tty1 starts with some things on it.</p>
<pre><code>$ sudo systemctl edit getty@tty1.service
</code></pre>
<p>This (creates and) openes file <code>/etc/systemd/system/getty@tty1.service.d/override.conf</code> for editing. I entered:</p>
<pre><code>[Service]
ExecStart=
ExecStart=-/sbin/agetty --noissue --autologin vrypan %I $TERM
Type=idle
</code></pre>
<p>To enable the service and starts an auto-login session on tty1:</p>
<pre><code>$ sudo systemctl enable getty@tty1.service; sudo systemctl restart getty@tty1.service
</code></pre>
<p>To automatically run some useful stuff on tty1, I added the following lines to <code>$HOME/.profile</code>:</p>
<pre><code>if [[ &quot;x$XDG_VTNR&quot; = &quot;x1&quot; &amp;&amp; &quot;x$SHLVL&quot; = &quot;x1&quot; ]] ; then
    # Sometimes fbterm failed to start immediately, it seems that
    # the framebuffer needs a couple of milliseconds to initialise.
    # Or maybe it's something else, but waiting a second or
    # two fixed it.
    echo Waiting 2 secs... 
    sleep 2
    /usr/bin/fbterm -- tmuxp load -y $HOME/custom/tmuxp.tty1.yaml 
fi
</code></pre>
<p>tmuxp.tty1.yaml will start a tmux session with all the panes arranged like I want them and run the corresponding processes in each one of them.</p>
<pre><code>#  tmuxp.tty1.yaml
session_name: tty1
windows:
  - window_name: status
    focus: 'true'
    layout: 0774,240x75,0,0{91x75,0,0[91x10,0,0{45x10,0,0,1,45x10,46,0,7},91x64,0,11,2],148x75,92,0[148x38,92,0,3,148x36,92,39,4]}
    options:
      automatic-rename: 'off'
      pane-active-border-style: fg=black
      pane-border-style: fg=black
      status: &quot;off&quot;
    panes:
    - tty-clock
    - while true; do clear; ncal -M ; sleep 1m ; done
    - while true; do clear; calendar -A 2 ; sleep 1m ; done
    - glances -1
    - colortail -f &lt;(docker exec pihole pihole -t )
    start_directory: /home/vrypan
  
  - window_name: lights_on
    panes:
      - shell_command:
          - tput setab 7
          - clear
</code></pre>
<p>And this is the result:</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/screenshot.png" alt="screenshot" /></figure></p>
<h1>The services</h1>
<p>I also installed docker, and then configured a couple of containers (that replaced rasperrypis I used for this purposes):</p>
<ul>
<li><a href="https://hub.docker.com/r/pihole/pihole">pihole</a></li>
<li>an <a href="https://hub.docker.com/r/ipfs/go-ipfs/">ipfs server</a></li>
<li>and <a href="https://github.com/oznu/docker-homebridge">homebridge</a></li>
</ul>
<p>I also configured syslog-ng to receive logs from my Unifi Dream Machine:</p>
<pre><code># /etc/syslog-ng/conf.d/remote.conf 
source t_src { tcp(port(514)); };
source u_src { udp(port(514)); };
destination r_all { file(&quot;/var/log/$HOST&quot;); };
log { source(t_src); source(u_src); destination(r_all); };
</code></pre>
<h1>Using the iMac as a (sort of) LED panel light</h1>
<p>You may have noticed there is a second tmux window, called <em>ligths_on</em>. I find this kind of cool. It's a window that is all white (tput settab 7 sets the background to white). So I can ssh to this machine, do <code>tmux next -t tty1</code> and the screen will turn on white.</p>
<p>And since this is placed on my desk, I use it as a light panel (!!!) that makes me look better when I'm on a video call on my laptop. Then <code>tmux next -t tty1</code> will switch back to my normal &quot;control center&quot; view.</p>
<p><figure><img src="https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/lights-on.png" alt="" /></figure></p>
<p>Of course, don't expect a thousand nits from this display. But it makes a difference when there's low light.</p>
<h1>Turning on and off the iMac screen using Siri</h1>
<p>I don't want my iMac screen to be on all the time. So I use the following over ssh</p>
<pre><code>$ echo 0 |sudo tee /sys/class/backlight/nv_backlight/brightness # turn off
$ echo 100 |sudo tee /sys/class/backlight/nv_backlight/brightness # turn on
</code></pre>
<p>But since I have already homebridge running, why not use Siri for this?</p>
<p>I order to easily allow the homebridge docker container to access /sys/class/backlight/nv_backlight/brightness I changed the permissions</p>
<pre><code>$ sudo chmod 666 /sys/class/backlight/nv_backlight/brightness
</code></pre>
<p>and I also mount <code>/sys/class/backlight/nv_backlight/</code> as a rw docker volume, so my docker-compose file looks like this:</p>
<pre><code>version: '2'
services:
  homebridge:
    image: oznu/homebridge:latest
    container_name: homebridge
    restart: always
    network_mode: host
    environment:
      - TZ=Europe/Athens
      - PGID=1000
      - PUID=1000
      - HOMEBRIDGE_CONFIG_UI=1
      - HOMEBRIDGE_CONFIG_UI_PORT=8581
    volumes:
      - $HOME/data/homebridge:/homebridge
      - /sys/class/backlight/nv_backlight:/backlight:rw
</code></pre>
<p>Next I installed the <a href="https://github.com/cr3ative/homebridge-shell-switch#readme">homebridge-shell-switch</a> plugin, and configured like this:</p>
<pre><code>{
    &quot;accessory&quot;: &quot;ShellSwitch&quot;,
    &quot;name&quot;: &quot;Monitor&quot;,
    &quot;onCmd&quot;: &quot;echo 100 &gt; /backlight/brightness&quot;,
    &quot;offCmd&quot;: &quot;echo 0 &gt; /backlight/brightness&quot;
}
</code></pre>
<p>Now, I can turn on and off the monitor by saying <em>Hey Siri, turn the monitor off</em>. I can also schedule the monitor to turn off during the night for example, or turn it on/off using the Home.app on my iPhone.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/head.png"
   type="image/png"
   length="79055"/>

   <enclosure url="https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/lights-on.png"
   type="image/png"
   length="930028"/>

   <enclosure url="https://blog.vrypan.net/2022/01/06/putting-an-old-imac-to-use/screenshot.png"
   type="image/png"
   length="289680"/>

    </item>
    
    <item>
      <title>Christina's Linux adventures, part 2.
</title>
      <link>https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures-part-2/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures-part-2/</guid>
      <pubDate>Sun, 26 Dec 2021 21:42:21 +0200</pubDate>
      <description>(If you haven't done so, read Part 1 of this series.)</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures-part-2/printout.jpeg">
        
	<p>(If you haven't done so, read <a href="/2021/12/26/christina-s-linux-adventures/">Part 1</a> of this series.)</p>
<p>The next morning, when Christina woke up, she found the above note.</p>
<p>This is what Tips-and-Tricks-1.txt said:</p>
<pre><code>Hello, Christina!

Try the following commands!

$ bb

$ fortune

Every time you run fortune, you get a new fortune cookie. Try it.

Now, try this:
$ echo &quot;Hello, Christina!&quot; | boxes -d santa
$ echo &quot;Hello, Christina!&quot; | boxes -d boy
$ echo &quot;Hello, Christina!&quot; | boxes -d girl
$ echo &quot;Hello, Christina!&quot; | boxes -d cat

If you want to see all available &quot;boxes&quot;, type
$ boxes -l

You can always pipe the output of one command to an other!

$ echo &quot;Hello, Christina!&quot; | boxes -d cat | lolcat

or...

$ fortune | boxes -d cat | lolcat

or even.....

$ fortune | cowsay | boxes -d cat | lolcat

Remember, you have already used the following commands:

ls
ls -l
pwd
cd
asciiquarium
cowsay
lolcat

You can see your terminal history by typing 
$ history

</code></pre>
<p>After she tried all the above, I heard what every geek dad wants to hear:</p>
<blockquote>
<p><em>Is there a way to make this fortune cookie appear every time I log in?</em></p>
</blockquote>
<p>Yes!!! She has questions!!! Now, we are in business.</p>
<p>We edited <code>.bashrc</code> and added <code>fortune | boxes -d cat | lolcat</code> at the end.</p>
<p>An other thing she tried was a box, within a box, within a box, something like <code>fortune | boxes -d mouse | boxes -d cat | boxes -d dog</code></p>
<p>She spent a big part of the day trying various combinations of the commands she knows.</p>
<p>Our day, ended with this.</p>
<blockquote>
<p>Dad, I think the terminal is my favourite app.</p>
</blockquote>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures-part-2/printout.jpeg"
   type="image/jpeg"
   length="170579"/>

    </item>
    
    <item>
      <title>Christina's Linux adventures. Part 1.
</title>
      <link>https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/</guid>
      <pubDate>Sun, 26 Dec 2021 13:01:29 +0200</pubDate>
      <description>One of Christina's Christmas presents was an old MacBook (Late 2008 Aluminum), that had not been used for years. I cleaned it, formated the disk and installed Linux Mint.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/lolcat1.png">
        
	<p>One of Christina's Christmas presents was an old MacBook (Late 2008 Aluminum), that had not been used for years. I cleaned it, formated the disk and installed Linux Mint. <sup class="footnote-ref"><a href="#fn-1" id="fnref-1" data-footnote-ref>1</a></sup></p>
<p>Before we presented it to her, I had already created an account for her, so I just had to give her the password and she logged in.</p>
<p>Christina is quite experienced with computers and electronics (as most of the kids her age), but she mostly lives inside her iPad, and I realised that the desktop environment looked strange to her. Especially the trackpad gestures like tap-to-click, or two-fingers-click, etc.</p>
<p>Not surprisingly, the first thing she wanted to know is how to change the desktop background 😆. Which turned out to be a good opportunity to use right-click-save, after she googled for backgrounds. We also installed Skype, and tested OpenOffice Writer.</p>
<hr />
<p>Next stop was the terminal (and to be honest, this was my goal, what we had done so far she could do much better and easier on her iPad).</p>
<p>She had already seen a terminal a year ago, when I tried and failed to introduce her to Python on an old iMac (where almost nothing worked without tweaking). I also took the opportunity to explain to her that the application is called &quot;terminal&quot; because it's a software that works just like... a terminal. Yes, we have one of these in the house.</p>
<p>This time, I decided to start with something fun. <sup class="footnote-ref"><a href="#fn-2" id="fnref-2" data-footnote-ref>2</a></sup></p>
<pre><code>$ sudo apt install sl
$ sl
</code></pre>
<p><figure><img src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/linux-terminal-train.png" alt="" /></figure></p>
<p>Next we tried <code>asciiquarium</code><sup class="footnote-ref"><a href="#fn-3" id="fnref-3" data-footnote-ref>3</a></sup>,
<figure><img src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/asciiquarium.png" alt="" /></figure></p>
<p>and <code>cowsay</code><sup class="footnote-ref"><a href="#fn-4" id="fnref-4" data-footnote-ref>4</a></sup>
<figure><img src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/cowsay.png" alt="" /></figure></p>
<p>I also installed <code>aalib</code>, <code>aview</code> and <code>jp2a</code>  which allowed us to view the pokemon image she downloaded in the terminal.
<figure><img src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/jp2a.png" alt="" /></figure></p>
<p>What turned out to be a great hit, was <code>lolcat</code><sup class="footnote-ref"><a href="#fn-5" id="fnref-5" data-footnote-ref>5</a></sup>, which also provided a nice intro to using Unix pipes. Once she got to know <code>lolcat</code>, she had to pipe the output of every command she knew through it.
<figure><img src="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/lolcat1.png" alt="" /></figure></p>
<p>As we went through these commands, we also had to learn <code>ls</code>, <code>pwd</code>, even <code>sudo</code> (&quot;it's like 'please', for Linux&quot;). I tried to let her do most of the typing, and let her get the expected errors when she did not leave a space or when a file was not found because of an uppercase letter, etc.</p>
<p>Overall, she got really excited with her new laptop, and especially with the command line.</p>
<section class="footnotes" data-footnotes>
<ol>
<li id="fn-1">
<p><a href="https://www.reallinuxuser.com/bring-your-macbook-aluminum-late-2008-back-to-life-again-with-linux/">Bring your MacBook Aluminum Late 2008 back to life again with Linux</a> <a href="#fnref-1" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="1" aria-label="Back to reference 1">↩</a></p>
</li>
<li id="fn-2">
<p><a href="https://itsfoss.com/ubuntu-terminal-train/">Running a Train in the Linux Terminal to Amuse Your Friends and Family</a> <a href="#fnref-2" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="2" aria-label="Back to reference 2">↩</a></p>
</li>
<li id="fn-3">
<p><a href="https://robobunny.com/projects/asciiquarium/html/">ASCIIquarium</a> <a href="#fnref-3" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="3" aria-label="Back to reference 3">↩</a></p>
</li>
<li id="fn-4">
<p><a href="https://alligator.io/workflow/cowsay/">Command-line Basics: Dressing up Output with cowsay</a> <a href="#fnref-4" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="4" aria-label="Back to reference 4">↩</a></p>
</li>
<li id="fn-5">
<p><a href="https://www.tecmint.com/lolcat-command-to-output-rainbow-of-colors-in-linux-terminal/">Lolcat – A Command Line Tool to Output Rainbow Of Colors in Linux Terminal</a> <a href="#fnref-5" class="footnote-backref" data-footnote-backref data-footnote-backref-idx="5" aria-label="Back to reference 5">↩</a></p>
</li>
</ol>
</section>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/asciiquarium.png"
   type="image/png"
   length="9917"/>

   <enclosure url="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/cowsay.png"
   type="image/png"
   length="189803"/>

   <enclosure url="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/jp2a.png"
   type="image/png"
   length="582181"/>

   <enclosure url="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/linux-terminal-train.png"
   type="image/png"
   length="12206"/>

   <enclosure url="https://blog.vrypan.net/2021/12/26/christina-s-linux-adventures/lolcat1.png"
   type="image/png"
   length="93952"/>

    </item>
    
    <item>
      <title>web3, ens and trademarks
</title>
      <link>https://blog.vrypan.net/2021/11/05/web3-ens-and-trademarks/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/11/05/web3-ens-and-trademarks/</guid>
      <pubDate>Fri, 05 Nov 2021 11:37:47 +0200</pubDate>
      <description>Of course, all this may make no sense to you. ENS, .eth, web3, wtf are they?</description>
      <content:encoded><![CDATA[
	
	<blockquote>
<p>Trademarks + Web3. 1/🧵 <small>// @vrypan<a href="https://twitter.com/i/web/status/1456536317463044122">→</a></small></p>
</blockquote>
<blockquote>
<p>Web3 will bring new identity systems, like @domains_ens. Your ENS domain will be the way for others to verify it's you, it will probably be the way social networks will verify the identity of your brand, it will be the address where your clients will use to pay you. 2/ <small>// @vrypan<a href="https://twitter.com/i/web/status/1456536318805221383">→</a></small></p>
</blockquote>
<blockquote>
<p>The thing is that Web3 is decentralised and to a large extent, anonymous. Which means that your trademark will be really hard to claim.</p>
</blockquote>
<blockquote>
<p>What can you do against the ETH address that holds your companyname.eth? Sue them? Good luck. 3/ <small>// @vrypan<a href="https://twitter.com/i/web/status/1456536320239673352">→</a></small></p>
</blockquote>
<blockquote>
<p>Maybe ask ENS to take the domain away?</p>
</blockquote>
<blockquote>
<p>&quot;[...]  the root key holders have locked control of the .eth registrar contract, which means that even keyholders cannot affect the ownership of .eth domains.&quot; <a href="https://docs.ens.domains/frequently-asked-questions">docs.ens.domains/frequently-as...</a> 4/ <small>// @vrypan<a href="https://twitter.com/i/web/status/1456536322252939292">→</a></small></p>
</blockquote>
<blockquote>
<p>So, here's the obvious advise: make sure you claim your brand-related .eth domains <em>now</em>, before someone else does. Smart companies already did.</p>
</blockquote>
<blockquote>
<p>Or buy them if someone else claimed them already: Most probably it will cost you less now than in the future.  5/5 <small>// @vrypan<a href="https://twitter.com/i/web/status/1456536324203335680">→</a></small></p>
</blockquote>
<p>Of course, all this may make no sense to you. ENS, .eth, web3, wtf are they?</p>
<p>Remember: Domain names made no sense to you or the people that were in your shoes back in the 90s, when the web was starting. But a couple of decades later, we got to this: <a href="https://www.godaddy.com/garage/the-top-20-most-expensive-domain-names/">The top 25 most expensive domain names</a>.</p>
<p>So, find someone who knows about these things and pay them to handle it for you.</p>
<p>There's one thing you can be sure of: When all this is common sense, when your kids will have their own .eth address, then your brand/corporate .eth domain will cost <strong>much much more</strong> to buy back. And this time, it won't take decades to get there.</p>

]]></content:encoded>

    </item>
    
    <item>
      <title>Planet LRR
</title>
      <link>https://blog.vrypan.net/2021/11/03/planet-lrr/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/11/03/planet-lrr/</guid>
      <pubDate>Wed, 03 Nov 2021 16:54:41 +0200</pubDate>
      <description>Today I'd like to introduce you to my latest passion: Planet LRR.  // @vrypan→Planet LRR is actually a mathematical object, disguised as a painting. It's the result of a very very simple process called "cellular automata". This is where it got its name from: Left, Right, Right. /...</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2021/11/03/planet-lrr/media1.jpg">
        
	<blockquote>
<p>Today I'd like to introduce you to my latest passion: Planet LRR.  <small>// @vrypan<a href="https://twitter.com/i/web/status/1455875308775780358">→</a></small></p>
</blockquote>
<blockquote>
<p>Planet LRR is actually a mathematical object, disguised as a painting. It's the result of a very very simple process called &quot;cellular automata&quot;. This is where it got its name from: Left, Right, Right. <small>// @vrypan<a href="https://twitter.com/i/web/status/1455875311652982793">→</a></small></p>
</blockquote>
<blockquote>
<p>The actual process to generate Planet LRR took 2 million steps but you can see the genesis of Planet LRR (the first 30-something thousand steps) here: <a href="https://videos.files.wordpress.com/fFpFOWdg/planet-rll-genesis.mp4">videos.files.wordpress.com/fFp...</a> <small>// @vrypan<a href="https://twitter.com/i/web/status/1455875313477603330">→</a></small></p>
</blockquote>
<blockquote>
<p>The reason I find it fascinating is that all this complexity comes from such a simple rule. Which is actually an existential or cosmological question: is our universe with all its complexity the result (or governed by) some very simple rules/laws? <small>// @vrypan<a href="https://twitter.com/i/web/status/1455875315193032704">→</a></small></p>
</blockquote>
<blockquote>
<p>To my knowledge, there are no (or at least very few?) pieces of art that try to explore these questions. My <a href="http://turmites.art">turmites.art</a> project is an effort to make works (of art?) about these great questions. I hope you like it. :-) <small>// @vrypan<a href="https://twitter.com/i/web/status/1455875317122412551">→</a></small></p>
</blockquote>
<blockquote>
<p>You can find more about Planet LRR here: <a href="https://turmites.art/gallery/planet-lrr/">turmites.art/gallery/planet-lr...</a> <small>// @vrypan<a href="https://twitter.com/i/web/status/1455875319009849350">→</a></small></p>
</blockquote>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/11/03/planet-lrr/media1.jpg"
   type="image/jpeg"
   length="133637"/>

    </item>
    
    <item>
      <title>Stories from NFT land #1
</title>
      <link>https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/</guid>
      <pubDate>Fri, 22 Oct 2021 22:58:28 +0200</pubDate>
      <description>It was February 2021 when I bought my first NFT art. I was looking around, trying to find some NFTs that I liked but did not cost a ton of money, when I found Lisa Fogarty's "Nostalgia Series" on Mintable.</description>
      <content:encoded><![CDATA[
	
	<p>It was February 2021 when I bought my first NFT art. I was looking around, trying to find
some NFTs that I liked but did not cost a ton of money, when I found <a href="https://lisafogarty.se/">Lisa Fogarty's</a>
&quot;Nostalgia Series&quot; on Mintable.</p>
<p><figure><img src="https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/nostalgia-series.png" alt="nostalgia series watter color" /></figure></p>
<p>I'm no art expert, my only criteria is how much I like a piece, and these three spoke directly to my heart,
so I went ahead and bought them.</p>
<p>I looked up Lisa, found <a href="https://instagram.com/lisakfogarty">her Instagram account</a> and messaged her that
I liked her work, and suggested she should add a link from her Instagram profile to her Mintable profile
to prove that she is her on both sites.</p>
<p>Since then, she has joined twitter
(<a href="https://twitter.com/NftLisa">@NftLisa</a>, follow her!), she got deep into NFTs and her works are sold at
significantly higher prices than the early ones I bought 8 months ago.
(links: <a href="https://linktr.ee/LisaFogarty">https://linktr.ee/LisaFogarty</a>)</p>
<p><figure><img src="https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/lisa-fogarty-foundation.png" alt="Lisa Fogarty Foundation page" /></figure></p>
<p>Some days ago, I reached out to her again, to ask her something technical about these early NFTs, and
as we were chatting, she was very kind to offer to send me the original works as a gift
for the early support.</p>
<p>So, today I got these! <strong>Thank you so much Lisa!</strong></p>
<p><figure><img src="https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/nostalgia-series-rl.png" alt="photo" /></figure></p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/lisa-fogarty-foundation.png"
   type="image/png"
   length="2948947"/>

   <enclosure url="https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/nostalgia-series-rl.png"
   type="image/png"
   length="993549"/>

   <enclosure url="https://blog.vrypan.net/2021/10/22/stories-from-nft-land-1/nostalgia-series.png"
   type="image/png"
   length="323379"/>

    </item>
    
    <item>
      <title>Some thoughts on stablecoins
</title>
      <link>https://blog.vrypan.net/2021/05/21/some-thoughts-on-stablecoins/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/05/21/some-thoughts-on-stablecoins/</guid>
      <pubDate>Fri, 21 May 2021 08:40:51 +0200</pubDate>
      <description>It turns out that stable coins are a fascinating subject. You may say, what's so fascinating about something that's stable by definition? Thread 👇 // @vrypan→For one, the various implementations. Take DAI, USDT, USDC, SUSD, TUSD, BUSD, GUSD and the rest. In theory, they are 1-1 t...</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2021/05/21/some-thoughts-on-stablecoins/media1.jpg">
        
	<blockquote>
<p>It turns out that stable coins are a fascinating subject. You may say, what's so fascinating about something that's stable by definition? Thread 👇 <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613622160793602">→</a></small></p>
</blockquote>
<blockquote>
<p>For one, the various implementations. Take DAI, USDT, USDC, SUSD, TUSD, BUSD, GUSD and the rest. In theory, they are 1-1 to USD. But you get algorithmic vs centralised implementations, each one with its pros and cons. <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613623427403780">→</a></small></p>
</blockquote>
<blockquote>
<p>And then, even for the centralised ones, you get to have different jurisdictions. You want a stable coin backed by a company regulated/audited in the US or not? How much do you trust the backer (if centralised) or the algorithm (if decentralised)? <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613624698343426">→</a></small></p>
</blockquote>
<blockquote>
<p>Also, you have to consider liquidity and integration with marketplaces, exchanges and other services. Will you be able to convert your stablecoin to the desired price? Which one(s) are supported by the services you are interested in? <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613625969217536">→</a></small></p>
</blockquote>
<blockquote>
<p>I think that nothing illustrates these differences than this. This is the current deposit/borrow APY on aave. In theory they are all the same, but the APYs differ based on demand. <a href="https://app.aave.com/markets">app.aave.com/markets</a>  <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613631216295936">→</a></small></p>
</blockquote>
<blockquote>
<p><figure><img src="https://blog.vrypan.net/2021/05/21/some-thoughts-on-stablecoins/media1.jpg" alt="media" /></figure></p>
</blockquote>
<blockquote>
<p>You may think that stablecoins are second class citizens compared to the reference currency. But in some cases they are better. For example, there is no KYC. Remittances are a breeze and you don't have to convert to the local (usually much weaker currency). <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613633036574721">→</a></small></p>
</blockquote>
<blockquote>
<p>Sidenote on remittances: This is a <em>huge</em> and critical economic activity for a very big percentage of the global population. For example, in Nigeria official remittances have exceeded oil revenues for multiple years. See <a href="https://www.pwc.com/ng/en/pdf/the-economic-power-of-nigerias-diaspora.pdf">www.pwc.com/ng/en/pdf/the-econ...</a> <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613634311692291">→</a></small></p>
</blockquote>
<blockquote>
<p>I'm looking forward to stablecoins pegged to other currencies. I for one, would love to have one (or more) EUR stablecoins. Is someone working on this? <small>// @vrypan<a href="https://twitter.com/i/web/status/1395613635699957762">→</a></small></p>
</blockquote>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/05/21/some-thoughts-on-stablecoins/media1.jpg"
   type="image/jpeg"
   length="31620"/>

    </item>
    
    <item>
      <title>Leaving ChannelVAS
</title>
      <link>https://blog.vrypan.net/2021/04/27/leaving-channelvas/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/04/27/leaving-channelvas/</guid>
      <pubDate>Tue, 27 Apr 2021 03:22:22 +0200</pubDate>
      <description>I joined ChannelVAS when it was more like a startup. We were setting up our first projects, the team was small, we had to do a bit of everything.</description>
      <content:encoded><![CDATA[
	
	<p>I joined <a href="https://www.channelvas.com">ChannelVAS</a> when it was more like a
startup. We were setting up our first projects, the team was small, we
had to do a bit of everything.</p>
<p>I got to work in a truly multicultural company, with people from Europe, Africa,
Asia, Latin America, the Middle East. I got to travel to places I'd never been before:
Ghana, Zambia, Saudi Arabia, India, Brazil, Kambodia, Bangladesh, Nepal, Surinam,
Trinidad and Tobago, Curacao, Sri Lanka, Tanzania, Tunisia, Algeria, UAE (I'm probably
forgetting some), and worked with even more, like Benin and Uganda. I made some good
friends, and I worked with great people from around the world.</p>
<p>When I joined, the telco tech stack was a black box to me.
5.5 years later, after working with something like 20 mobile operators and their vendors
and the peculiarities of each country and region, you could call me an expert on some
parts of this stack, especially the IN and billing systems and various CDRs. But I also
got to understand how the various product offerings work in all these operators and
countries -and the similarities and differences.</p>
<p>So, I learned a lot, I traveled to places I'd never been before, I met and worked
with great people and made some good friends.</p>
<p>But ChannelVAS has grown up, the team is 10x bigger, processes have been put in place, things have become
more structured and well defined. And even if this sounds good for most people, it's
no longer the startup mess where I can give my best.</p>
<p>Cheers to all the people I worked with in these 5.5 years! We'll be in touch.</p>
<p><figure><img src="https://blog.vrypan.net/2021/04/27/leaving-channelvas/beers.png" alt="beers around the world" /></figure></p>
<hr />
<p>For job openings, checkout <a href="https://apply.workable.com/channelvas/">https://apply.workable.com/channelvas/</a>.</p>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/04/27/leaving-channelvas/beers.png"
   type="image/png"
   length="4748935"/>

    </item>
    
    <item>
      <title>The rise of the activist trader (?)
</title>
      <link>https://blog.vrypan.net/2021/01/31/the-rise-of-the-activist-trader/</link>
      <guid isPermaLink="true">https://blog.vrypan.net/2021/01/31/the-rise-of-the-activist-trader/</guid>
      <pubDate>Sun, 31 Jan 2021 10:12:10 +0200</pubDate>
      <description>I think of trading activism in the same way as consumer activism.</description>
      <content:encoded><![CDATA[
	
        <img  src="https://blog.vrypan.net/2021/01/31/the-rise-of-the-activist-trader/wallstreet.jpg">
        
	<p>I think of trading activism in the same way as consumer activism.</p>
<blockquote>
<p>Consumer activism is a process by which activists seek to influence the way
in which goods or services are produced or delivered. Kozinets and Handelman
attempt to define the broad concept as any social movement that uses society's
drive for consumption to the detriment of business interests.
<em>-- <a href="https://en.wikipedia.org/wiki/Consumer_activism">wikipedia: Consumer activism</a></em></p>
</blockquote>
<p>In the same way that an activist consumer may boycott a product that is cheaper,
better or even essential to them in order to apply pressure to a producer or a distributor
to change their policies (for example using sweatshops, destroying palm trees, or lobbying
for a specific politician), an activist trader may buy or sell stocks or other financial
instruments in order to make an ideological point by driving out of buisness
or causing significant financial damage to a company, an institution, or a fund
that is considered to have negative social impact.</p>
<p>For example, the some individual traders kept buying $GME stock at any price, in hope
of buncrupting hedge funds because they consider that these funds are bad for society.
They knew that they may loose their small investment, but they did not care, as the expected
profit for them was to bring down a hedge fund. [1]</p>
<p>Activist trading has become feasible by services like Robinhood that allow retail
traders invest small amounts and social networks like reddit that allows the coordination
and aggregation of these activists.</p>
<p><strong>Much like activist consumers, activist traders do not act in their best financial
interest.</strong></p>
<p>This may be a new reality that shakes the fundamental assumption behind financial markets
that all parties act in their best financial interest. Publicly traded companies, individual
and institutional investors, brokers, funds and other parties like banks that are part of the
financial system will have to take this into account.</p>
<hr />
<small>
[1] I'm not saying that *all* $GME traders acted with this motive in mind. I am refering to
the ones that bought and hold $GME "to bring the f---- hedge funds down".
</small>
<small>
[2] Image source: [Wikimedia commons](https://commons.wikimedia.org/wiki/File:Wall_Street_-_New_York_Stock_Exchange.jpg)
</small>

]]></content:encoded>

   <enclosure url="https://blog.vrypan.net/2021/01/31/the-rise-of-the-activist-trader/wallstreet.jpg"
   type="image/jpeg"
   length="457881"/>

    </item>
    
  </channel>
</rss>
