First feature release after the v1.0 ship a few weeks back. Three things worth calling out:
H.264 hardware encode for screen share. Previously K-os used libvpx (VP8) software encode for every frame, which turned the CPU into a heater during a 1440p stream. The streamer now probes for hardware H.264 (NVENC on NVIDIA, QuickSync on Intel, AMF on AMD, VideoToolbox on macOS, VA-API on Linux), falls back to libx264 or VP8 software if none are present, and tells viewers which codec it picked so they open the right decoder. Anything with a GPU made since ~2010 has hardware H.264 support, so this is essentially a free CPU/battery win for almost every user.
Voice/video SFU got way cheaper. The server used to decrypt every incoming UDP packet, re-encrypt it once per viewer, and forward — which scaled badly with channel size. v1.1 swaps that for a per-channel shared key (Path B): senders encrypt once, the server forwards bytes byte-for-byte, viewers decrypt. Add Opus DTX (don't transmit during silence), in-band FEC (recover single-packet losses without click/gap), and median-based bitrate adaptation so one slow viewer can't anchor everyone else down, and a large voice channel actually feels alive now.
Theme sharing. Settings → Appearance gained Import and Export buttons. Anything dropped into a themes/ folder next to the binary shows up in the theme picker. The three built-in themes (Dark, Light, Korra) stay hardcoded, so they're always there as a starting point — export one and you've got a template to fork.
License switched from MIT to AGPL v3. Anyone modifying K-os and running a public server now has to publish their changes, same as Mastodon / Nextcloud / Matrix's Synapse. The full text is in LICENSE; operator obligations (COPPA, GDPR, network-use trigger under AGPL §13) live in the new DISCLAIMER.md. Also: registration now has a "I am 13 or older" checkbox.
Smaller things in the box: NACK aggregation so retransmits don't storm, TCP upload backpressure, incremental playback drop on overrun, and a new Epoch primitive that prevents stale decoder events from firing across stream restarts. Full list is on the release page →.
Last release I said the next thing on the list was a weather radar. Here it is — animated precipitation, right in the app.
The radar. Hit Radar and a window opens centered on your location with the last couple hours of precipitation plus the short-range nowcast, as animated frames you can play or scrub. Each frame is labeled with the actual time it represents — "2:10 PM (-20 min)" for an observation, "+30 min forecast" for a nowcast frame — so it's always clear whether you're looking at the past or a prediction. Drag to pan, wheel to zoom, and there's a little wind gauge in the corner showing which way the wind's pushing things.
Drawn locally, on purpose. The radar imagery comes from RainViewer (free, no key). Everything under it — coastlines, state and country borders, county lines, interstates, and city/town labels — is drawn by the app from public-domain Natural Earth vectors bundled in the download. Nothing about the map is fetched from a tile server that could log it; the only request that leaves your machine is for the radar tile itself. Same free-and-private posture as the rest of the app.
Getting it to behave. Two problems were worth the trouble. RainViewer rate-limits bursts, and naively grabbing every animation frame for the whole viewport at once trips that instantly — so the app now fetches the frame you're looking at first, prefetches the rest only while animating, reuses connections, and backs off when it's told to. And because RainViewer's data only goes so deep, zooming past it used to show a "zoom not supported" tile; now the app stops requesting past that point and upscales the data it already has, so zooming in just goes soft instead of blank — like every slippy map you've used.
A sky panel that rotates. The Sky panel became a little weather-channel carousel: it cycles (and pauses when you mouse over it) through the sunrise arc / moon / aurora view, an air-quality breakdown with plain-language guidance, the NWS Area Forecast Discussion — the actual narrative a forecaster wrote — an almanac comparing today to the 1991–2020 normal, and tides plus wave height on the coast.
The smaller stuff. A one-line daily takeaway sits atop the current conditions ("Strong sun today — sunscreen if you're out midday"). Rain about to start now fires a push notification, and clicking any notification brings the app up. And there's a light theme now, if the dark Korra palette isn't your thing.
MIT-licensed, on GitHub, Windows build is portable — unzip and run.
This one was mostly about making the data more accurate and more useful while keeping it free and key-less. The headline addition is a minute-by-minute rain nowcast — a single line that tells you "rain starting in ~20 min" or "stopping in ~15 min," pulled from Open-Meteo's 15-minute precipitation series.
Official alerts, not just my guesses. 1.0 derived its own alerts from the forecast. 1.1 adds real US NWS watches and warnings and ranks them above the derived ones, so a tornado warning looks like a tornado warning.
More of what a weather app should show. Current conditions now include air quality (US AQI), UV index, dew point, visibility, and barometric pressure with a 3-hour tendency (rising / steady / falling). The 7-day forecast shows a cross-model confidence chip per day — when the models disagree, you see "low," and the headline high/low is clamped to stay inside that range so the number never contradicts the spread. The 24-hour view got a temperature/precip trend chart that lines up with the columns and scrolls with them; hover any hour for the per-hour rain or snow amount.
A sky panel that knows the time of day. The old "Tonight" panel is now Sky: a sunrise→sunset arc with the sun riding it at the current time and a contextual "Sunset in 3h 34m" / "Sunrise in 8h 12m" countdown, sitting next to the moon phase, aurora odds and active meteor showers.
Little things that add up. A quick-look card when you hover the tray icon. Exact-coordinate entry and one-shot OS geolocation. A "vs yesterday" line. And a performance pass: the forecast now paints immediately on launch (air quality, the model band, aurora and official alerts fill in a beat later instead of blocking the first paint), and the app quits promptly — in-flight network requests are aborted on exit instead of holding the window open while they time out.
There's also a small unit-test suite now, so the parsing and alert logic stay honest. It's MIT-licensed and on GitHub — the Windows build is portable, unzip and run. Next on the list: an open, privacy-clean weather radar built from public-domain NOAA data.
The Windows (x64) build of VidConverter v1.0.0 is now up alongside the macOS one. Download →
It's a portable VidConverter.exe — unzip and run, nothing written to Program Files. FFmpeg does the encoding, so install it and put it on your PATH (winget install Gyan.FFmpeg). The build is unsigned for now, so SmartScreen may ask the first time — More info → Run anyway — and there's a SHA-256 on the release page if you want to verify the download.
The companion yt_fetch YouTube-downloader CLI is a separate optional download on that page — it bundles yt-dlp, same FFmpeg-on-PATH requirement. A Linux build of the same v1.0.0 is still to come.
A universal media converter that wraps FFmpeg in a friendly Tk GUI and a scriptable CLI — same engine behind both. MIT licensed, source on GitHub, and now wearing the Korra theme so it matches the rest of the family.
Highlights:
- Every format that matters — WebM, MP4, MKV, MOV (incl. ProRes), AVI, FLV, animated GIF, audio-only (MP3 / AAC / FLAC / WAV), professional audio (AIFF, 24-bit / 32-bit-float WAV), and TIFF/PNG image sequences. - Profiles, not flag-memorization — tuned High / Balanced / Fast presets per format, savable custom profiles, and a manual codec/CRF/preset panel when you want the wheel. - Batch + scripting — convert shell globs or a JSON manifest that gives each file its own settings, all from the CLI. - YouTube fetch — a companion yt_fetch CLI grabs videos by URL via yt-dlp and converts them in one step. No account required. - Zero Python dependencies — standard library only; FFmpeg does the encoding.
macOS (Apple Silicon) build is up now; Windows and Linux builds of the same v1.0.0 will join it once they're cut from the respective hardware. Needs FFmpeg installed (brew install ffmpeg), or run it from source on any platform with python vidconverter.py.
New project, first release: weather desktop is out. Download → · Source →
It's a small native weather app that lives in your system tray — built with SDL2 + Dear ImGui + OpenGL, pulling weather from Open-Meteo (no API key). Current conditions, a scrollable 24-hour view and a seven-day outlook, all with pixel-art weather icons.
Alerts that know when to be quiet. It watches for severe weather, temperature swings, rain, snow, hail, high wind and freezing precipitation. The part I actually cared about is delivery: you can have alerts pop as they happen, hold them during quiet hours, or batch them into a single daily digest so your night isn't a string of buzzes. New alerts arrive as floating toasts in the corner, and a notification center keeps the history to acknowledge and review.
Tonight. There's a panel for the night sky — the current moon phase (custom-drawn from the date, then swapped for hand-made phase sprites) with illumination, a rough aurora chance computed from your latitude and NOAA's free planetary K-index feed, and any meteor showers that are active, flagged when one's near its peak.
It's MIT-licensed and on GitHub. The Windows build is portable — unzip and run. macOS/Linux and code signing are down the road.
The whole point of filex is moving big files, which means a transfer can be running for a while — long enough that your Wi-Fi blips, your buddy's laptop sleeps, or the network hiccups for a second. In v1.0 any of those killed the transfer outright and you started over from zero. v1.1 fixes that.
Now: a dropped link reconnects and resumes. When the connection drops mid-transfer, filex doesn't fail — it shows "reconnecting…", re-establishes the peer-to-peer link on the same code (retrying for up to a minute), and recovers the file in flight. Unencrypted files resume from exactly where they stopped; password-locked files restart from the beginning (the streaming cipher can't pick up mid-stream — a fair trade for the extra at-rest encryption). This works for both one-shot sends and shared rooms — and in a room, the room itself and your send queue survive the drop, so you don't lose the session.
How it works. The tricky part of reconnecting a live WebRTC connection is that a torn-down connection's callbacks can fire after you've started a new one and quietly corrupt it. So every connection attempt gets a generation number, and a stale callback simply no-ops. The sender's role (who re-offers the channel) is fixed up front and preserved across reconnects, so the two sides always re-pair cleanly no matter who comes back first. The resume offset rides along in the existing handshake: the receiver keeps its partial file, reports how many bytes it already has, and the sender seeks there and continues. One background thread watches for stalls and drives the reconnects.
Also fixed: minimizing the window during a transfer used to peg a CPU core (and could crash on some GPUs) because it kept drawing to a zero-size window. The transfer never depended on the window — it runs on background threads — so v1.1 just stops rendering while minimized.
All of it is covered by a fault-injection test that yanks the connection mid-transfer and confirms the bytes still arrive, hash-for-hash, on both the one-shot and shared-room paths.
A round of polish landed in the same build. The title bar is now tinted to the app's palette so the window reads as one piece instead of a bright strip bolted on top (loaded through DWM at runtime, so it degrades gracefully on older Windows). When a transfer finishes while filex is in the background, the taskbar flashes so you actually notice. Shared-room transfers grew a live speed + ETA readout to match the one-shot view. And when a direct connection can't be made, the error now tells you what to do about it — add a TURN server under the network settings — instead of just giving up.
Grab the v1.1 build and drop a big file on a flaky connection — it'll get there.
A look back at where the engine has been. The clips below are in the order they were captured — earliest experiments at the top, latest at the bottom. Each one was a milestone at the time: the first thing that proved a system was actually working.
## // 1. glyph shapes — first stroke recognition //
The first time the $1 Recognizer could tell one drawn shape from another. No spells wired up yet, no mana, no projectiles — just a stroke buffer, normalization, and a debug panel printing the best match and a confidence score. Drawing a triangle returned "triangle." Drawing a circle returned "circle." It worked. The whole spellcasting pillar collapses out of this one routine, so seeing it land was the green light to start building Arx-style magic for real.
The recognizer plugged into a real cast pipeline. Hold RMB, draw the glyph, release — and if the shape matches a spell in your spellbook AND you have the mana, the spell fires. Magic missile, frost, fireball. Surfaces start to matter here too: frost on water turns the tile to ice for a few seconds. This was the moment the engine stopped being "a renderer with a glyph demo bolted on" and started being a game.
## // 3. bullet time //
A timescale slider wired into the fixed-timestep loop. Press the bind, the sim continues to tick at 60 Hz internally but dt is multiplied by 0.25; the renderer keeps interpolating so everything stays smooth. Projectiles, swing curves, status-effect timers, AI cooldowns — all of them inherit the slowdown for free because they all consume the same dt. The clip is the first proof that the entire simulation could be slowed and resumed without anything desyncing.
## // 4. the in-engine editor //
Phase 10b. The tile-grid world model retired; sectors took over. With sectors came the editor — a 2D plan view on top, a 3D preview underneath, both reading from the same Level struct that the game runs on. Walls split. Portals link sectors. Floors slope. Walking from the editor into play mode is a single key press. Everything you'll see authored in future posts is built in this thing.
## // 5. bhop //
Source-style bunny-hopping. Air-strafing accumulates speed as long as you release ground contact within a tight window and steer the look vector correctly while airborne. Tuning fell out of: the jump impulse, the air- acceleration cap, the friction curve, and a slop window on the ground re-detection. The clip is what "movement feels right" finally looked like.
## // next //
The current focus is doors, locks, and pressure plates — gating systems so levels can have real progression. After that: a vertical slice with a boss designed around the mode-swap. More clips when there's something to show.
The first public drop. Self-hosted Discord alternative for small friend groups — native client, native server, no Electron, no cloud. Years of internal 0.x churn collapsed into a 1.0 that's actually stable.
Highlights since the last internal build:
- Spatial audio. Drag voice participants on a 2D pad in the voice panel; horizontal axis is stereo pan, distance from listener attenuates volume. Local-only mixer — your layout, no protocol changes. - Voice effects + tuner. A small DSP chain (pitch shift, reverb, robot, telephone, distortion, bitcrush) with presets and a "Preview" tuner that loops your mic back to your speakers so you can dial in your voice before joining a call. - Full DPI / UI scaling. Real font-atlas rebuild at the chosen size — text stays crisp, padding scales, the whole UI grows proportionally at 100% / 125% / 150% / 175% / 200%. - Three Windows artifacts. Installer (Inno Setup, signed), portable client zip, and server zip. macOS and Linux 1.0.0 builds drop later from the respective hardware.