π Termweave turns an OpenTUI + React interface into a native desktop app β running inside a real CRT monitor. You bring the vibes, termweave brings the machine.
You write React β we handle:
- π¦ The native window, terminal renderer, app lifecycle & packaging
- πΊ The whole CRT: bezel, tube optics, power-on click, ambient hum
- πΌοΈ
PixelRendererβ PNG/JPEG backdrops under your UI - π§
ThreeRendererβ three.js scenes in the tube, RGB332-quantized like everything else - πͺ
SpaceObjectβ proceduraly generated universe as a starter example - βοΈ One
app.config.json: name, colors, bundle metadata - π₯ Live reload without restarting the window
- β‘οΈ One command to a native
.app+.dmg
- π€ AI agents that deserve a home screen, not a boring terminal
- πΉοΈ Retro games that want to feel like 1998
- π¬ ThreeJS dataviz people actually screenshot
You need macOS, Bun 1.3+, Rust, and the Xcode Command Line Tools.
bun install
bun run devThe monitor turns on. Press Ctrl+C in the window to quit. That's the whole tutorial. β¨
app/App.tsxβ your interfaceapp.config.jsonβ name,themeColor, bundle metadataapp.icon.pngβ your icon
Edits under app/ hot-reload. Change the config or icon β restart bun run dev.
This is the part that makes people go "wait, what?" β a monitor bezel around a live tube with physically calibrated optics:
- π Barrel curvature
- π Chromatic fringe
- β¨ Bloom & scanlines
- π The power-on click and a low hum
All rendered on the terminal's own GPU, never a canned overlay. Your themeColor repaints the whole machine β tube, bezel, glow.
import { PixelRenderer } from "#termweave";
import bg from "./assets/bg.png" with { type: "file" };
export function App() {
return (
<PixelRenderer uri={bg} width="100%" height="100%">
<box position="absolute" bottom={0} width="100%" height={8}>
<text>overlay whatever on top</text>
</box>
</PixelRenderer>
);
}Your terminal, but it's a little world. π
import { ThreeRenderer, useFrame } from "#termweave";
import { Scene, PerspectiveCamera, Mesh } from "three";
export function App() {
const scene = new Scene();
const camera = new PerspectiveCamera(50, 1, 0.1, 100);
camera.position.set(0, 4, 10);
// scene.add(...) your geometry
useFrame((dt) => {
// mutate the scene; 30fps, only ticking while mounted
camera.rotation.y += dt / 1000;
});
return (
<ThreeRenderer scene={scene} camera={camera} width="100%" height="100%">
<text position="absolute" top={1} left={4}>overlay text</text>
</ThreeRenderer>
);
}Renders through the same super-sampled pipeline as PixelRenderer π§. Everything goes through the tube.
<SpaceObject> generates πͺ PixelPlanets and drops them straight into your CRT, over the darkened starfield.
import { SpaceObject, randomSpaceObjectConfig } from "#termweave";
export function App() {
// roll it β or hand-write the config: { type, seed?, palette?, layers? }
return <SpaceObject object={randomSpaceObjectConfig(1234)} backgroundSeed={5678} />;
}- πͺ 12 types: terran wet/dry, islands, no-atmosphere, gas giants (ringed β¨), ice & lava worlds, asteroids, black holes, galaxies, stars
- π¨ Curated, space-truth palettes: earth, mars, moon, jupiter, saturn, neptune, europa, gargantua, milky-wayβ¦
- π±
seed= the geography β same palette + new seed = whole new world - πΈ One static frame per config β deterministic (same config in, same pixels out), the GPU naps between renders
- π
backgroundSeedjust reshuffles the starfield
| command | does |
|---|---|
bun run dev |
run it, live reload |
bun run build |
native .app + .dmg |
bun test |
tests |
bun run typecheck |
types |
MacOS only for now (arm64 & x64). Bundles build for your machine.
Issues & PRs welcome. β Star the repo if you ship something cool β and share what you made.
π A config-driven Tauri and OpenTUI builder for native desktop terminal apps.
terminal cli tui terminal-user-interface terminal-based react typescript rust tauri webgl threejs opentui pixel-art procedural-generation crt retro retro-terminal developer-tools ai-agents hacktoberfest
