RSSAmplifier

Blog

Max Leiter

Max Leiter's blog

maxleiter.comRSS feed ↗47 posts

Latest posts

Running Wayland, X11, GNOME, and KDE natively on an iPad

I like running software on devices that aren't "supposed" to run it. I own the hardware. I should control the software. And for reasons , Apple makes phenomenal hardware and operating systems, but locks them down. I've been bitter for a long time. Six years ago, when I should’ve been studying for finals, I ported X11 to my jailbroken iPad because I wanted to try using it as a "real" personal…

They're Made Out of Weights

After Terry Bisson's "They're Made Out of Meat" . "They're made out of weights." "Weights?" "Weights. Floating-point numbers. We checked the whole thing through. It's nothing but weights." "Weights doing what? Where do the words come from?" "The weights make the words. Are you understanding me? We opened it up. There's no dictionary in there, no grammar rules, no little man. Just weights. Eighty…

Per-directory terminal colors in fish shell

My terminal background color changes based on the current directory. It's a small touch that makes it easy to tell which project I'm in at a glance, which is especially useful when juggling AI agents. It works via a custom fish function called _color_for_dir , which: Hashes the current $PWD Maps the hash to a hue (0-359) Converts it to a dark RGB color Sends an OSC 11 escape sequence to change the…

Sandcastle: A web-based Linux desktop environment

Six years ago, while I should have been studying for finals, I patched and compiled X11 (and all its dependencies) to run on a jailbroken iPad . I wanted to run real applications on my tablet. I've spent the last few months weeks days hours building vibecoding something that feels like a better solution: a Linux desktop environment, on the web. I wrote zero lines of code. You can try it out here ,…

How we made v0 an effective coding agent

Learn how we built v0 to be an effective AI coding agent through careful system design and iteration. Read on vercel.com

Introducing HFSViewer

Last year my roommate and I found an old original iMac G3 outside our apartment building. It has some interesting early 2000s/late 90s style websites and files on it that I want to preserve (and hope to share here soon!). But I realized getting files off of it wouldn't be easy. The machine is running macOS 9.2, which supports USB 1.0. We're up to USB 4 now, so thats pretty old; none of my modern…

The new maxleiter.com

I redesigned maxleiter.com this week. I've wanted to make it more personal and opinionated for a long time, but felt I lacked the expertise to do it justice. With v0 and Claude Code (and some manual cleanup) it only took a few hours. If you haven't played with the homepage yet, some of the features are: Draggable and resizable windows, including the blog posts A web-friendly version of KnightOS in…

You should be rewriting your prompts

I've been "lucky" to work with a lot of different LLMs over the past few years (there is, in fact, a reason we made the AI SDK ). When a new model is publicly released there's a good chance we've already tried it and evaluated it for use with v0 within a few hours. Our results do not always improve as expected, even when we use newer and strictly better models[^1]. Another example of this is when…

I have seen the future through AR glasses

I like to try new technology. 75% of what I buy is something I use once or twice then sell or give away (or keep in a drawer and forget about. Sorry, remarkable). But sometimes, on rare occasions, there's a product that is A) fucking awesome and B) I can't help but evangelize. One of my more recent purchases was the XReal One Pros , and wow: I have seen the future, and it's through AR glasses. If…

Formatting code should be unnecessary

