| ▲ | Show HN: Coi – A language that compiles to WASM, beats React/Vue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 165 points by io_eric 4 days ago | 56 comments | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I usually build web games in C++, but using Emscripten always felt like overkill for what I was doing. I don't need full POSIX emulation or a massive standard library just to render some stuff to a canvas and handle basic UI. The main thing I wanted to solve was the JS/WASM interop bottleneck. Instead of using the standard glue code for every call, I moved everything to a Shared Memory architecture using Command and Event buffers. The way it works is that I batch all the instructions in WASM and then just send a single "flush" signal to JS. The JS side then reads everything directly out of Shared Memory in one go. It’s way more efficient, I ran a benchmark rendering 10k rectangles on a canvas and the difference was huge: Emscripten hit around 40 FPS, while my setup hit 100 FPS. But writing DOM logic in C++ is painful, so I built Coi. It’s a component-based language that statically analyzes changes at compile-time to enable O(1) reactivity. Unlike traditional frameworks, there is no Virtual DOM overhead; the compiler maps state changes directly to specific handles in the command buffer. I recently benchmarked this against React and Vue on a 1,000-row table: Coi came out on top for row creation, row updating and element swapping because it avoids the "diffing" step entirely and minimizes bridge crossings. Its bundle size was also the smallest of the three. One of the coolest things about the architecture is how the standard library works. If I want to support a new browser API (like Web Audio or a new Canvas feature), I just add the definition to my WebCC schema file. When I recompile the Coi compiler, the language automatically gains a new standard library function to access that API. There is zero manual wrapping involved. I'm really proud of how it's coming along. It combines the performance of a custom WASM stack with a syntax that actually feels good to write (for me atleast :P). Plus, since the intermediate step is C++, I’m looking into making it work on the server side too, which would allow for sharing components across the whole stack. Example (Coi Code): component Counter(string label, mut int& value) {
}component App { mut int score = 0;
}app { root = App; title = "My Counter App"; description = "A simple counter built with Coi"; lang = "en"; } Live Demo: https://io-eric.github.io/coi Coi (The Language): https://github.com/io-eric/coi WebCC: https://github.com/io-eric/webcc I'd love to hear what you think. It's still far from finished, but as a side project I'm really excited about :) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | trzeci 5 hours ago | parent | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I love the idea and execution. I did some reading of the code webcc and it's just brilliantly simple, and delivers to the promise. From the product perspective, it occupies a different market than Emscripten, and I don't see it's good comparison. Your product is borderline optimized to run C++ code on Web (and Coi is a cherry on top of that). Where Emscripten is made to make native C++ application to run on Web - without significant changes to the original source itself. Now, the `webcc::fush()` - what are your thoughts about scalability of the op-codes parsing? Right now it's switch/case based. The flushing part can be tricky, as I see cases when main logic doesn't care about immediate response/sharing data - and it would be good to have a single flush on the end of the frame, and sometimes you'd like to pass data from C++ while it's in its life scope. On top of that, I'd be no surprised that control of what flushes is lost. (I'm speaking from a game developer perspective, some issues I'm thinking aloud might be exaggerated) Last, some suggestion what would make developers more happy is to provide a way to change wasm compilation flags - as a C++ developer I'd love to compile debug wasm code with DWARF, so I can debug with C++ sources. To wrap up - I'm very impressed about the idea and execution. Phenomenal work! | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | gdotdesign 7 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
It's nice to see that we are converging on the same syntax I came up for Mint (https://mint-lang.com) 8 years ago (feels strange to write it down). I saw Ripple some time ago its syntax has the same structure more or less (component, style, render, state, etc...) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | Leftium an hour ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Svelte used to have compile-time reactivity, but switched to runtime reactivity via signals: https://svelte.dev/blog/runes I'm curious if Coi will also suffer from the drawbacks of compile-time reactivity. Or as its own language that doesn't have to "fit" into JS, can Coi side-step the disadvantages via syntax? Runes allowed simpler Svelte syntax while making it more clear, consistent, flexible, and composable. Support for signals may help in terms of interop with native browser JS and other frameworks: https://github.com/tc39/proposal-signals | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | publicdebates 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> It’s way more efficient, I ran a benchmark rendering 10k rectangles on a canvas and the difference was huge: Emscripten hit around 40 FPS, while my setup hit 100 FPS. Just curious, what would the FPS be using native plain pure JavaScript for the same exact test? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | rthrfrd 7 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Sounds interesting! But do you think it would be possible to achieve similar results without a new language, but with a declarative API in one of your existing languages (say, C++) instead? If possible, that would remove a big adoption barrier, and avoid inevitably reinventing many language features. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | vanderZwan 3 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I too feel like Emscripten is doing way more than it should for the vast majority of actual use-cases for WASM on the web out there. It's too heavy to install, too much of a hassle to get running, produces way bigger output than it should if the main target is a website, and adds needless friction by being largely oblivious to how the web works from the C++ side of things. The shared memory architecture + batched calls also aligns with hunches I had about unlocking fast WASM for web dev. So this sounds extremely interesting! Coi looks pretty nice! But honestly I think WebCC might actually be the thing I have been waiting for to unlock WASM on the web. Because if I understand correctly, it would let me write C++ code that compiles to tiny WASM modules that actually integrates with generic JS code very efficiently. Which would make it much easier to add to existing projects where there are some big bottlenecks in the JS code. Looking forward to giving it a spin! | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | NetOpWibby 28 minutes ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This looks great. Is it possible to import modules from npm/jsr? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | kccqzy 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> It’s a component-based language that statically analyzes changes at compile-time to enable O(1) reactivity. Unlike traditional frameworks, there is no Virtual DOM overhead This itself is quite cool. I know of a project in ClojureScript that also avoids virtual DOM and analyzes changes at compile-time by using sophisticated macros in that language. No doubt with your own language it can be made even more powerful. How do you feel about creating yet another language? I suppose you think the performance benefits are worthwhile to have a new language? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | progx 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I don't like this html-syntax, cause you use a separate syntax-methods for existing js-functions wrapped as html-tags:
As a JS/TS dev it feel unnatural to write language operations as html-tags. That is what i did not like in svelte too.Here something that looks little more like PHP-Style, better separation, but too much to type:
Shorter with a $-func for wrapping html-content
I don't know, has somebody a better idea? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | elzbardico 4 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This is the kind of innovation that coding agents make difficult to get traction. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | frankhsu 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Gotta say the Shared Memory approach is genius. Finally someone's cutting down the clunky back-and-forth. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | written-beyond 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I think this genuinely might be the first time I'm seeing a language rework for UI's that actually makes sense and incorporates all that we've learned in the modern age about UI code. What I am wondering is how language interop will work? The only way I see this growing is either you can easily import js libraries or you get a $100,000 dono and let Claude or any other LLM run for a few days converting the top 200 most used react packages to Coi and letting it maintain them for a few months until Coi's own community starts settling in. I would love to use this for non web use cases though, to this date UI outside of the browser(native, not counting electron) is still doggy doo doo when compared to the JS ecosystem. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | zigzag312 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Well, you claim to combine several interesting features. Type safety, small binary size, high performance, predictable performance (no GC). So, I'm interested how this will turn out. For web small binary size is really important. Frameworks like Flutter, Blazor WASM produce big binaries which limits their usability on the web. JS/TS complicates runtime type safety, and it's performance makes it not suitable for everything (multithreading, control over memory management, GC etc.) I wonder how much/if no GC hurts productivity. It looks like Coi has potential to be used for web, server and cross-platform desktop. Since the intermediate step is C++ I have a question what this means for hot-reload (does that make it impossible to implement)? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | arendtio 7 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
From a syntax perspective, I prefer the component syntax in Vue / Riot, which is HTML-like. That way, the general structure is clear, and you have to learn only the additional directives. As a bonus, syntax highlighting in most editors just works without an additional plugin. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | orphea 8 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Did you compare with Svelte? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | radicalethics 3 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Still holding out for a full WASM DOM renderer. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | iamsaitam 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This looks very interesting! Do you have any tips/pointers on how one could use Coi to generate a component and then integrate it into an existing project which uses a traditional Javascript framework? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | nkmnz 5 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Could this be a transpilation target for existing Vue code to achieve smaller bundle size and higher runtime speed? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | merqurio 8 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nice work ! Thanks for shating It reminds me of https://leptos.dev/ in Rust, although the implementation might be very different | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | LudwigNagasena 5 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
What are the exact features that require it to be a new language with new syntax? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | monster2control 3 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I like it. Here’s hopping it continues to grow | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | amelius 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
So the style and view parts work like f-strings in Python? That's something I could live with. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | skybrian 6 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This looks quite promising. How long does it take to compile? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | hans2002 4 days ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Binary size alone got me interested. What's missing before 1.0? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | doublerabbit 4 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
COI compiles on FreeBSD but the example app didn't.
Yet exists within /usr/includeNot a rant, but developers, please include testing on FreeBSD. Git issue raised. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | zedai00 8 hours ago | parent | prev | next [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
would love to try it soon! | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ▲ | cap11235 7 hours ago | parent | prev [-] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
https://www.gnu.org/software/stow/manual/stow.html If what you want is an orchestrated symlink farm, here's your dude. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||