You are browsing as a guest. Sign up (or log in) to start making projects!

Fork()

  • 7 Devlogs
  • 10 Total hours

Fork() is a spatial text editor for mapping out logic trees, user flows, and branching thoughts on an near-infinite canvas. Designed for a "zero-mouse" flow, it lets you rapidly build complex architectures using just your keyboard.

Ship #1

I built Fork(), a spatial text editor for mapping out logic trees, user flows, and branching thoughts on an infinite canvas. It is designed around a "zero-mouse" flow, allowing users to rapidly brainstorm complex architectures using only keyboard shortcuts without breaking their flow state.

What did you find challenging?
Exporting an infinite, DOM-based canvas into an image file was a massive pain. Browsers lack a native DOM-to-image API, and standard libraries couldnt handle modern Flexbox math. Furthermore, when trying to export massive trees, Chrome's memory limits would silently cut the XML data, causing the exports to crash. I had to build a custom "Shrinkwrap" staging area and utilize RAM-based Binary Blobs to bypass browser string limits entirely.

What are you proud of?
I am proud of the bulletproof export engine that can instantly generate infinite-resolution SVGs, but I'm equally proud of the UI polish. I am also proud of the idea itself because i personally think the idea is very unique.

What should people know so they can test your project?
No login required: Just open the link and start typing.

Use the keyboard: Press Cmd + Enter to spawn a child branch, and Cmd + B for a sibling. Try "Focus Mode" (Cmd + Shift + F) once you have a large tree. And there are more keyboard shortcuts in the Keyboard Shortcuts screen on the website.

SVG Testing: Because Chrome flags local SVGs containing tags as a security risk, double-clicking the exported SVG on your desktop might show a blank screen. Drag that exact file into Figma or Illustrator to see the proper image.

Try project → See source code →
Open comments for this post

3h 42m 9s logged

Devlog #4: Onboarding and Revised Export Engine + Other improvements.

This is probably the final devlog before i ship my project. Here are the changes i made:

  1. Onboarding screen : To introduce the user to what Fork() is, i designed and onboarding screen. The screen features a typewriter animation and some bento boxes explaining the usefulness of the app. It introduces the user to the core concepts of the app without overwhelming them. Once dismissed (via a custom checkbox), it saves a flag to localStorage so it never interrupts returning users.

The Shortcuts screen: I also added a small section on the bottom left that shows some of the useful keyboard shortcuts. It breaks down the entire zero-mouse flow (like Cmd + ↵ for child branches and Cmd + B for siblings) so users can reference the hotkeys instantly. By pressing on a Show more shortcuts button, another screen pops up with all of the shortcuts

  1. SVG & PNG Exports: This was the hardest engineering challenge of the project and took me the longes. Because Fork() uses standard HTML elements ( and ) instead of a raw , exporting it meant reverse-engineering the DOM into an image. Here is what i had to face to perfect these two engines

The Outdated Engine: Initially, I used html2canvas, but it couldn’t understand modern Flexbox math or connecting branch lines, resulting in empty, broken files. I completely swapped the engine to the modern html-to-image library.

The large canvas: Browsers panic when trying to capture a 100,000-pixel infinite canvas. To fix this, I built an invisible staging area. When you click export, the app clones the tree, strips away the UI buttons, removes all absolute coordinates, and uses native CSS to tightly “shrinkwrap” the bounding box around your exact nodes.

The 2MB Chrome Limit: When generating the SVG, Google Chrome kept throwing an XML error. This was because I was putting the raw image data into a URL string, and Chrome silently chops off strings larger than 2 Megabytes.

The Blob Fix: To bypass the browser’s memory limits, I converted the raw data into a Binary Blob stored securely in RAM. By using URL.createObjectURL(blob), the app generates a tiny pointer URL that allows users to instantly download massive, infinite-resolution vector trees without the browser crashing.

