Hey HN! We're Ben and Izak, founders of Repaint (YC S23). Repaint is like Figma, but for creating real websites.
It has panning, zooming, and dragging elements around. The settings closely follow html/css. We think an open canvas is a big improvement over other website builders. Everything is easier: styling, consistency, responsiveness…
But making it work was hard! We thought HN would appreciate the tech behind it:
- A custom WebGL rendering engine (w/text, shadows, blurs, gradients, & opacity groups)
- A partial implementation of the css spec
- A custom text editor & text shaper
- A transformer to turn designs into publishable html/css
Repaint is a design tool for html/css. But internally, it doesn’t actually use html/css itself. All your designs live in a single <canvas> element.
We wanted users to be able to see all their content on one screen. We target +60fps, so frames only have 16ms to render. The browser’s layout engine couldn’t handle simple actions, like zooming, with many thousands of nodes on the screen. To fix that, we wrote a rendering engine in WebGL.
Since we use custom rendering, we had to create a lot of built-in browser behavior ourselves.
Users modify a large dom-like data-structure in our editor. Each node in the document has a set of css-like styles. We created a layout engine that turns this document into a list of positions and sizes. We feed these values into the rendering engine. Our layout engine lets us display proper html layouts without using the browser's layout engine. We support both flex and block layouts. We already support multiple layout units and properties (px, %, mins, maxes, etc.).
We also can’t use the browser’s built-in text editor, so we made one ourselves. We implemented all the common text editor features regarding selection and content editing (clicking, selection, hotkeys, inline styling, etc.). The state consists of content and selection. The inputs are keystrokes, clicks, and style changes. The updated state is used to render text, selection boxes, and the cursor.
When you publish a website, we turn our internal document into an html document. We've intentionally structured our document to feel similar to a dom tree. Each node has a 1:1 mapping with an html element. Nodes have a list of breakpoints which represent media-queries. We apply the styles by turning them into selectors. All of the html pages are saved and stored on our fileserver for hosting.
We made a playground for HN, so you can try it yourself. Now that the tech works, we’d love feedback and ideas for improving the product experience.
And we’d love to meet more builders interested in the space. If that’s you, feel free to say hello in the comments! Or you can reach Ben from his website.
Playground: https://app.repaint.com/playground
Demo Vid: https://www.loom.com/share/03ee81317c224189bfa202d3eacfa3c3?...
Main Website: https://repaint.com/
Contact: https://benshumaker.xyz/
I just tried to insert an emoji on the demo. The page didn't recognize the IME was up and when pressed enter in the IME it inserted a carriage return in the text area. I tried pasting in some Japanese and an emoji. Neither displayed. I tried right-clicking so I could use cut/copy/paste/define/lookup/spellcorrect. All of them were missing