[{"data":1,"prerenderedAt":113},["ShallowReactive",2],{"products":3,"post:introducing-opendraw":100,"product-by-slug:opendraw":108},[4,23,38,60,73,85],{"title":5,"tagline":6,"description":7,"status":8,"kind":9,"order":10,"art":11,"artAlt":12,"platforms":13,"facts":16,"links":20,"slug":11,"path":22},"Fold","Journaling, but cool.","The journaling app for Gen Z. Photos, voice notes and quick thoughts, captured with a tap, a hold, or a swipe.","waitlist","app",1,"fold","A skeleton reading a book in a field of roses",[14,15],"iOS","Android",[17,18,19],"Free","Coming 2026","No account, no cloud",{"waitlist":21},"https:\u002F\u002Ffold.taohq.org","\u002Fproducts\u002Ffold",{"title":24,"tagline":25,"description":26,"status":27,"kind":9,"order":28,"art":29,"artAlt":30,"platforms":31,"facts":33,"links":35,"slug":29,"path":37},"Bottles","Bookmarks and docs, filed properly.","A quiet place for your links, notes and files. No feed, no noise. One space for what you keep, one for what you write.","live",2,"bottles","A skull resting in still water, surrounded by rings of ripples",[32],"Web",[34],"Live now",{"app":36},"https:\u002F\u002Fbottles.taohq.org","\u002Fproducts\u002Fbottles",{"title":39,"tagline":40,"description":41,"status":42,"kind":43,"order":44,"art":39,"artAlt":45,"platforms":46,"facts":51,"links":54,"install":58,"slug":39,"path":59},"opendraw","Hand-drawn diagrams, as one component.","A free, open-source hand-drawn whiteboard for your app. Draw hand-drawn diagrams with shapes, arrows, text and sticky notes, one component for Vue, Nuxt, React and Svelte.","open-source","library",3,"A hand-drawn diagram: a rectangle, an ellipse, an arrow, a sticky note, a diamond and a spark",[47,48,49,50],"Vue","Nuxt","React","Svelte",[52,53],"MIT license","Autosaves to localStorage",{"app":55,"github":56,"npm":57},"https:\u002F\u002Fopendraw.taohq.org","https:\u002F\u002Fgithub.com\u002FTheAlphaOnes\u002Fopendraw","https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@opendrawjs\u002Fnuxt","npm i @opendrawjs\u002Fnuxt","\u002Fproducts\u002Fopendraw",{"title":61,"tagline":62,"description":63,"status":64,"kind":9,"order":65,"art":66,"artAlt":67,"platforms":68,"facts":69,"slug":66,"path":72},"Bubbles.space","Your AI assistant's home.","A personal AI workspace OS built for the way you actually think. Bubbles, your assistant, lives and works alongside you.","in-development",4,"bubbles-space","A small figure sitting under a blossoming tree beneath a full moon",[],[70,71],"Part of the Bubbles family","AI-agent first","\u002Fproducts\u002Fbubbles-space",{"title":74,"tagline":75,"description":76,"status":64,"kind":9,"order":77,"art":78,"artAlt":79,"platforms":80,"facts":82,"slug":78,"path":84},"Bubbles.mail","It reads your inbox so you don't have to.","An intelligent mail client that turns the raw chaos of email into a short report of what matters, what can wait, and what to hand off.",5,"bubbles-mail","A skull crowned with blossoms, pierced by an arrow",[81],"macOS",[70,83],"Native macOS","\u002Fproducts\u002Fbubbles-mail",{"title":86,"tagline":87,"description":88,"status":42,"kind":43,"order":89,"art":86,"artAlt":90,"platforms":91,"facts":93,"links":95,"install":98,"slug":86,"path":99},"web-have-sounds","UI sounds, generated with math.","A zero-dependency JavaScript library for UI sound effects. No audio files, no network requests. Just the Web Audio API.",6,"A crow perched on a skull inside an arched frame",[32,92],"npm",[94],"Zero dependencies",{"github":96,"npm":97},"https:\u002F\u002Fgithub.com\u002FNormVg\u002Fweb-have-sound","https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@thenormvg\u002Fweb-have-sounds","npm i @thenormvg\u002Fweb-have-sounds","\u002Fproducts\u002Fweb-have-sounds",{"title":101,"description":102,"date":103,"author":104,"product":39,"slug":105,"path":106,"readingMinutes":28,"html":107},"Introducing opendraw","We shipped a free, open-source hand-drawn whiteboard that drops into Vue, Nuxt, React and Svelte as one component. Here's what it does and how to try it.","2026-11-01","taohq","introducing-opendraw","\u002Fwriting\u002Fintroducing-opendraw","\u003Cp>Today opendraw is live at \u003Ca href=\"https:\u002F\u002Fopendraw.taohq.org\">opendraw.taohq.org\u003C\u002Fa>, and the whole thing — engine, editor and every framework adapter — is on \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FTheAlphaOnes\u002Fopendraw\">GitHub\u003C\u002Fa> under the MIT license.\u003C\u002Fp>\n\u003Cp>opendraw is a hand-drawn whiteboard that lives inside your app as a native component. Not an iframe. Not a third-party embed with its own login screen. One component, \u003Ccode>&lt;OpenDraw \u002F&gt;\u003C\u002Fcode>, that brings the canvas, the toolbar, the properties panel, keyboard shortcuts, dark mode and autosave with it — for Vue, Nuxt, React and Svelte.\u003C\u002Fp>\n\u003Ch2>The whole quick start\u003C\u002Fh2>\n\u003Cpre class=\"shiki taohq\" style=\"background-color:#201e25;color:#ece8f3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#ECE8F3\">npm \u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">install\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\"> @opendrawjs\u002Fnuxt\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre class=\"shiki taohq\" style=\"background-color:#201e25;color:#ece8f3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#8A8494;font-style:italic\">\u002F\u002F nuxt.config.ts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B2A0D8\">export\u003C\u002Fspan>\u003Cspan style=\"color:#B2A0D8\"> default\u003C\u002Fspan>\u003Cspan style=\"color:#ECE8F3\"> defineNuxtConfig\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#ECE8F3\">  modules\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">:\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">'\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">@opendrawjs\u002Fnuxt\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">})\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre class=\"shiki taohq\" style=\"background-color:#201e25;color:#ece8f3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">template\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">  &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">div\u003C\u002Fspan>\u003Cspan style=\"color:#B2A0D8\"> style\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">=\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">height: 100vh\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">OpenDraw\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\"> \u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">  &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">div\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">template\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>That&#39;s the entire integration. The editor fills its container and saves the scene to \u003Ccode>localStorage\u003C\u002Fcode> as you draw, so a reload puts everything back. If you&#39;re not on Nuxt, the same editor ships as \u003Ccode>@opendrawjs\u002Freact\u003C\u002Fcode> and \u003Ccode>@opendrawjs\u002Fsvelte\u003C\u002Fcode>, and plain Vue 3 works through \u003Ccode>@opendrawjs\u002Fnuxt\u002Fvue\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2>What&#39;s in the box\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Thirteen tools\u003C\u002Fstrong>: selection, hand, rectangle, diamond, ellipse, arrow, line, freedraw, text, sticky note, image, frame, eraser and a laser pointer — each with a keyboard shortcut, plus a tool lock for drawing many of the same shape.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Arrows that connect\u003C\u002Fstrong>: bind an arrow to shapes and it follows them when they move. Straight, curved or elbowed around whatever sits between them.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Frames\u003C\u002Fstrong>: group content into frames that carry and clip their children.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Files\u003C\u002Fstrong>: autosave, many named drawings in one browser with a sidebar to manage them, \u003Ccode>.opendraw\u003C\u002Fcode> files you can open and save, and PNG or SVG export.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Themes\u003C\u002Fstrong>: light and dark, with the hand-drawn ink inverting while your canvas background stays exactly as you chose it.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Responsive and accessible\u003C\u002Fstrong>: on phones the toolbar moves to the bottom and the properties panel becomes a sheet; every control is a real, labelled, keyboard-navigable element.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>The hand-drawn look is the point, not a gimmick. Sketchy rendering lowers the stakes: nobody expects a rough rectangle to be a commitment, which is exactly the mental state you want people in while they&#39;re thinking. That look comes from \u003Ca href=\"https:\u002F\u002Froughjs.com\">rough.js\u003C\u002Fa> for the geometry, \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fsteveruizok\u002Fperfect-freehand\">perfect-freehand\u003C\u002Fa> for pressure-aware strokes and \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fexcalidraw\u002Fexcalifont\">Excalifont\u003C\u002Fa> for the text.\u003C\u002Fp>\n\u003Ch2>The demo is the docs\u003C\u002Fh2>\n\u003Cp>\u003Ca href=\"https:\u002F\u002Fopendraw.taohq.org\">opendraw.taohq.org\u003C\u002Fa> is itself an opendraw component. Draw on it, press \u003Ccode>?\u003C\u002Fcode> for every shortcut, and when you want the longer version, the \u003Ccode>\u002Fdocs\u003C\u002Fcode> page covers the headless API, custom UI, and building an adapter for a framework we don&#39;t ship.\u003C\u002Fp>\n\u003Cp>We also wrote four companion pieces this week:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"\u002Fwriting\u002Fwhy-we-built-opendraw\">Why we built it\u003C\u002Fa> — the gap between a whiteboard app and a whiteboard component.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fwriting\u002Fhow-we-built-opendraw\">How we built it\u003C\u002Fa> — a framework-free engine, five packages, one test suite.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fwriting\u002Fhow-to-use-opendraw\">How to use it\u003C\u002Fa> — the practical guide, from install to custom toolbars.\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"\u002Fwriting\u002Finside-the-opendraw-engine\">Inside the engine\u003C\u002Fa> — immutable elements, seeded wobble and cheap undo.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>opendraw stands on the shoulders of \u003Ca href=\"https:\u002F\u002Fexcalidraw.com\">Excalidraw\u003C\u002Fa>, which defined how a hand-drawn whiteboard should feel; several of its algorithms are ported into opendraw with their MIT notices kept. If you want a complete, collaborative whiteboard app, use Excalidraw. opendraw is for putting a whiteboard inside your own.\u003C\u002Fp>\n\u003Cp>It&#39;s MIT, it runs everywhere we could test, and issues and pull requests are welcome. If you draw something with it, we&#39;d genuinely love to see it.\u003C\u002Fp>\n",{"title":39,"tagline":40,"description":41,"status":42,"kind":43,"order":44,"art":39,"artAlt":45,"platforms":109,"facts":110,"links":111,"install":58,"slug":39,"path":59,"html":112},[47,48,49,50],[52,53],{"app":55,"github":56,"npm":57},"\u003Cp>\u003Cstrong>opendraw is a free, open-source hand-drawn whiteboard for your app: shapes, arrows, text and sticky notes, rendered sketchy, as one component for Vue, Nuxt, React and Svelte.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Ch2>What you can draw\u003C\u002Fh2>\n\u003Cp>Rectangles, diamonds and ellipses, arrows that connect, lines, freehand drawing, text, sticky notes and frames. Everything renders sketchy through rough.js, so it looks drawn by hand, because it was. There are tools and shortcuts for everything: every tool has a key, from V for select to K for the laser pointer. Press \u003Ccode>?\u003C\u002Fcode> inside the editor for the full list.\u003C\u002Fp>\n\u003Ch2>One engine, five packages\u003C\u002Fh2>\n\u003Cp>opendraw ships as five packages:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>@opendrawjs\u002Fcore\u003C\u002Fstrong>, the engine: element model, document &amp; history, geometry, hit testing, rendering and export. No framework code.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>@opendrawjs\u002Feditor\u003C\u002Fstrong>, the framework-free editor: tools, gestures, keyboard, the action registry, persistence. Mounts onto any DOM.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>@opendrawjs\u002Fnuxt\u003C\u002Fstrong>, the Vue\u002FNuxt adapter: \u003Ccode>&lt;OpenDraw \u002F&gt;\u003C\u002Fcode>, \u003Ccode>useOpenDraw()\u003C\u002Fcode> and the full editor UI.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>@opendrawjs\u002Freact\u003C\u002Fstrong> and \u003Cstrong>@opendrawjs\u002Fsvelte\u003C\u002Fstrong>, the React and Svelte 5 adapters.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>Getting started\u003C\u002Fh2>\n\u003Cp>Install, register the module, and drop the component anywhere. It fills its container, so give the container a height:\u003C\u002Fp>\n\u003Cpre class=\"shiki taohq\" style=\"background-color:#201e25;color:#ece8f3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#ECE8F3\">npm \u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">install\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\"> @opendrawjs\u002Fnuxt\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre class=\"shiki taohq\" style=\"background-color:#201e25;color:#ece8f3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#8A8494;font-style:italic\">\u002F\u002F nuxt.config.ts\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B2A0D8\">export\u003C\u002Fspan>\u003Cspan style=\"color:#B2A0D8\"> default\u003C\u002Fspan>\u003Cspan style=\"color:#ECE8F3\"> defineNuxtConfig\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">({\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#ECE8F3\">  modules\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">:\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">'\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">@opendrawjs\u002Fnuxt\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">],\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">})\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cpre class=\"shiki taohq\" style=\"background-color:#201e25;color:#ece8f3\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">&#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">template\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">  &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">div\u003C\u002Fspan>\u003Cspan style=\"color:#B2A0D8\"> style\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">=\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">height: 100vh\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">    &#x3C;\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">OpenDraw\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\"> \u002F>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">  &#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">div\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#A39DAD\">&#x3C;\u002F\u003C\u002Fspan>\u003Cspan style=\"color:#C4B5E3\">template\u003C\u002Fspan>\u003Cspan style=\"color:#A39DAD\">>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>The module auto-imports the components and composables. Plain Vue 3 without Nuxt works too: \u003Ccode>import { OpenDraw } from &#39;@opendrawjs\u002Fnuxt\u002Fvue&#39;\u003C\u002Fcode>. The scene saves itself to \u003Ccode>localStorage\u003C\u002Fcode> and restores on reload, and a drawings sidebar keeps many drawings, each saved on its own.\u003C\u002Fp>\n\u003Ch2>Where to Find It\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>\u003Cstrong>Docs and demo\u003C\u002Fstrong>: \u003Ca href=\"https:\u002F\u002Fopendraw.taohq.org\">opendraw.taohq.org\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Cstrong>GitHub\u003C\u002Fstrong>: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002FTheAlphaOnes\u002Fopendraw\">github.com\u002FTheAlphaOnes\u002Fopendraw\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Cstrong>npm\u003C\u002Fstrong>: \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@opendrawjs\u002Fnuxt\">npmjs.com\u002Fpackage\u002F@opendrawjs\u002Fnuxt\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>MIT licensed. If you draw something with it, we&#39;d genuinely love to see it.\u003C\u002Fp>\n",1793498088102]