Note on SVGs: Because Chrome flags local SVGs containing tags as a security risk, double-clicking the exported file on a desktop shows a blank screen or a cutoff svg file. But if you drag that exact same file into Figma, Illustrator, or Miro, It renders the vector math flawlessly.

  1. Better UX: I entirely stripped out native browser alert() boxes—which are terrible for UX because they freeze the main browser thread—and built a custom Alert System.

The Loader: Exports now trigger a Loading Screen with three spinning rings. It features a text element that actively cycles through statuses (“Freezing DOM…”, “Processing spatial math…” and some other stuff).

That was my final changes to the website. I just need to write the README.md and then i can officially ship this project

0
0
3
Open comments for this post

1h 18m 21s logged

Devlog #4: Focus Mode + Branching + Recenter

The product is almost coming to an end and here are some final features i added:

  1. Branch Folding:
    I added a tiny dropdown button to the bottom of each of the nodes that allows the user to collapse their branches.

How it works: Instead of writing complex JavaScript to check if a node has children, I used the modern CSS :has() selector (.node:has(> .children > .node)). The browser automatically figures out if a branch has children and fades the button in for me. Clicking it toggles a .collapsed class that hides the tree below.

I also wired the Fork() button and Ctrl+Enter shortcuts to automatically unfold a branch if you try to add a new child to a collapsed node, so you never spawn invisible data.

  1. There was a probem however. Everytime i delete or add a branch, the screen jerks and moves somewhere else. This was the hardest technical hurdle. Because the canvas is massive, whenever I used JavaScript to .focus() a new text box, the browser’s native engine would mess up everything. It tried to auto-scroll to center the text box, which contradicted my pan engine, causing the screen to jerk wildly.

How I fixed it: I disabled the native and scrollbars (overflow: hidden; overscroll-behavior: none), intercepted any native window.scrollTo events to force them to 0, and applied {preventScroll: true} to every text box.

  1. Once I disabled the browser’s native scrolling, the “camera” wouldn’t follow me when I navigated off-screen. I had to build a custom “camera”:
  • Flexbox centering breaks when elements resize (like when collapsing a branch), causing the whole tree to shift. I fixed this by making the canvas 100,000px wide container and locking the transform origin to 0,0. The root node sits permanently at exactly 50,000 pixels. It never moves.Smart Panning: I wrote a math function that calculates the exact pixel center of the active text box, compares it to the physical center of the user’s monitor, and glides the canvas coordinates (panX, panY) to align them perfectly.

  • Zoom-to-Center: I upgraded the mouse-wheel math to calculate where your cursor is relative to the screen, adjusting the pan coordinates while scaling so it zooms smoothly into your target instead of shooting off

  1. Focus Mode: I also added a Focus Mode (Cmd+Shift+F). When you are deep in work, the sheer number of boxes is overwhelming.

How it works: It strips away the background grid and dims every single node and connecting line to 15% opacity. Using JavaScript’s focusin event, it tracks exactly which box you are typing in and fully illuminates it. Using CSS :has(), I tell the browser to look up the DOM tree and keep the parent nodes semi-illuminated at 60% opacity, creating a “trail” leading back to your root thought.

The focus mode is shown in the picture attached below:

0
0
1
Open comments for this post

54m 30s logged

Devlog #3: Undo Redo Engine and Dark Mode

The aim was first to create an undo redo option where the user can revert back to the previous change if they made a mistake or sth.

To do this i made the following changes:
I created two arrays, one for undoHistory and one for redoHistory. They work in such a way that every time you fork or delete a branch, the app takes a snapshot of the DOM and pushes it to the stack. The app only takes a snapshot of the canvas right before you make a structural change (like forking or deleting a branch). If you hit Ctrl+Z, it pops that HTML snapshot back onto the screen. Keystroke typos are still handled by the browser’s native undo.

The next change is the dark mode. This is quite self explanatory. I added a dark mode to the website to offer customization options for the user. The preference is also saved to localStorage so the website remembers what theme the user was on.

0
0
3
Open comments for this post

