Documenting here the projects/hacks I've posted so anyone who stumbles upon my profile can see what I've built! Ordered by amount of likes:
1. An IDE + GUI for writing ffmpeg commands
I got fed up writing FFmpeg commands. Its unintuitive, and can get ugly and complicated quickly
A couple of months ago, I built this GUI to help me write complex ffmpeg filtergraphs that we have been using internally and decided to launch today.
I got fed up writing FFmpeg commands. Its unintuitive, and can get ugly and complicated quickly
A couple of months ago, I built this GUI to help me write complex ffmpeg filtergraphs that we have been using internally and decided to launch today.
I wrote a 2D game, entirely in type-level Typescript.
Yes, you read that right. This is flappy bird, written only in Typescript types.
How did I do it? It involves a lot of type magic, and a new type-level Typescript runtime I made in Rust + Zig.
Let me walk you through it:
Got tired of tsc taking forever to type check my code so I made a Typescript type checker in Rust for fun
For a small Typescript file it's 500x faster than tsc taking ~0.002s vs ~1.3s (using SWC for compilation). It supports only a small subset of Typescript (for now).
It's not Zig vs Rust... its Zig and Rust
An unexpected power combo for a project I'm working on.
Doing the high-level things in Rust, and the hardcore low-level stuff in Zig
Update: I'm joining the
@bunjavascript
team
But I won't be writing Zig code, I quit programming several months ago to pursue my passion in artisan baking
My role will be ensuring that the Bun team is well-fed with pastries, breads, and, naturally, buns
When Zig is safer and faster than Rust:
I recently wanted to compare Rust vs Zig, so I wrote a garbage collected bytecode interpreter in both languages
It turned out that the Zig version was actually faster AND safer than the Rust version
How come?
So happy everyone's excited about the project I've been working on!
I build interpreters for fun, building a shell might be the hardest one I've built yet
It took me ~20k lines and 2 months, but was so fun
Maybe one day I'll write a blog post on the process
Initial thoughts:
1. Copilot is terrible for systems programming, I actually have it turned off for Rust and Zig. Most problems you solve just aren't represented well in the training data, so copilot just suggests absurd shit. Supermaven seems to be slightly smarter, I guess…
Five years ago I created TabNine, the first commercial code completion tool to use deep learning.
Today I'm releasing Supermaven, the first code completion tool with a context window exceeding 100,000 tokens.
Most people think Rust is a low-level language, but writing in it actually feels very, very high-level
Rust gives you:
- type-directed metaprogramming (traits)
- operator overloading
- generics
- algebraic data types + pattern matching
- FP-style functions (.map, .filter, etc)
Rust has features people associate with "low-level", namely the ability to manipulate memory on the level of bits and bytes
But the Rust experience is mostly about high level interactions with the borrow checker or constructing abstractions within the type system, etc.
Are you sick of Go's inflexible type system and its lack of sum types (tagged/discriminated unions)?
I'm going to show you how to hack Golang and add sum types to the language:
Programming just hits different when you write a class in Zig that schedules a task on the event loop, add it to the Bun global, and then call and await it from JS
It feels like you're a sorcerer with the ability to bend javascript to your will
Working on adding glob matching support to Bun
Bun.Glob is 6.54x faster than "fast-glob" at matching all js files in node_modules (~80ms vs ~550ms)
I think this is also my first legit open-source contribution ever
Got tired of nvim/VSCode being slow so I made the code editor I'm building with Rust + OpenGL run at ~100 FPS.
This is a more than 2x improvement over nvim/VSCode which run around ~45 FPS (or worse when scrolling).
OOP really disillusioned generations of programmers into thinking the way to do polymorphism is to construct overly complex class hierarchies instead of just using sum types (tagged/discriminated unions)
Working on adding glob matching support to Bun
Bun.Glob is 6.54x faster than "fast-glob" at matching all js files in node_modules (~80ms vs ~550ms)
I think this is also my first legit open-source contribution ever
Every video editing software I've used has always felt clunky and hindered my creativity.
So we're hacking on a crazy idea - "an infinite canvas timeline", a space that gives you the freedom to experiment, where collaboration is a core primitive and iteration can happen quickly.
Hey
@gather_town
i reverse engineered your websocket protocol and am spawning infinite gokarts onclick at the
@buildspace
demo day event
cant believe they paid 6k for this :P
@wileycwj
well to be honest it's very rare that you have to write out a type like this
but typescript is no stranger to big ass confusing types, it would look like this in typescript:
It also has autocomplete with documentation embedded right in the UI, my goal was to make this feel somewhat like an IDE for FFmpeg filters
This is my favorite feature, helps me maintain flow state and never have to waste time flipping to FFmpeg documentation
It's using SWC to parse Typescript, then it type checks the returned AST. Right now it supports a subset of TS's type system with the end goal of reaching feature parity with Typescript and possibly making an LSP server that goes brrr
In the end, the Zig version was not only safer and faster than the Rust version, but also much easier to write.
I talk more in depth on why in my new blog post:
It does analysis on your graph and filters to make sure they're correct. For example you've properly connected nodes, your filter arguments are correct, etc.
This is huge, a lot of cool tech written in Rust to explore and learn from
The CRDT implementation and GPU accelerated UI framework are probably most exciting
Zed is now open source!
Our mission is to revolutionize developer collaboration, building the world's best code editor in the process. After working together in Zed as a small team, it's time to scale up to transform Zed into a collaboration platform.
I'm thinking of making a "Zig for Rustaceans" guide/blog post/etc
Should I?
As a big Rust fanboy, it wasn't clear what Zig gave me that I couldnt get out of Rust. Turns out, its a lot, and I wanna share that
Learning Rust at least 5x'ed my coding skill, and Zig 5x'ed it again
How noisy a programming language's syntax is plays a big role in detecting bugs and errors in code
It's a subtle reason why raw manipulation of memory in Zig feels way less error prone than C or C++ or Rust. Zig code is just easier to scan and read
Fundamentally, Zig is a language that understands you are going to do memory-unsafe things and is designed around making that experience better and less error-prone.
I'm aware that SWC is making a type checker, but it still isn't clear if it was going to be open source or commercially licensed, so I decided to make my own for personal use and fun
We wrote a lil experimental compiler that desugars ts-pattern match expressions into regular if statements!
The way it's done is cool if you're interested in compilers:
Introducing 🎂 pattycake
An optimizing compiler for ts-pattern for 10x faster performance
Now, you have your cake (expressive pattern matching), and eat it too (zero runtime overhead).
Setup in <5 minutes:
A benchmark showing that ts-pattern is surprisingly faster than you'd think.
It takes ~0.88 ms for it to match 1k random objects.
pattycake removes the runtime overhead so it runs in 0.01ms, but for most usecases that perf boost is negligible
"JIT happens"
This is cool.
TS-Pattern is faster than most people think, and it's unlikely for code branching to be the perf bottleneck of your app, but compiling its runtime away is an interesting idea for perf critical code. Thank you for exploring this path
@aidenybai
&
@zack_overflow
!
But that's not all. By creating this runtime, I also accidentally created probably the fastest and most complete type-checker for Typescript, but types only.
This was a terrible idea. We didn't really solve any of our original problems. We kind of implemented sum types but it ended up being not worth it in terms of performance or ergonomics.
Blog post goes in more detail with other attempts too:
@TythosEternal
I consider Rust to be a pretty high level language. Most of my time in the language is dealing with high level abstractions, which are zero-cost and compile to very efficient machine code, but are nonetheless quite high level.
The language also lets you do low level things if…
Rust's language design is optimized around making it so you never need to do memory-unsafe things.
I had a difficult time because almost everything I was doing was breaking the borrow checker's rules and treading in territory Rust wasn't designed for
So to compete with Zig (and also for for fun), I decided to practice the dark arts and use unsafe Rust.
It turns out that unsafe Rust is hard. There are a lot of complicated rules about undefined behaviour. It's super easy to violate them and cause subtle bugs
I then compile the runtime to Wasm, and each frame it takes the draw commands from the game and executes them using the web canvas API.
And that's the basic overview of how I made flappy bird in type-level Typescript!
More detail in this blog post:
So each frame, we pass the game state through a series of updates that need to happen each frame: handling jumps, applying gravity to the bird, moving the pipes.
The end result looks something like this, and its a surprisingly elegant, linear, pipelining of functions:
Garbage collection is a hard problem to solve in Rust, it fundamentally is something that doesn't play nicely with the borrow checker.
It's possible to write one in safe Rust, typically using refcounting or arenas+handles, but those seem to be slower than a typical mark/sweep gc
First off, type-level Typescript can be thought of as a purely functional programming language, where everything is immutable.
So we can't have some global game state (bird position, pipes, etc.) and mutate it
What we can do is use functions to return a new, updated game state
Cool thread-safe triple buffering approach made lock-free by atomically swapping the pointers to the buffers
Thinking about using this for my code editor when I add LSP support
The main render thread needs to get data from the second thread which manages the LSP server process
At
@modfydotvideo
we wrote our own test runner because we hate Jest. It's:
- 12x faster than Jest
- 11x faster than Vite
Here's a basic benchmark (take with a grain of 🧂) comparing it w/ other test runners. We're thinking of releasing it, pls let us know if you would want this
The recent Unity debacle has inspired me to build my own game engine for fun and completely from scratch in C
So far I've implemented loading glTF models, vertex skinning, skeletal animations, and crossfading smoothly between animations
And here is the final Typescript code for the game, if you wanna check out my unholy type-level trickery.
It's actually not that bad, just the moving pipe logic and the collision with pipe logic is unsightly because it needs to do iterative recursion
some people ask about the quote in my bio: "this guy's all boners for Rust" —
@ThePrimeagen
that's an actual quote, he said that about me on stream while reading my blog post
here's the clip:
My hope is that by focusing on nailing down type-checking type-level Typescript first, which is a way easier task than all of Typescript, the runtime can be useful very quickly.
Check out the source here:
And play the game here:
Yes, you can do low-level things in Rust. But 95% of the time you don't need to, you can stay in the realm of high abstractions and get good perf because of the borrow checker and zero-cost abstractions
Some of my most productive days are when I wake up and code in bed for 8 hours straight
Or when I'm laying in bed about to fall asleep, but get a wind of energy and code until 8 am the next morning
The basic rundown is that I created a type-level Typescript runtime, allowing types to be run outside of the Typescript compiler/language server.
It's made of two parts:
1. A compiler in Rust to convert Typescript types -> bytecode
2. A custom VM in Zig to execute that bytecode
The next part is rendering. I drew inspiration from modern graphics APIs and added a command buffer to the game state: basically a list of drawing commands
Each frame, we update the game state, and populate the draw command buffer.
In the end even rendering becomes elegant too:
Do you like state machines and type-safety? I wanna share a wip library I'm building to make working with state machines easier and more type safe in typescript.
It's like XState.js had a baby with Zustand
lemme walk u thru how it works
Okay, that's the type-level logic. But in the video, the game is running in the browser, how does that work?
This where some hardcore programming comes into play.
@rhesus_kato
it's not a real field, but a marker type to tell the compiler to treat ListIter<'a, T, N> as if it were borrowing a reference to List<T, N>
1/ Starting my journey on learning CRDTs seriously and more in-depth and going to be documenting it for others and for fun.
If you don't know about CRDTs they're the data types that power collaborative features in multiplayer apps like Figma
changed my github profile picture to one with my feet
so everytime someone links a PR in bun that I made
you'll see my feet in the og image
my feet now watch over all my commits
Always thought the name WebAssembly is super misleading. Wasm has nothing to do with "assembly" in the traditional sense.
It's really a specification for a bytecode format, and an accompanying virtual machine that can interpret that bytecode.
But WebBytecode sounds less cool.
I got fed up writing FFmpeg commands. Its unintuitive, and can get ugly and complicated quickly
A couple of months ago, I built this GUI to help me write complex ffmpeg filtergraphs that we have been using internally and decided to launch today.
There is always an overhead from copying/serializing/deserializing data from WASM -> JS and vice-versa and it can be bad for perf.
For WASM to outperform JS you kinda have to minimize how frequently data crosses the JS/WASM boundary, to reduce this redundant copying/computation
@cpojer
I've wanted to make a babel/swc/bun transform pass that desugars ts-pattern api calls into regular switch cases so you there is no or at least minimal runtime overhead incurred from the lib
I also think Rust + Zig is not explored enough
I tried it and it worked really well for me, using Rust for the high-level things and Zig for hardcore low-level programming
It's not Zig vs Rust... its Zig and Rust
An unexpected power combo for a project I'm working on.
Doing the high-level things in Rust, and the hardcore low-level stuff in Zig
@sacsbrainz
I learned Rust by building a compiler and I learned Zig by building a VM
My trick is to pick hard projects that fascinate me so I'm motivated to keep going
stc, the effort to rewrite TypeScript in Rust, has been abandoned.
All in all, I'd say fair enough - it proved to be an impossible goal.
Here's the interview I did with
@kdy1dev
back when he was in full swing working on it.
If you're interested in baking bread or writing hard-core & high-performance Zig/C++ with me, check out our open roles:
And feel free to DM me if you have any questions: the process, or the type of work we do, etc.
@Fly1ngT0a5t3rs
@acemarke
in a way
@GrugBrainedDev
would explain it:
compiler/linker => compiler turn source code into machine code. linker combine pieces machine code together, make runnable program.
transpiler => take source code one language, produce source code another language.
interpreter => read…