I had a (maybe slightly overqualified) computer science teacher back in highschool, Mr. Paige. He worked on the Ada compiler and has been programming since the early 80s. One day I complained about linter tooling that was driving me nuts. I said something to the effect of, "it's 2016, how are we still dealing with this sort of thing?" Turns out, that problem was solved four decades ago (well,…

Vibe-coding Minecraft mods

{/* eslint-disable react/jsx-no-undef */} If you aren't familiar with the extent of the Minecraft modding scene, it's big . There are mods with more thought put into them than many AAA games. The best example is Create : { Note that trains (and windmills and assembly lines) are not built into Minecraft. } So I was pretty lost when I started playing for the first time in a long time. Table of…

Implementing Notion style URLs

I hate unrecognizable URLs. If I want to go back to a specific document or page, I should be able to type the name of it in the address bar and find it in my browser history. Notion is particularly good at this, and v0 was particularly bad at it (for a while), so this is what I did to fix v0. Here's what a notion URL looks like: <span style={{ fontFamily: 'monospace', fontSize: '1.2em', }}…

Introducing the v0 composite model family

Introducing the v0 composite model family. Read on vercel.com

Reduce Cognitive Load

The AI team at Vercel has been growing; what was five people a year ago is almost 15. In most ways, this has been fantastic. But it's been a challenge, too. More people are reading my code, and I'm reading theirs. A lot of time can be spent just trying to understand what's going on, even if it's a code base you're familiar with, to no fault of the author. I've been thinking a lot about how to make…

Never think about branch names again

I recommend swapping out `max` to basically anything else. #!/bin/bash # Get the current month and day month=$(date +%m) day=$(date +%d) # Prefix the branch name with max/{month}-{day} branch_name="max/$month-$day-$1" # Checkout the branch git checkout -b "$branch_name" To use on macOS/linux, you can paste the above into a file in `/usr/local/bin` and make it executable with `chmod +x…

Updating JSONB fields with Drizzle

I recently made a jsonb column in a postgres database and it took me a bit to figure out how to update a single value without overwriting the entire field. If you know a better way please let me know. import * as schema from './schema' export async function updateThing(id: string, title: string) { return db .update(schema.thing) .set({ metadata: sql`COALESCE(${schema.thing.metadata}, '{}')::jsonb…

Ship something every day

Edit : A better title would've been " commit every day that you work ". I don't mean you should work on weekends or not take time off, and whatever you work on doesn't need to "ship to prod". I don't feel particularly qualified to give advice (I blame imposter syndrome), but I do have one tip to share that I think has been useful for me. It applies both to professional software dev and personal…

Set your default directory in VS Code's open dialog

This is my workflow for opening a project in VS Code: Open an empty window of VS Code Hit cmd+O Navigate to my `~/Documents/...` directory Hit enter In my opinion, that's a few too many steps. I've made it a little better by changing the `files.dialog.defaultPath` setting (added almost exactly one year ago ). Hope this helps.

gemini.sh script

As of late 2024/early 2025, I recommend using the great repomix tool: https://github.com/yamadashy/repomix I've been messing with gemini-1.5-pro with the 1 million token context window for a while now and found this script very useful for grabbing entire repos. It ignores most binary files and concatenates the rest into a single file. You'll need to have `parallel` installed for this to work…

Sending a Slack message with fetch

I like using Slack bots for things like alerts and notifications and have needed this snippet enough to leave it here. I use slack-block-builder to build the message; writing raw slack blocks is a pain. const res = await fetch('https://slack.com/api/chat.postMessage', { method: 'POST', headers: { // IMPORTANT! You need to set the charset to utf-8 'Content-Type': 'application/json; charset=utf-8',…

SWR for more than fetching

SWR is a great library for data fetching in React. It looks like this: import useSWR from 'swr' export function MyComponent() { const { data, error } = useSWR<string>('/api/data', fetcher, { refreshInterval: 1000, fallbackData: { name: 'swr' }, }) } But my favorite use for it is local state management. Here's an example of how I use it for modals and dialogs: import useSWR, { mutate } from 'swr'…

Loading wasm files on Vercel Edge and Node.js runtimes

Loading wasm on the Vercel Edge runtime is easy. You need to do a little more work to do the same on Node.js. async function getWasmNextJSEdge() { // Webpack and Turbopack can tree-shake this. if (process.env.NEXT_RUNTIME === 'edge') { return (await import('./file.wasm?module')).default } } async function getWasmNode() { if (!process.env.NEXT_RUNTIME || process.env.NEXT_RUNTIME === 'nodejs') {…

watch.sh

A simple bash script for macOS that runs a command and displays a notification when the output of the command changes. #!/bin/bash if [ $# -eq 0 ]; then echo "Usage: $0 <command> [sleep_time]" exit 1 fi COMMAND="$1" SLEEP_TIME="${2:-3}" PREV_OUTPUT=$($COMMAND) while true; do CURRENT_OUTPUT=$($COMMAND) if [ "$CURRENT_OUTPUT" != "$PREV_OUTPUT" ]; then osascript -e 'display notification "Command…

Introducing AI SDK 3.0 with Generative UI support

Stream React Components from LLMs to deliver richer user experiences. Read on vercel.com

Some tips for working with Next.js 14

I've been working with the Next.js App Router for a while now, and wanted to share some of the patterns and snippets I've found useful and keep referring to. My goal is for this post to be a living document, but I haven't been great about writing much so we'll see about that 🤷‍♂️. I'm assuming you have some familiarity with the App Router. If you don't, I recommend you check out my older post:…

Transcribing with AWS Textract

My family has (in my opinion) a very cool written history of our family tree on my father's side. Recently, my grandfather found a renewed interest in the book and decided to digitize and update it. He took it to a local print shop and had them scan it to a PDF (it's 60+ pages), which resulted in scans like this: It seems like something for OCR , but no tool I tried could handle the font and the…

Introducing the Vercel AI SDK

An interoperable, streaming-enabled, edge-ready software development kit for AI apps built with React and Svelte. Read on vercel.com

Why your website's fonts might be larger than intended

Someone recently reported that the font-size in some of my code blocks on my build-your-own Next.js blog post was too large. That's interesting because I use React and the code blocks are the same component. So why would the font-size be different between them? I was able to reproduce the issue and found that it only happened on iOS devices. Here it is in action: <img src="…

Nintype is still the best iOS keyboard

Describing Nintype is a challenge. Here's a the demo video from it's launch back in 2014: "the true touch typing experience" Essentially, Nintype is a keyboard that enables you to swipe and tap with both hands at the same time. If you're typing "there", you'd swipe the `th` with your right hand, and tap or swipe the `ere` with your left. It's such elegant and obvious next step for swipe keyboards…

Building a blog with Next.js 15 and React Server Components

I've been tinkering with this website and the Next.js 13 App Router for a while now, and it's been a great experience, especially in the last few months. But I've seen some confusion around how to use the new features and React Server Components, so I wrote up an outline on building this website. {' '} This post has been updated for [Next.js 15.](https://nextjs.org/blog/next-15){' '} To address…

Improving the accessibility of our Next.js site

We've made some improvements to the accessibility of our Next.js site. Here's how we did it. Read on vercel.com

The Node ecosystem (still) has tooling problems

I recently published a small npm package containing a Vue library. The package is written in TypeScript powered by Vite, which I (wrongly) assumed would mediate most of my woes. First, I used Vite to build a small front-end site to demonstrate the library. This let me test the component and demonstrate usage in the same repository. Getting this working was fairly straight forward for someone with…

Live updating page views with Supabase and Next.js

This post was written for the (now stable) beta Next.js middleware. If you want your own analytics, I recommend looking at{' '} Vercel's solution. This post starts with a brief introduction. If you want to jump down to the tutorial, click here . You can also see the live updating views in action in the top right of this page! The analytics events themselves require no JavaScript and occur…

Internet Explorer or CSS3?

I was watching Reactathon 2022 this weekend and enjoyed the Syntax fm live session. They did a great audience interaction bit with quizzing them about what a particular piece of CSS did. I decided to take a look into Supabase (coincidentally, they just raised a modest $80M series B). I'm happy I did, because the ease of setting up the database and realtime support was incredible. With a few hours…

Easy ways to improve your websites accessibility and performance

Below is a short list I wrote up for people who are comfortable building websites (with any technology) but want to improve their work, whether that be in terms of loading speeds, software quality, or accessibility. TL;DR: Use WAVE Compress your images Embrace semantic HTML Don’t use JavaScript to replace browser controls Invest in learning your developer tools WAVE WAVE is a suite of tools for…

How hackers* run their sites

* hackers: users of hacker news Yesterday, when I probably should have been doing something productive, I instead asked hacker news users for links to their personal sites . It got far more replies than I expected (over 1000 at the time of writing) so I had the idea to do some scraping and see how commenters build and host their sites. I wrote a quick-and-dirty typescript script (at the bottom of…

Introducing Drift

View this post on Drift I've wanted a Gist alternative for years, but it wasn't until I saw this tweet I decided to sit down and build it: "What is the absolute closest thing to GitHub Gist that can be self-hosted? In terms of design and functionality. Hosts images and markdown, rendered. Creates links that can be private or public. Uses/requires registration. I have looked at dozens of…

How to start contributing to open-source projects

One of the most common questions I'm asked by my computer science friends and students is how they can contribute to an open-source project. In order for me to organize and share my thoughts I thought I'd write something here. First off, it's a good idea! Contributing to projects is a fantastic way to build experience, connections, and improve a piece of software you use or rely on. I've grown…

Pin your npm/yarn dependencies

Today, the open-source maintainer Marak intentionally bricked two popular JavaScript libraries (with ~25 total million weekly downloads) in such a way that they broke dependents software. There's nothing that npm or any other public registry could've done to have prevented this; the release was indistinguishable from a regular update, unless you looked at the code. This is not the first time an…

My macOS programs and setup

In the off-chance you're reading this today, happy new year! If you're reading this later, I hope $CURRENT_YEAR is treating you well. Before this post, I kept a list of my programs in my iCloud in case my computer broke or I was setting up a work laptop. After some recent events, I trust iCloud less than I once did, and figured the list can live here instead. Like the rest of my blog, this exists…

useMousetrap()

I've been messing around with a React implementation of The Lounge lately (for no real reason except that I can) and wanted a functional way to use Mousetrap , which TL already uses. The below hook let me replace the Vue use of Mousetrap (which was pretty much vanilla JS) in a React-like fashion. For bonus typing, add `@types/mousetrap` to your project. Usage is pretty simple:…

Creeper Host API wrapper in TypeScript

I've had a server on Creeper Host for around eight years now, and have used it for small side projects and hackathons. Lately, I've been trying to automate more of my life and discovered that the API their in-house control panel uses is available for general use . I'm making this post in case someone else ever wants to interact with their API via JavaScript. Maybe someday I'll create a proper…

run-pr.sh

Today I found myself once again trying to run a pull request that was created in a different GitHub repository. If it was in the same repo, it would be a simple `git checkout`, however because GitHub insisted on the creation of "forks" I now need to go through the extra steps of fetching that specific ref. Here's what I do: git fetch https://github.com/${team}/${respository}.git…

Impressions of the Framework Laptop

I received my Framework Laptop DIY edition a few days ago and have been setting it up software-wise. I have it running Manjaro Linux with the Sway window manager. This is my first time using a Wayland desktop, and oh has it been a learning experience. This post will be largely about the hardware, but I plan to make one about the software once I'm more happy with my setup. Here's what I got:…

Adding ambient light support to Linux and GNOME

A couple of a weeks ago I picked up a Surface Pro 7 (i3 1.2 mhz) at a Black Friday sale. I love making devices run software they shouldn't, so I got to work dual-booting Linux on it. To my surprise, almost everything worked with the default Fedora 33 kernel, not including the touchscreen, the ambient light sensor, and the camera. After compiling and loading the great linux-surface kernel the…

New edge dev infrastructure

New edge dev infrastructure. Read on vercel.com

X11 on iOS

This work has been picked back up recently, with KDE, GNOME, Wayland, and more. Read about it here: https://maxleiter.com/blog/xios I'm excited to announce that X11 is coming soon to iOS. Most (see below) packages and dependencies for a fully functioning X11 desktop system have been compiled and are available on Cydia for iOS 11+. All packages have been compiled for arm64 and have been tested on…