1h 51m 40s logged

Devlog #3: localStorage sync + export functoin

I realised one of the features missing is the export function where the user can export their tree as many things, so i started coding that. At first, I tried to make the app export to a standard text file or a CSV for Excel. But as soon as I tested it, I realized that a tree/mindmap just doesn’t fit into a flat spreadsheet or as plain text. It was completely illegible. So, I scrapped that and built three new export options:

Markdown (Clipboard): I wrote a custom function that takes the tree and converts it into an indented Markdown list. You can click ‘Copy’ and paste it anywhere and it formats it instantly.

JSON Data: you can also export the entire tree as a nested JSON file and literally drop it straight into your codebase.

PNG Image: to also make exporting it in a visually pleasing way, i coded this option. I integrated html2canvas so you can download a high-res image. To make the UI more like professional, i wrote a script that temporarily hides the UI buttons, resets the zoom/pan, takes the picture, and puts you right back where you were after the export.

The second thing i built is the localStorage. I didnt want users refreshing the website and losing all the stuff that they inputted so this is very essential. Fortunately, since i attached the fork button eventListener to the document itself and not only the individual buttons, i could just add a simple localStorage.setItem for each of the events and save it in localStorage. This was quite simple and wasnt too hard to do.

0
0
2
Open comments for this post

39m 47s logged

Devlog #2: Infinite Canvas + Keyboard shortcuts.

Since this mission is about making life easier, i realised that always switching between mouse and keyboard to just move around and stuff is a bit ironic. So, I rewrote how the entire workspace behaves.

Changes:

Drag & Pan: I threw out standard scrollbars entirely. Now, the background is like an infinite canvas. You can click and drag anywhere to pan around, or use your trackpad to move in any direction.

Keyboard Shortcuts: I wanted to make it possible to map out an entire codebase without ever touching the mouse. I split the branching logic into two intuitive shortcuts:

  • Ctrl + Enter drops down to create a child branch (diving deeper into an idea).
  • Ctrl + B creates a parallel sibling branch right next to you (exploring an alternative idea).
  • Arrow Key Navigation: You can now move through the branches tree using Ctrl + Arrow Keys. Heading Up takes you to the parent thought, Down dives into the branches, and Left/Right hops between parallel options.
  • Ctrl + delete/backspace deletes the current branch/texarea that you are on. If you delete a branch, the cursor shifts focus to the parent node so your typing flow never breaks.

Some problems: Fixed a frustrating bug where the connecting lines were off by a single pixel on the outermost branches. Using a calc(), the layout is now completely locked in and perfectly aligned.

Next up, I’m diving into LocalStorage so the canvas automatically saves your notes in the background.

0
0
3
Open comments for this post

1h 21m 17s logged

Devlog #1: Building Fork()

Fork() is a branching notepad for the Frictionless mission. I decided to tackle a massive personal pain point: linear note-taking. Whenever I’m mapping out complex logic or trying to write a function, I always hit a point where I want to try two different approaches. Usually, that means either deleting my past context, or scrolling endlessly up and down a huge document. It completely breaks my flow. So, I started building Fork().

Here’s what I managed to get working for the core engine so far:

Branching: I set up the JavaScript so that the moment you click Fork(), a new parallel text box pops up and automatically grabs your cursor. You don’t even have to click into it to start typing.

Branchign tree lines: This is the part I’m most proud of. I originally thought I’d have to write a bunch of heavy JavaScript math or use a HTML Canvas to draw the connecting lines between the thoughts. Instead, I figured out how to draw the entire tree using pure CSS. As you spawn new branches, the browser instantly redraws the geometry.

Zooming: Since the canvas grows infinitely left, right, and down, I added a custom zoom controller (and also included Ctrl + Scroll). When your logic tree gets massive, you can zoom out to get a bird’s-eye view of your whole thought process. The text boxes also automatically resize and push the rest of the tree down as you type, so nothing gets cut off.

0
0
7

Followers

Loading…