jeanrojas.com

Footer

jeanrojas.com

Boosting remote teamwork and improving systems architecture focusing on team communication patterns.



jrojastechnology@gmail.com
+1 (929) 2245443

Links

  • About
  • Experience
  • Blog
  • Contact

Social

  • Github
  • Codepen
  • Linkedin
  • Twitter
  • Behance
  • Quora
  • AdpList

Subscribe to my newsletter

The latest news, articles, and resources, sent to your inbox weekly.

© Jeanrojas.com All rights reserved.

← All articles

September 29, 2026 · 7 min read

Why we built Fanta on top of a code editor

How our 2024 browser-canvas experiments and 2026 native editor fork shaped Fanta's readable design files, canvas, and agent workflow.

On this page

Fanta build log · Part 1 of 4 · 2024–2026 journey

The first version of Fanta's current editor fork was a .fig viewer. That was a useful place to start because it forced us to confront a real design file before building an elaborate editor around an imaginary one. On 7 July we committed the editor baseline and viewer foundation. On 8 July we added an editable canvas, panels and an inspector. The interesting decision, though, came before either commit: we chose to start from Zed, a code editor, instead of from a blank graphics window.

We had already put the native editor in public in an earlier LinkedIn announcement showing .fig import, readable source and undoable edits. This longer series opens up the decisions and failures behind that preview; it does not assume that posting alone improved the product.

That sounds backwards until you state the thing we wanted to build. Fanta is a native Mac design editor in which a design can also be read and changed as source. An agent, a designer dragging a shape, and a developer editing a file should be working on the same project. If a rectangle moves, we want a useful diff. If someone edits the source, we want the canvas to follow. An editor already has years of work in text buffers, project files, Git, panes, diagnostics, commands and agents. Zed also has GPUI, the native UI framework behind its own interface. Those foundations were closer to our problem than a bare drawing surface was.

Run / Deploy / Read

Pick the path that matches your hardware and patience

GitHub
ShareLinkedInX / Twitter

This is a fork, and it should be called one. The adoption plan sets out the boundary: keep the editor, GPUI, workspace, project, Git and agent foundations where they help; make the product identity, design model and service decisions Fanta's own. A native design canvas on top of an editor is still a lot of work. It gives us a strong place to put that work.

Before the native fork

The editor idea did not begin with this Rust repository. In July 2024, we were building a browser canvas with Fabric.js. The first weeks brought responsive layout, shape and text tools, undo and redo, import and export, and an AI sidebar. The web editor later grew into Fantaisa, with more image-editing work; by January 2026 we had added project version history and an agent that could call canvas tools. Those experiments gave us two years of design-editor problems to learn from. The current Fanta Edit fork is a new implementation, not a continuation of the browser codebase.

In parallel, I explored how image selection could feel like editing instead of waiting for a remote model on every click. In May 2026 I published a browser ONNX recipe and a more detailed SAM2 segmentation build log, with a working demo and code. They document a related technical thread in the wider Fanta journey; they do not establish that the current Mac canvas uses that exact browser pipeline.

Start with a file we did not create

A viewer for our own test format would have proved very little. For the Rust/Zed fork, we started with exported Figma .fig files. A modern export is a ZIP archive with a canvas.fig entry and embedded images. Inside canvas.fig is a Kiwi-encoded document: an embedded schema, compressed chunks, and a tree of design nodes. Older exports and bare streams vary, so the importer reads the framing and detects the compression rather than assuming one vintage of the format.

The reader was checked against a real community design file. That mattered. A parser can be perfectly symmetric with its own writer and still fail on someone else's export. The fork's first milestone was to get the file into our scene model and render it with the Skia Metal path, with a CPU fallback. Only then did we add editing.

The import is a bridge, not the ongoing source of truth. When Fanta opens a .fig, it materializes a sibling Fanta project and edits that project. Reopening the original file redirects to the existing project, so a later open does not silently reimport an old export over new work. The original .fig remains an import input.

Figma .fig export
    → parse and import once
    → Fanta project folder
    → canvas, source files, Git history

The project is deliberately ordinary on disk. It has a fanta.json manifest, page source under pages/, components, metadata and assets. The page source is .fnx, a restricted JSX-like language: an element is a scene node, attributes are literal properties, and nested elements are children. Here is pseudocode showing the shape; a real FNX file includes more properties and an identity sidecar:

<Frame id="01ARZ3NDEKTSV4RRFFQ69G5FAV" name="Home" clip_size={[800.0, 600.0]}>
  <Rect id="01ARZ3NDEKTSV4RRFFQ69G5FAW" name="Hero" x={48.0} y={48.0} width={320.0} height={120.0} />
</Frame>

The important point is that moving Hero can change one attribute in one file. It does not have to replace an opaque document blob.

The seam between a cursor and an agent

The visual editor and the agent need a common vocabulary. We introduced a DesignSurface layer for operations such as creating a node, setting a fill, grouping, aligning and creating a component. The local MCP server exposes the focused design through six tools: read editor state, read guidelines, read nodes, apply a batch of design operations, take a screenshot and read FNX source. A design batch is one undoable transaction. If an operation in the batch fails, it does not leave half an agent instruction applied to the canvas.

That seam is a product choice as much as an API choice. An agent should be able to inspect the same page a person sees, change it through the same document model, and let the result pass through autosave and Git. It should not need a private route that bypasses undo or writes unreviewable state somewhere else.

