Photogrammetry scan turned into a 3D print Photogrammetry scan turned into a 3D print

Phone scan to 3D print: photogrammetry, a watertight mesh, and Bambu

TL;DR Phone scanners (Polycam, KIRI Engine, RealityScan) export raw geometry that’s sparse, has holes, and is non-manifold—not printable. First critical step: normalize scale. Scans export in meters and import at the wrong size. Fix this before anything else or Blender’s voxel remesh produces nothing. Blender’s voxel remesh rebuilds the mesh into a guaranteed watertight, manifold shell. Then decimate down to a slicer-friendly polygon budget. Export as both STL (geometry) and 3MF (units + compression). Slice in Bambu Studio and print. Watch for: voxel size mismatch, color loss after remesh, holes bigger than the voxel size, and X1C build plate limits (256×256mm). The Photogrammetry Gap There’s a seductive lie in 3D printing: buy a phone, scan something, print it. In reality, there’s a canyon between a photogrammetry scan and a printable model. ...

July 7, 2026 · 6 min · zolty
Vintage cassette deck repair bench Vintage cassette deck repair bench

Recapping a dead cassette deck: a vintage-audio repair triage

TL;DR “Dead” can mean anything from a sticky play button to catastrophic power supply failure. Map the symptoms first before you commit to a $40 parts order. Electrolytic capacitors dry out over 30–40 years. The tell is ESR (equivalent series resistance), which you can’t measure with a multimeter—you need a dedicated ESR meter. Mechanical failures (belts, pinch rollers, switches) cause 50% of what looks like electronics trouble. Try contact cleaner and spin the reels manually before you touch a soldering iron. Replace the power supply filter caps first. If hum persists after disconnecting the mains input, you’ve got a trace issue, not a capacitor issue. Full recap economics: ~$15–40 in parts + 2–6 hours of work. Only worth your time if the restored unit will fetch ~60% of that total cost on resale. What “Dead” Really Means A cassette deck doesn’t come with an error code. It just stops. And the failure modes are a taxonomy you need to parse before you spend an evening at the bench. ...

July 3, 2026 · 8 min · zolty
The Hugo, S3, CloudFront, and AI drafting pipeline behind this blog The Hugo, S3, CloudFront, and AI drafting pipeline behind this blog

How this blog is built: Hugo, S3, CloudFront, and an AI drafting pipeline

TL;DR This site is deliberately boring infrastructure for a reason: Hugo generates static HTML with the PaperMod theme. Terraform manages AWS (S3, CloudFront, Route53, ACM). GitHub Actions and self-hosted k3s runners deploy on every push to main. An AI pipeline (Bedrock + a Python script) drafts articles into Hugo page bundles and opens PRs for review. There’s no dynamic backend, no database, no server to maintain. The AWS bill is ~$30/month. This post is a tour of the machine that prints the other posts. ...

June 19, 2026 · 8 min · zolty
Parallel agents sweeping repos for improvements under a token budget Parallel agents sweeping repos for improvements under a token budget

Token-budgeted self-improvement: pointing parallel agents at my own repos

TL;DR I have $X in monthly Claude tokens I don’t always use. Instead of letting the unused credit evaporate, I built a parallel agent sweep that fans out autonomous scouts to scan for dependency upgrades, CVEs, CI waste, and quick wins across my repos. Each discovery agent returns a scored candidate list. The orchestrator triages and ranks them, then spins up isolated worktree agents to implement the safe ones — all under a hard token cap and with human gates between phases. The output is a pile of merge requests, not silent commits. Noise is real and review burden is the limiting factor, but when it lands right, an hour of agent work + human review beats a weekend of manual maintenance. ...

June 16, 2026 · 9 min · zolty
A crowded Ultima Online street where every NPC has something to say A crowded Ultima Online street where every NPC has something to say

The peasant has friends now: rumors, routines, and a 3,200-strong crowd

TL;DR Last time I wrote about giving my Ultima Online shard’s NPCs a voice, a memory, and a small autonomous life. That post ended with “the peasant talks back now.” In the eight days since, the project grew six new systems: NPCs keep daily routines anchored to real places, every town runs a rumor board that traveling NPCs physically carry between cities, townsfolk gossip about players (your katana, your karma, your reputation), the GM avatar got actual powers governed by a genie rule, villagers hand out delivery quests, and a population director keeps every city stocked with 200 ambient “denizens” who hail you in the street. That’s ~3,200 new NPCs and maybe a dozen new LLM call sites, still running entirely on a local gemma-class model — the trick is that the model never gained a single new permission. Every new capability is deterministic code; the LLM still only ever produces words and picks verbs off allowlists. Also: I found out my RAG pipeline had been silently dead for days, and the lesson there is worth the price of admission. ...

June 11, 2026 · 12 min · zolty
An Ultima Online town NPC with a speech bubble driven by a local language model An Ultima Online town NPC with a speech bubble driven by a local language model

When the peasant talks back: LLM NPCs in Ultima Online

TL;DR I run an Ultima Online shard on my homelab where the NPCs are driven by a local LLM instead of canned dialog trees. Each NPC rolls a persisted identity, remembers conversations with individual players across reboots, runs its own errands and cross-map journeys, and — the part I’m writing about today — strikes up ambient chatter with nearby NPCs on its own. The newest work extends all of that from townsfolk to language-speaking monsters: ogres, lizardmen, ratmen, gargoyles, daemons, and especially liches, who address each other like god-kings deigning to notice an insect. Inference is a local gemma-class model behind an in-cluster gateway, so it’s free and private, with the one tradeoff being cold-load latency. It’s single-shard hobby-scale and it absolutely shows the seams. I love it. ...

June 3, 2026 · 13 min · zolty
C# integration scripts wiring a local language model into an Ultima Online shard C# integration scripts wiring a local language model into an Ultima Online shard

How LLM-driven NPCs work in Ultima Online (ServUO)

TL;DR I open-sourced the integration that puts a local LLM behind the NPCs on my Ultima Online (ServUO) shard. It’s about 7,500 lines of C# that drop into a shard’s Scripts/Custom/ directory and compile at boot — no separate build, no service to deploy. This post is the code-level companion to the story version of the project: how config hot-reloads, how the model client marshals async results back onto the game thread, how the LLM is kept entirely out of the simulation loop, and how a deterministic allowlist makes a non-deterministic model safe to put in a stateful world. The whole thing is fail-open: if the model is slow, down, or wrong, the NPC silently degrades to a vanilla ServUO NPC. Code is on GitHub: ZoltyMat/uo-llm-npc. ...

June 1, 2026 · 11 min · zolty
AWS Lens running as a web server on k3s AWS Lens running as a web server on k3s

Running AWS Lens as a Self-Hosted Web App on k3s

TL;DR AWS Lens is an open-source Electron desktop app for managing AWS resources — EC2, S3, Lambda, IAM, Cost Explorer, and more. I wanted it accessible from my browser without running a desktop app. I adapted it to run as a containerized Express server on k3s, fixed a class of runtime crashes from the Electron-to-web adapter, hardened it against three security issues, and deployed it behind Traefik and Let’s Encrypt. The changes are open-source in BoraKostem/AWS-Lens#21. ...

March 30, 2026 · 7 min · zolty

Affiliate Disclosure: Some links on this site are affiliate links (Amazon Associates, DigitalOcean referral). As an Amazon Associate, I earn from qualifying purchases. This does not affect the price you pay or my editorial independence — I only recommend products and services I personally use and trust.