index.html (9227B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <title> 6 Sprig Arbor Chat Client · Jack Mordaunt 7 </title> 8 <meta charset="utf-8"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <meta name="color-scheme" content="light dark"> 11 12 13 14 15 <meta name="author" content="Jack Mordaunt"> 16 <meta name="description" content="Arbor Chat client in Go."> 17 <meta name="keywords" content="blog,developer,personal,software,robust,performance,sovereign"> 18 19 20 21 <meta name="twitter:card" content="summary"> 22 <meta name="twitter:title" content="Sprig Arbor Chat Client"> 23 <meta name="twitter:description" content="Arbor Chat client in Go."> 24 25 <meta property="og:url" content="http://jackmordaunt.com/projects/sprig/"> 26 <meta property="og:site_name" content="Jack Mordaunt"> 27 <meta property="og:title" content="Sprig Arbor Chat Client"> 28 <meta property="og:description" content="Arbor Chat client in Go."> 29 <meta property="og:locale" content="en"> 30 <meta property="og:type" content="article"> 31 <meta property="article:section" content="projects"> 32 <meta property="article:published_time" content="2022-03-17T17:30:23+00:00"> 33 <meta property="article:modified_time" content="2022-03-17T17:30:23+00:00"> 34 <meta property="article:tag" content="Go"> 35 <meta property="article:tag" content="Gio"> 36 <meta property="article:tag" content="Native"> 37 <meta property="article:tag" content="Portfolio"> 38 39 40 41 42 <link rel="canonical" href="http://jackmordaunt.com/projects/sprig/"> 43 44 45 <link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin> 46 <link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin> 47 <link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin> 48 49 50 51 52 <link rel="stylesheet" href="/css/coder.min.6445a802b9389c9660e1b07b724dcf5718b1065ed2d71b4eeaf981cc7cc5fc46.css" integrity="sha256-ZEWoArk4nJZg4bB7ck3PVxixBl7S1xtO6vmBzHzF/EY=" crossorigin="anonymous" media="screen" /> 53 54 55 56 57 58 59 60 61 62 <link rel="stylesheet" href="/css/coder-dark.min.a00e6364bacbc8266ad1cc81230774a1397198f8cfb7bcba29b7d6fcb54ce57f.css" integrity="sha256-oA5jZLrLyCZq0cyBIwd0oTlxmPjPt7y6KbfW/LVM5X8=" crossorigin="anonymous" media="screen" /> 63 64 65 66 67 68 69 70 <link rel="stylesheet" href="/css/custom.min.931a9d02d6f7655cd0cd50317fac1204e00c54ffd0232085acc957b2db5e1283.css" integrity="sha256-kxqdAtb3ZVzQzVAxf6wSBOAMVP/QIyCFrMlXstteEoM=" crossorigin="anonymous" media="screen" /> 71 72 73 74 75 76 77 <link rel="icon" type="image/svg+xml" href="/images/self-tiny-white.svg" sizes="any"> 78 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="32x32"> 79 <link rel="icon" type="image/png" href="/images/self-tiny-white.png" sizes="16x16"> 80 81 <link rel="apple-touch-icon" href="/images/apple-touch-icon.png"> 82 <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"> 83 84 <link rel="manifest" href="/site.webmanifest"> 85 <link rel="mask-icon" href="/images/safari-pinned-tab.svg" color="#5bbad5"> 86 87 88 89 90 91 92 93 <script defer data-domain="jackmordaunt.com" src="https://plausible.io/js/script.js"></script> 94 95 96 97 98 </head> 99 100 101 102 103 104 105 <body class="preload-transitions colorscheme-auto"> 106 107 <div class="float-container"> 108 <a id="dark-mode-toggle" class="colorscheme-toggle"> 109 <i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i> 110 </a> 111 </div> 112 113 114 <main class="wrapper"> 115 <nav class="navigation"> 116 <section class="container"> 117 118 <a class="navigation-title" href="http://jackmordaunt.com/"> 119 Jack Mordaunt 120 </a> 121 122 123 <input type="checkbox" id="menu-toggle" /> 124 <label class="menu-button float-right" for="menu-toggle"> 125 <i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i> 126 </label> 127 <ul class="navigation-list"> 128 129 130 <li class="navigation-item"> 131 <a class="navigation-link " href="/posts/">Blog</a> 132 </li> 133 134 <li class="navigation-item"> 135 <a class="navigation-link " href="/about/">About</a> 136 </li> 137 138 <li class="navigation-item"> 139 <a class="navigation-link " href="/projects/">Projects</a> 140 </li> 141 142 <li class="navigation-item"> 143 <a class="navigation-link " href="/contact/">Contact</a> 144 </li> 145 146 <li class="navigation-item"> 147 <a class="navigation-link " href="/pay-with-bitcoin/">Pay</a> 148 </li> 149 150 151 152 </ul> 153 154 </section> 155 </nav> 156 157 158 <div class="content"> 159 160 <section class="container page"> 161 <article> 162 <header> 163 164 <h1 class="title"> 165 <a class="title-link" href="http://jackmordaunt.com/projects/sprig/"> 166 Sprig Arbor Chat Client 167 </a> 168 </h1> 169 170 </header> 171 172 <style> 173 .carousel { 174 display: flex; 175 overflow: scroll; 176 } 177 </style> 178 <div class="carousel"> 179 <img src="/images/sprig/sprig.webp" alt="Sprig" /> 180 </div> 181 <h2 id="overview"> 182 Overview 183 <a class="heading-link" href="#overview"> 184 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 185 <span class="sr-only">Link to heading</span> 186 </a> 187 </h2> 188 <p>Built by <a href="https://git.sr.ht/~whereswaldon" class="external-link" target="_blank" rel="noopener">~whereswaldon</a>, <a href="https://git.sr.ht/~whereswaldon/sprig" class="external-link" target="_blank" rel="noopener">Sprig</a> is a client for <a href="https://man.sr.ht/~whereswaldon/arborchat" class="external-link" target="_blank" rel="noopener">Arbor</a>, an open source federated chat platform.<br> 189 Sprig is a cross-platform client supporting Windows, macOS, Linux, Android, and iOS.<br> 190 It’s written in <strong>Go</strong>, using the <a href="https://git.sr.ht/~eliasnaur/gio" class="external-link" target="_blank" rel="noopener"><strong>Gio</strong></a> immediate-mode UI toolkit.</p> 191 <hr> 192 <h3 id="my-role"> 193 My Role 194 <a class="heading-link" href="#my-role"> 195 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 196 <span class="sr-only">Link to heading</span> 197 </a> 198 </h3> 199 <p>When I joined, Sprig stored each chat message as an individual file on disk. This file-per-message model worked reasonably well on Linux, but resulted in <strong>severely degraded performance</strong> on Windows, where reading thousands of tiny files led to <strong>notably slow startup times</strong>.</p> 200 <p>To address this, I migrated the persistence layer from the filesystem to <a href="https://github.com/boltdb/bolt" class="external-link" target="_blank" rel="noopener"><strong>BoltDB</strong></a>, an embedded key-value store written in Go. This upgrade significantly improved startup performance across all platforms, with the largest gains on Windows.</p> 201 <p>In addition to this core performance enhancement, I contributed minor UI improvements and refinements.</p> 202 <hr> 203 <h3 id="result"> 204 Result 205 <a class="heading-link" href="#result"> 206 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 207 <span class="sr-only">Link to heading</span> 208 </a> 209 </h3> 210 <p>The app now launches significantly faster, offers a smoother user experience, and maintains cross-platform compatibility—all without sacrificing the simplicity of a local-first storage model.</p> 211 <h3 id="platforms"> 212 Platforms 213 <a class="heading-link" href="#platforms"> 214 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 215 <span class="sr-only">Link to heading</span> 216 </a> 217 </h3> 218 <div style="display: flex; flex-wrap: wrap; gap: 2rem;"> 219 <i class="fa-4x fa-brands fa-windows"></i> 220 <i class="fa-4x fa-brands fa-apple"></i> 221 <i class="fa-4x fa-brands fa-linux"></i> 222 <i class="fa-4x fa-brands fa-android"></i> 223 </div> 224 <h3 id="languages"> 225 Languages 226 <a class="heading-link" href="#languages"> 227 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 228 <span class="sr-only">Link to heading</span> 229 </a> 230 </h3> 231 <div style="display: flex; flex-wrap: wrap; gap: 2rem;"> 232 <img style="max-height: 100px;" src="/images/brands/go.svg"/> 233 </div> 234 <h3 id="tech"> 235 Tech 236 <a class="heading-link" href="#tech"> 237 <i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"></i> 238 <span class="sr-only">Link to heading</span> 239 </a> 240 </h3> 241 <div style="display: flex; flex-wrap: wrap; gap: 2rem;"> 242 <img style="max-height: 100px;" src="/images/brands/gio.svg" class="invert-me"/> 243 <img style="max-height: 100px;" src="/images/brands/boltdb.webp"/> 244 </div> 245 246 </article> 247 </section> 248 249 250 251 </div> 252 253 <footer class="footer"> 254 <section class="container"> 255 © 256 257 2025 258 Jack Mordaunt 259 · 260 261 Powered by <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> & <a href="https://github.com/luizdepra/hugo-coder/" target="_blank" rel="noopener">Coder</a>. 262 263 </section> 264 </footer> 265 266 </main> 267 268 269 270 271 272 <script src="/js/coder.min.6ae284be93d2d19dad1f02b0039508d9aab3180a12a06dcc71b0b0ef7825a317.js" integrity="sha256-auKEvpPS0Z2tHwKwA5UI2aqzGAoSoG3McbCw73gloxc="></script> 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 </body> 314 </html>