In a 9 September release-build smoke run, the local MCP bridge passed 18 of 18 scripted checks, including a design operation reaching the canvas, autosave and Git. We also drove about forty operations in that session. That is evidence for the agent-to-file path. It is not evidence that every toolbar button, drag gesture or App Store build was exercised by a person. The distinction is part of building in public: a passing protocol test answers one question, not every question.

What the fork made harder

Keeping a large upstream editor underneath a design product creates two pressures. We need to retain enough compatibility that upstream changes remain possible, while replacing inherited product behavior that is wrong for Fanta. A Zed account flow, cloud default or updater cannot become a Fanta feature just because it arrived with the code. The initial fork plan therefore put product identity and service safety ahead of the canvas work. That was less visible than drawing a shape, but it prevented the app from presenting itself as one product while silently depending on another product's services.

The other pressure is that a design editor stresses a code editor differently. A page may have tens of thousands of nodes and hundreds of images. Selection, render invalidation and saving cannot all copy the entire scene after every pointer movement. We hit that limit in real imported documents. A later build log will share the measurements and the fixes; the large case still has uncomfortable memory use.

Where this leaves us

Fanta now has the essential shape of the idea: a native canvas, an import path from real .fig files, a readable project format, and agent operations that share the editing model. The remaining work is not hidden behind the word “alpha.” There are import and format gaps, large-document costs, native UI validation to finish, and a separate Mac App Store release path with stricter sandbox rules. The Mac App Store build also does not promise every external developer workflow of the non-store build.

The next article will cover the mistake that nearly undermined the whole thesis: our design files were readable, but the in-memory canvas could still overwrite them. We changed which side owned the truth, and the change reached much further than serialization.

If you work with code-backed design tools, I would like to know where the source/canvas boundary breaks for you: identity, merge conflicts, asset handling or something we have missed. The public repository makes the current implementation inspectable. This is Part 1 of our four-part #Shipaton build log. The later entries will follow the source-file pivot, large-document tests and Mac App Store release work as we publish them.

Comments

Tags in this post

  • #fanta
  • #shipaton
  • #build-in-public
  • #rust
  • #design-tools

Keep reading

  • Carnegie Hall, rebuilt from a seating chart

    How I turned a flat ticketing map into a complete Stern Auditorium: 2,758 seats, four tiers of gilded parapets, vaulted ceilings and hundreds of real light fixtures. I did it by building tools instead of sculpting.

    33 min · Sep 16, 2026

  • Parsing documents without uploading them

    A procurement pipeline that never leaves the tab: PDF, DOCX and XLSX to editable Markdown, PP-OCRv6 on ONNX Runtime Web inside a module worker, and the canvas shims nobody warns you about.

    12 min · Jul 7, 2026

  • Rendering Brilliance

    A visual tour of the cubemap-based diamond shader — how a faceted gemstone becomes a single texture lookup, and what that gets you. Eight interactive figures, plain-English asides, and the optics that hold it all together.

    15 min · May 26, 2026

All tags

  • #ai
  • #blender
  • #build-in-public
  • #cubemap
  • #design-tools
  • #diamond
  • #environment-art
  • #expo
  • #fanta
  • #graphics
  • #houdini
  • #huggingface
  • #image-generation
  • #licensing
  • #mdx
  • #meta
  • #next.js
  • #ocr
  • #onnx
  • #open-source
  • #pdf
  • #procedural
  • #python
  • #r3f
  • #ray-tracing
  • #react-native
  • #rendering
  • #replicate
  • #rust
  • #sam2
  • #segmentation
  • #shaders
  • #shipaton
  • #technical-art
  • #three.js
  • #vercel
  • #wasm
  • #web-worker
  • #webgl
  • #webgpu
← Back to all articles

Tags in this post

  • #fanta
  • #shipaton
  • #build-in-public
  • #rust
  • #design-tools

Keep reading

  • Carnegie Hall, rebuilt from a seating chart

    How I turned a flat ticketing map into a complete Stern Auditorium: 2,758 seats, four tiers of gilded parapets, vaulted ceilings and hundreds of real light fixtures. I did it by building tools instead of sculpting.

    33 min · Sep 16, 2026

  • Parsing documents without uploading them

    A procurement pipeline that never leaves the tab: PDF, DOCX and XLSX to editable Markdown, PP-OCRv6 on ONNX Runtime Web inside a module worker, and the canvas shims nobody warns you about.

    12 min · Jul 7, 2026

  • Rendering Brilliance

    A visual tour of the cubemap-based diamond shader — how a faceted gemstone becomes a single texture lookup, and what that gets you. Eight interactive figures, plain-English asides, and the optics that hold it all together.

    15 min · May 26, 2026

All tags

  • #ai
  • #blender
  • #build-in-public
  • #cubemap
  • #design-tools
  • #diamond
  • #environment-art
  • #expo
  • #fanta
  • #graphics
  • #houdini
  • #huggingface
  • #image-generation
  • #licensing
  • #mdx
  • #meta
  • #next.js
  • #ocr
  • #onnx
  • #open-source
  • #pdf
  • #procedural
  • #python
  • #r3f
  • #ray-tracing
  • #react-native
  • #rendering
  • #replicate
  • #rust
  • #sam2
  • #segmentation
  • #shaders
  • #shipaton
  • #technical-art
  • #three.js
  • #vercel
  • #wasm
  • #web-worker
  • #webgl
  • #webgpu