# Devan Metz — portfolio and blog > Projects by Devan Metz, including Goop Troops, OpenFloat Archery, a DIY electric bike, and hand-painted 3D prints. Website: https://devanmetz.com Generated: 2026-10-28T13:12:05.389Z ## In short I build browser games, hardware, software tools, and 3D-printed props. This site brings together my projects and posts about building them. I’m Devan, an electrical engineer and maker. I build software and physical projects, from browser games and bow sensors to an electric bike and printed instruments. I graduated from the Milwaukee School of Engineering (MSOE) in 2022 with a BS in Electrical Engineering and a minor in Mathematics. I made Goop Troops, built a belt-drive electric bike, and printed and painted props from Rust. I also built OpenFloat Archery, which pairs a sensor on the bow with a browser dashboard to review its movement. My interests include Blender, Python, Arduino and Zephyr, CNC, RC, e-bike projects, YouTube, and 3D printing and painting. I’m open to collaboration and commissions. A 3D-printing store may come later. Profiles: [GitHub]() · [X]() Contact: [Homepage contact form]() Blog feed: [RSS]() --- # OpenFloat Archery > A tiny bow-mounted sensor and a browser dashboard for seeing what happens before, during, and after a shot. Canonical page: [OpenFloat Archery]() Project date: Jun 2026 Updated: 2026-10-17 Category: Embedded hardware Status: Open source Tags: Bluetooth LE, Zephyr, JavaScript, Signal processing - **My work:** Firmware, browser app, and sensor integration - **Hardware:** XIAO nRF54L15 Sense + motion sensor - **Data:** Local shot history and optional sync - [Try the dashboard]() - [Source & build guide]() ## In short I built OpenFloat to record how a bow moves before, during, and after an arrow is released. A small sensor sends that movement to a browser so I can replay shots and compare them. It tracks bow movement, not where the arrow lands. ![OpenFloat dashboard displaying an archery target with colored hold, release, and follow-through traces.]() Shot review in OpenFloat, with a phase-colored trace and replay controls. ## Problem The target shows where an arrow landed. I wanted to see what the bow did on the way there. OpenFloat records motion before, during, and after release with a small bow-mounted sensor, then turns each shot into a trace I can replay and compare in a browser. ### Try it without hardware [Open the dashboard]() and select a recorded demo shot. The live demo can also generate synthetic motion. With the sensor connected, the same interface captures real shots and keeps them with a practice session. Float Score describes movement of the bow; it does not measure where the arrow hit. ## Constraints I need the trace to describe bow movement without implying that it measures arrow impact. The sensor also needs to preserve shots when the browser disconnects, and the browser connection depends on Web Bluetooth support and permission. ## Hardware and firmware The sensor uses a Seeed XIAO nRF54L15 Sense running firmware (the software on the sensor) built with Zephyr, an embedded operating system, and the nRF Connect SDK (NCS), Nordic’s development toolkit. Its LSM6DS3TR-C motion sensor is read through an interrupt-driven FIFO: a first-in, first-out buffer that holds readings in order and signals when they are ready. The firmware samples at 3,332 Hz (readings per second) and averages those readings into a roughly 1,110 Hz Bluetooth stream. The firmware estimates orientation with a Madgwick filter, which combines motion readings to estimate the bow’s angle. Live data frames carry acceleration, orientation, and a microphone-envelope measurement, a measure of sound level over time. Shot detection looks for a sudden motion above an impulse threshold, checked against recoil (the bow’s kick at release), then captures the motion around the release. The sensor keeps a lifetime shot count and the newest 100 shot records in nonvolatile memory, which keeps data when power is off. Buffered traces can be replayed when the browser reconnects. ## Shot review and training The browser uses the sensor’s orientation estimate to drive a bubble level and a 3D bow view. Shot review separates hold, release, and follow-through with different colors. - **Replay:** scrub through the motion leading into and following release. - **Comparison:** inspect several traces together to look for repeatable movement. - **Float Score:** summarize the trace with the project’s own 0–100 scoring system. - **Steady Aim:** practice a hold with a live trace, countdown, and cant readout showing sideways bow tilt. - **Sessions:** group shots into practice records and revisit them later. Float Score summarizes bow movement. Arrow impact still needs to be checked at the target. ## Browser connection and storage Web Bluetooth needs a supported browser, a secure context (such as an HTTPS page), and a user action to start device selection. A connect button gives that permission request an explicit place in the workflow. Browser and operating-system support should be checked against the [Web Bluetooth compatibility notes](). Receiving a shot and saving it are separate steps. OpenFloat acknowledges buffered shots (confirms receipt to the sensor) after the browser has saved them locally. Reconnection can then recover records that were captured while the browser was unavailable. ### Keeping and backing up shots The app uses IndexedDB, storage inside the browser, and can operate offline after loading as a progressive web app (a website that can work like an installed app). Backup and restore are available for local data. Keeping a session in one browser does not automatically back it up to another device; optional self-hosted sync is separate from the local workflow. ## Getting started 1. Open the [hosted dashboard]() and review a demo capture. 2. Use the repository’s Quick Start for the supported sensor, firmware release, mounting, and first calibration. 3. Connect from the dashboard in a compatible browser. 4. Confirm the live orientation responds before recording a session. 5. Save a backup when the session is worth keeping. The browser app uses native JavaScript modules, separate code files loaded directly by the browser. The repository also includes firmware build instructions, Bluetooth Low Energy (BLE) command documentation, host-side validation tools, and mechanical assets. ## Build files and reference The [OpenFloat repository]() has the hardware setup, firmware builds, BLE command reference, and mechanical files. OpenFloat is an experimental project; the feature-status list tracks what is implemented and what is still in progress. ## Implementation figures and current limits The implementation figures documented above are **3,332 Hz sensor sampling**, a **roughly 1,110 Hz BLE stream**, and storage for the **newest 100 shot records**. These describe the data pipeline and storage capacity; they do not establish end-to-end latency, battery runtime, or the number of field shots recorded. ## What’s next I want the next update to connect a real practice session to the trace and explain what I changed afterward. I’m keeping the field-testing story as a draft until I can supply that account. ## FAQ ### What does OpenFloat Archery measure? It records how the bow moves before, during, and after release with a small bow-mounted sensor, then replays each shot as a trace in a browser. It tracks bow movement, not where the arrow lands. ### What hardware does OpenFloat use? A Seeed XIAO nRF54L15 Sense with an LSM6DS3TR-C motion sensor, running Zephyr firmware built with the nRF Connect SDK. The firmware samples at 3,332 Hz and averages the readings into a roughly 1,110 Hz Bluetooth Low Energy stream. ### Can I try OpenFloat without the sensor? Yes. The hosted dashboard at openfloatarchery.com includes recorded demo shots, and the live demo can generate synthetic motion. ### Which browsers can connect to the sensor? The dashboard connects over Web Bluetooth, which needs a supported browser, a secure context such as an HTTPS page, and a user action to start device selection. Check MDN's Web Bluetooth compatibility notes for browser and operating-system support. ### Where are recorded shots stored? In the browser's IndexedDB storage, with backup and restore for local data and optional self-hosted sync. The sensor also keeps the newest 100 shot records in nonvolatile memory so they can be recovered when the browser reconnects. ## Build photos ![Devan at full draw with a compound bow in a grassy field, with a phone propped on a wooden post beside him, shown above the OpenFloat Trace Review screen where a green hold trace clusters near the center of the target.]() A real shot outdoors: video of the draw above, and the Pin Float trace building in Trace Review below. Still frame from the demo clip in the OpenFloat repository. ![OpenFloat Steady Aim demo showing a green movement trace, a countdown, and a bow tilt reading beside hold-duration controls.]() Steady Aim in demo mode, with synthetic motion rather than a recorded shot. ![OpenFloat Shot Trainer dashboard in demo mode, showing a 3D bow orientation view, a bow cant level reading of -1.8 degrees with a Zero Calibration button, and a shot sequence trace over an archery target.]() The main dashboard in demo mode, with bow orientation, a cant level for sideways tilt, calibration controls, and the live shot trace. ## Related reading - [nRF54L15 Support]() - [6×10 WS2812 Matrix for XIAO nRF54L15]() - [A Smart Ring for Zwift]() --- # Goop Troops > A multiplayer strategy game where territory grows like an organism and one cut can break an opponent’s supply line. Canonical page: [Goop Troops]() Project date: Feb 2026 Updated: 2026-10-13 Category: Game development Status: Browser game Tags: TypeScript, React, Multiplayer, Realtime simulation - **My work:** Game systems, web client, and multiplayer service - **Platform:** Browser · desktop and touch controls - **Play:** Up to 8 players · bots · ranked 1v1 - [Play Goop Troops]() - [Find it on itch.io]() ## In short I built Goop Troops as a browser strategy game where every piece of territory needs a connected route. Cutting a narrow supply line can bring down a much larger army. You can learn against computer-controlled opponents, join public matches with up to eight players, or play in private rooms. ![Colorful branching armies competing across the Goop Troops grid.]() A gameplay capture with several bot-controlled armies sharing the battlefield. ## The hook In [Goop Troops](), one small cut can undo a much larger army. Territory grows across a grid, but every part of it depends on a connected route. A narrow strip behind the front line can matter more than the size of the front itself. I built the game, its browser controls, and the multiplayer service around that rule. You can [play a bot match]() to learn it, then join a public game with up to eight players or set up a private room. The gameplay image above shows several armies pressing into the same board. ## The supply-line rule A connected empire has both reach and dependencies. A large front may look strong while relying on a small piece of territory behind it. Cutting that connection can collapse the position more effectively than attacking the largest group directly. That rule makes the empty space between armies useful information. A player has to read routes, chokepoints (narrow passages that are easy to block), and access to gold as well as the territory immediately in front of them. Expansion creates options, but it also creates more connections to defend. The tutorial introduces this relationship before the player has to manage the full pace of a multiplayer match. ## Ways to play The browser release supports several entry points: | Mode | What it is for | | --- | --- | | Guest play | Enter a game without first creating an account | | AI opponents | Learn the rules and practice against computer-controlled armies | | Public matches | Share a battlefield with up to eight players | | Private rooms and teams | Arrange a game with specific people | | Ranked 1v1 | Play head-to-head through matchmaking | Desktop and touch controls make the same game accessible from different devices. The public version runs in a browser without a separate download. ## Architecture I built the browser client (the part running on the player’s device) with React and TypeScript. It shares game-simulation code, which calculates how the battlefield changes, with an authoritative Node.js realtime service, which processes the match as it happens. “Authoritative” means the server has the final say on the match state, including the interaction between human commands and bot decisions. Sharing simulation code keeps the rules close to the interface that explains them. Keeping the final match state on the server gives participants a common outcome when competing actions arrive. ### Between matches Persistence, or saving data beyond the current session, supports the parts of the game that extend beyond a single match. Onboarding, room selection, matchmaking, and account-backed play are separate concerns from drawing and advancing the battlefield. ## Project structure and editions The main web project contains the client and shared simulation. A separate realtime service handles multiplayer and bots. The repository also holds database resources, production deployment tools, a Windows desktop prototype, and a native Roblox edition. The browser game is the public release. The Windows and Roblox editions are separate development projects. ## Play and development notes Start at [Goop Troops](), use the tutorial, and try a bot match to get a feel for supply lines. Private rooms are available when you want to play with friends. The [itch.io page]() provides another public home for the game. I built the simulation, web client, realtime service, interface, and release tools. The source code remains private. ## FAQ ### What is Goop Troops? A multiplayer strategy game that runs in a browser. Territory grows across a grid, and every part of it depends on a connected route, so cutting a narrow supply line can bring down a much larger army. ### How many people can play Goop Troops? Public matches hold up to eight players. There are also private rooms and teams, ranked 1v1 matchmaking, and computer-controlled opponents for learning and practice. ### Do I need an account or a download? No. Guest play enters a game without creating an account, and the public version runs in a browser without a separate download, with desktop and touch controls. ### What is Goop Troops built with? A React and TypeScript browser client that shares game-simulation code with an authoritative Node.js realtime service. The source code is private. ## Build photos ![Goop Troops tutorial showing three connected green tiles and the instruction that every tile needs an unbroken path to its starting point.]() The tutorial introduces the connected-territory rule before a multiplayer match. ## Build stories - [A strategy game about the space between]() ## Related reading - [Poker With Your Friends]() - [KICKR CORE 2 Hub]() - [Market Atlas]() --- # DIY Electric Bike > A bicycle conversion combining a custom belt drive, CAD-designed mounts, and an ESP32 dashboard. Canonical page: [DIY Electric Bike]() Project date: 2022 Updated: 2026-10-15 Category: Mechanical & electrical Status: Physical build Tags: Fusion 360, 3D printing, ESP32, C++ - **My work:** Mechanical integration, printed mounts, and dashboard - **Electronics:** ESP32 · VESC UART · TFT display - **Files:** Fusion 360 assemblies, STL parts, and C++ - [Explore the build files]() ## In short I converted a bicycle with a custom belt drive, printed mounts, and a dashboard that shows data from the motor controller. The build brings together mechanical design and electronics so I can see battery and riding data on the bike. The bicycle is assembled, while the dashboard software remains a prototype. ![A blue bicycle fitted with a custom motor mount, large rear pulley, belt drive, and electronics.]() The assembled bicycle conversion, showing the motor, belt drive, and frame-mounted electronics. ## What I built The bicycle in the photo is the assembled result of three connected pieces of work: fitting a belt-driven motor to the frame, making the mounts and pulley, and giving the electronics a readable display. I designed the mechanical assembly in Fusion 360, a computer-aided design (CAD) tool, and printed parts to fit the bike. An ESP32, a small programmable computer, runs the dashboard. It reads the VESC motor controller over UART, a serial data connection, and shows battery voltage, power, speed, and distance. The bike is assembled; the dashboard is still prototype firmware (the software running on the ESP32). The [public build files]() include the editable CAD, printable parts, code, and build photos. ## Mechanical assembly I used Fusion 360 to fit the motor, pulleys, and mounts around the bicycle frame and rear wheel. A belt connects the motor to a large rear pulley, with the electronics mounted on the frame. ### Printable parts The printable parts include: - The motor mount. - The rear pulley. - Two seat-tube clamp halves. The CAD files also include a 180-tooth pulley revision. The editable assembly is useful for checking clearances or adapting the mounts to another frame. ## Electronics and live readings An ESP32 communicates with the VESC motor controller over UART. The display sketch (the program running on the ESP32) uses three code libraries: - **VescUart** reads controller data. - **TFT\_eSPI** drives the TFT, a thin-film-transistor display. - **FastLED** controls addressable lighting, where each light can be set separately. ### Measurements and lighting The display presents battery voltage, estimated electrical power, speed, distance, and amp-hours (a measure of electric charge used). Power is calculated from input voltage and current. Speed and distance are calculated from controller RPM (revolutions per minute) and tachometer readings that track rotation using constants in the sketch. The same firmware cycles colors on an eleven-pixel WS2812 LED strip while polling telemetry (regularly reading controller data) and updating the dashboard. ## Dashboard implementation notes The sketch communicates with the controller at 115,200 baud, the serial connection’s signaling rate. It updates individual regions of the TFT as the readings change. ### Checking the conversions The telemetry conversions are specific to this build. Motor pole count (the number of magnetic poles), wheel diameter, and pulley ratio (the relative sizes of the drive pulleys) affect the meaning of the reported RPM and distance. The code includes hard-coded conversion factors (fixed numbers in the program), and some nearby comments describe different example values. Those constants need to be checked against the actual drivetrain before reusing the sketch. ## Build files | Folder | Contents | | --- | --- | | `CAD/Fusion360` | Editable components and the full bicycle assembly | | `CAD/STL` | Motor mount, rear pulley, and seat-tube clamp exports in STL, a 3D-printable mesh format | | `Code/VESCOM` | Dashboard sketch and display assets | | `Pictures` | Assembled bike, CAD assembly, pulley, and dashboard photographs | The CAD, printable parts, dashboard code, and build photos are in the [public repository](). ## Status and reuse The bicycle is assembled, and the dashboard remains prototype firmware. To adapt the build, start with the editable CAD and check the frame fit, belt alignment, mount strength, and telemetry constants for your components. ## FAQ ### How is the motor connected to the bike? A belt connects the motor to a large rear pulley. The motor mount, rear pulley, and two seat-tube clamp halves are 3D-printed parts designed in Fusion 360. ### What does the e-bike dashboard show? Battery voltage, estimated electrical power, speed, distance, and amp-hours. An ESP32 reads the VESC motor controller over UART at 115,200 baud and draws the readings on a TFT display. ### Are the build files available? Yes. The public repository includes the editable Fusion 360 assembly, STL exports of the printed parts, the dashboard code, and build photos. ### Can I adapt the build to another bike? Start with the editable CAD and check frame fit, belt alignment, and mount strength. The dashboard is prototype firmware, and its telemetry constants must be checked against your motor, wheel, and pulley ratio. ## Build photos ![Close-up of the blue bicycle frame, where a motor on a tan mount plate drives a black toothed belt, with a frame bag, yellow connectors, and wiring running down to a black electronics case.]() A closer look at the motor mount, belt drive, and frame-mounted wiring. ![Black printed pulley mounted beside the rear wheel of a blue bicycle, with a toothed belt running around it.]() The belt and large printed rear pulley on the assembled bicycle. ![CAD assembly of the bicycle conversion and drive components.]() The mechanical assembly in CAD, before everything has to fit on the real frame. ![ESP32-based display showing electric bicycle telemetry.]() The ESP32 dashboard prototype displays data from the motor controller. ## Build stories - [One bike, three kinds of making]() ## Related reading - [3D-Printed Rainbow Violin]() - [From the Workbench]() - [Catan Organizers]() --- # 3D-Printed Rainbow Violin > A rainbow Hovalin printed on a CR-10, assembled with guitar tuners, and put to the test—from plucked strings to the first days of bow practice. Canonical page: [3D-Printed Rainbow Violin]() Project date: Jan 2021 Updated: 2026-10-13 Category: Making & music Status: Printed & played Tags: 3D printing, Hovalin, Music, Video - **My work:** Printing, assembly, sound tests, and video - **Printer:** Creality CR-10 - **Print time:** About 20 hours - [Original Hovalin design]() ## In short I printed and assembled a rainbow Hovalin violin, using a one-piece body, printed neck and bridge, and guitar tuners. I tested it with acoustic guitar strings while waiting for violin strings and a bow, then filmed my early bow practice. The videos show how the printed instrument sounds, both plucked and played with a bow. ![Playing a rainbow-colored printed violin fitted with a gray neck, four strings, and guitar tuning machines.]() The assembled violin during its first plucked-string sound test. Frame from my original video. ## Overview I found out I could 3D print a violin, so I made one. This is my rainbow build of the **Hovalin**, a 3D-printable violin design by [Hova Labs](). I started with an improvised guitar-string sound test while waiting for violin strings and a bow (the tool drawn across strings to make them sound). The videos below show that first test and my early attempts at playing with a bow. ## Printing and assembly ### Printed parts I printed the entire body in one piece on a **Creality CR-10**, a 3D printer, with a print time of about **20 hours**. The neck and bridge (the piece that supports the strings above the body) were also printed. Guitar tuning machines, or tuners, adjust string tension to change pitch. The body prints upright, standing vertically as the printer builds it layer by layer. Rainbow bands run across those layers. ### Assembly and tuning After printing, I fitted the neck, bridge, tuners, and strings. The gray neck and bridge contrast with the colorful body. I tuned it E–A–D–G, the notes of its four strings. ## First sound test Before my violin strings and bow arrived, I fitted **acoustic guitar strings** and tried plucking it. The first recording starts with a look around the body and hardware, followed by the playing test. I change notes by pressing the strings against the fingerboard, the surface along the neck. **First sound test of the printed violin with guitar strings** - [Video (video/webm)]() - [Video (video/mp4)]() - [captions: English]() - [Preview image]() The original 1 minute 16 second sound-test video, with the build introduction and plucked-string playing. English captions are available. **Video transcript** The body was completely 3D printed in one piece on my Creality CR-10. The neck and bridge were also printed. The violin uses guitar tuners and is tuned E–A–D–G. I am using acoustic guitar strings until my violin strings and bow arrive. The remainder of the video shows me holding the violin across my lap and plucking the strings while changing notes on the fingerboard. ## Learning with a bow Once I had a bow, I started learning to play. This clip is from about **three days of practice**—an early attempt, but a chance to hear the printed violin played with a bow. **Early bowed performance on the printed rainbow violin** - [Video (video/webm)]() - [Video (video/mp4)]() - [captions: English]() - [Preview image]() A 25-second excerpt from my original short video: early bow practice on the assembled violin. In the clip, I hold the instrument at my shoulder, draw the bow across the strings, and change notes with my left hand. There is no spoken narration in this excerpt. ## Design and build references **Hova Labs created the Hovalin design.** I printed and assembled this one, learned to play it, and filmed the tests. Their [project page]() has more about the instrument and its printable files. Other small physical builds, including the arcade controller and soldering fan, remain in [From the Workbench](). ## FAQ ### Who designed the violin? Hova Labs created the Hovalin design. Devan printed and assembled this build, tested its sound, and filmed early playing. ### Which printer was used? The body was printed upright in one piece on a Creality CR-10 in about 20 hours. The neck and bridge were also printed. ### Can I hear the printed violin? The page includes a plucked-string sound test using acoustic guitar strings and a separate clip of early practice with a bow. ## Build photos ![A 3D printer working on the upright rainbow violin body, with its sound holes and raised tailpiece visible.]() The body being printed in one piece. Frame from the original short build video. ![The completed rainbow violin body held upright before fitting the neck, bridge, and strings.]() The unstrung body, showing the color bands, printed layers, sound holes, and neck opening. ![The rainbow printed violin lying on a white table, fitted with a gray neck and bridge and acoustic guitar strings, under the title text “3D Printed Violin with Guitar Strings.”]() My earlier title thumbnail for the build, showing the violin strung with acoustic guitar strings before the violin strings and bow arrived. ## Build stories - [The first sound from my printed violin]() ## Related reading - [From the Workbench]() - [DIY Electric Bike]() - [Catan Organizers]() --- # Solar Cellular Trail Camera > A wildlife-camera engineering prototype spanning low-power firmware, a private gallery, and a modular printable enclosure. Canonical page: [Solar Cellular Trail Camera]() Project date: Sep 2026 Updated: 2026-10-26 Category: Embedded hardware Status: Engineering prototype Tags: ESP32-S3, LTE-M, Python, FastAPI, CAD - **My work:** Firmware, gallery, simulator, carrier, and enclosure CAD - **Platform:** ESP32-S3 + SIM7080G LTE-M - **Validation:** Software and CAD checked; physical build pending ## In short A solar cellular wildlife-camera prototype saves original photos locally and sends previews to a private gallery. It includes firmware, a Rev E carrier board, and a Revision A enclosure. Software and CAD exports have been checked; a complete camera has not been assembled or field-tested. ![CAD render of the modular camera enclosure with separate front openings and mounting features.]() Revision A enclosure geometry. This is a CAD render, not a photograph of an assembled camera. ## Overview I designed this solar cellular wildlife-camera prototype around occasional motion events and limited energy. Motion should wake the camera, trigger a photograph, preserve the original locally, and send a smaller preview to a private gallery. The system spans embedded firmware (software running on the camera’s electronics), a server, a browser interface, power calculations, and a printable enclosure. The Rev E carrier and Revision A enclosure are engineering prototypes. The software and computer-aided design (CAD) exports have been checked, but a complete physical camera has not yet been assembled or field-tested. ## Capture and upload lifecycle The firmware targets the LilyGO T-SIM7080G-S3 PMU (power-management unit) board, combining an ESP32-S3 processor with a SIM7080G cellular modem, which connects to the mobile network. 1. A motion event wakes the device. 2. The camera captures a JPEG image and writes the original and preview to an SD memory card. 3. The preview enters an upload queue, a list of images waiting to be sent. 4. The device attempts an HTTPS upload (an encrypted web transfer) and checks the server’s receipt. 5. Failed transfers remain queued for retry with backoff (waiting between attempts). 6. Battery-aware scheduling and shutdown of unused power domains (groups of powered components) reduce activity between events. Signed firmware updates can be delivered over the cellular connection during scheduled check-ins, with rollback to the previous valid version if the new version fails confirmation. The local original is retained after upload. Cellular coverage should affect when the gallery receives an image, rather than whether the image survives at all. ## Gallery and backend The backend (server software) uses FastAPI, a web framework, and SQLite, a database. It stores: - Per-camera image histories. - Telemetry (device status readings). - Configuration versions (revisions of the camera settings). - Requests for full-resolution originals. Per-camera credentials separate devices. The Field Station browser gallery is designed for phones as well as larger screens. ### Testing coverage gaps A simulator exercises the event path, including periods without coverage and later reconnection. It makes queue and gallery behavior testable before taking hardware outside. Browser notifications currently depend on leaving the gallery open. Closed-browser mobile push is outside the implemented scope. ## Power estimates and cellular connection The power model calculates how event count, upload cost, solar input, and battery capacity affect runtime. Its default scenario estimates 0.95 Wh (watt-hours, a measure of energy) per day at 100 events. It estimates about eight days of reserve without sun, adjusted for reduced battery capacity in cold conditions. ### What still needs measurement Those figures are model outputs, not measured runtime. Weak cellular signal, frequent activity, shade, and charging being inhibited in cold conditions can change the balance substantially. Actual sleep, capture, and transmission energy still need to be measured on the assembled hardware. LTE-M service (a cellular connection intended for low-power devices), compatible camera operation, charge-temperature protection (preventing charging at unsuitable temperatures), and night illumination also need controlled hardware checks on the workbench. ## Rev E carrier The custom Rev E printed circuit board (PCB) carries the LilyGO board on a 95 × 95 mm, two-layer carrier. A passive infrared (PIR) motion sensor and three 940 nm infrared emitters sit on the front of the board. The carrier includes panel protection, reverse-pack blocking, and a hardware cold-charge guard that operates independently of firmware. CAD and fabrication exports have been validated, but the board has not been populated or physically fit-tested. PCBWay sponsors the project; that sponsorship does not establish hardware performance, order affordability, or readiness for deployment. ## Enclosure and service access The mechanical design separates ten printable parts. Editable STEP geometry (a format for exchanging CAD models) and STL exports (3D-printable mesh files) are accompanied by assembly views and geometry reports. The enclosure provides: - Separate camera and infrared openings (infrared is light outside the visible range). - A replaceable electronics carrier. - A battery hatch. - Independent tree and adjustable solar mounts. ### Fitting parts and checking weather sealing Purchased components appear as dimensioned envelopes (shapes representing their size) in the CAD; module-specific supports still need to be matched to the actual parts. The enclosure images show the Revision A CAD design. Weather sealing still needs to be tested on a physical enclosure. ## Validation and next milestone The local backend and simulator run, the embedded firmware compiles (builds successfully into device software), and the CAD exports have been validated. The next physical milestone is a complete bench path from motion to photograph to local storage to cellular upload to viewing. After that, I need to measure power use, check battery and charging behavior, and test the optics and enclosure outdoors. Field reliability and actual runtime are still open questions. The source repository is private. ## FAQ ### Has the camera been assembled and field-tested? No complete physical camera has been assembled or field-tested. Software and CAD exports have been checked, and physical validation is pending. ### What happens when cellular coverage is unavailable? The firmware saves the original and preview to an SD card. Failed preview uploads remain queued for retry with backoff, and the local original is retained after upload. ### Are the runtime figures measured? No. They are power-model outputs. Actual sleep, capture, and transmission energy still need measurement on assembled hardware. ### Does the gallery notify me when the browser is closed? Current browser notifications depend on leaving the gallery open. Closed-browser mobile push is outside the implemented scope. ## Build photos ![Exploded CAD assembly showing the enclosure, internal carrier, battery access, and mounts.]() The service layout separates the enclosure, electronics carrier, battery access, and mounting parts. ![CAD render of a solar mount with a green slotted upper plate, two central supports, and a dark slotted base.]() Revision A solar-mount geometry, shown as a CAD render rather than an assembled or tested mount. ![Top view of a 95 by 95 mm carrier board render, with panel and pack connectors on the left, power circuitry and LilyGO sockets in the center, three infrared emitters at top right, and a motion sensor at bottom right.]() 3D CAD render of the Rev E carrier, not a photograph of a built board. ## Related reading - [From the Workbench]() - [Catan Organizers]() - [Printed LED Sculptures]() --- # nRF54L15 Support > Portable C libraries and Zephyr drivers for the Nordic nRF54L15 with examples for the Seeed XIAO nRF54L15 Sense. Canonical page: [nRF54L15 Support]() Project date: Oct 2026 Updated: 2026-10-13 Category: Embedded libraries Status: Open source Tags: C, Zephyr, nRF Connect SDK, Bluetooth LE, Embedded - **My work:** Portable C libraries, Zephyr adapters, firmware examples, and telemetry tools - **Hardware:** Seeed XIAO nRF54L15 Sense - **License:** Apache-2.0 - [View source]() - [v0.1.0 release]() ## In short I built nRF54L15 Support as reusable code for reading sensors, estimating orientation, and sending data from a small Nordic chip. It provides components for my OpenFloat Archery project, along with firmware examples and tests for other applications. This first release is experimental, and its programming interfaces may change. ![Illustration of a schematic MCU board, motion axes, and Bluetooth symbol beside the nRF54L15 Support name; not a photo or screenshot.]() Original illustration of the library's MCU, IMU, and Bluetooth LE themes, not a hardware photo or screenshot. ## Overview I built nRF54L15 Support as portable C libraries for the Nordic nRF54L15 system-on-chip (SoC), which combines a processor and hardware features on one chip. I included examples for the **Seeed XIAO nRF54L15 Sense**. Zephyr hardware adapters connect the libraries to an embedded operating system. The portable code can run on a host computer or sit inside an nRF Connect SDK application, using Nordic’s development toolkit. ### Memory and hardware calls The library code allocates no heap memory: it does not request extra memory dynamically while running. Callers own the state and buffers (the stored working data), while the Bluetooth service is a singleton, meaning there is one shared instance. Zephyr and the SDK manage their own resources. Hardware calls run in thread context, within scheduled tasks rather than interrupt handlers. They must be serialized: callers need to keep those calls from running at the same time. ## Motion and hardware support ### Orientation and motion readings An inertial measurement unit (IMU) measures motion. My orientation code includes: - A **Madgwick IMU filter**, which combines motion readings to estimate orientation. - Quaternion normalization, which keeps the mathematical orientation representation valid. - Euler conversion, which expresses orientation as three angles. - Wrapped angles, which keep angle values within a repeating range. Motion support includes an upstream Zephyr IMU adapter and direct LSM6DS3TR-C I2C access (a wired chip-to-chip connection). Readings can use polling (checking for data), a FIFO (first-in, first-out buffer), INT1 notifications (signals on the sensor’s interrupt pin), and suspend/resume. Stationary gyro calibration adjusts the rotation sensor while it is still, rejecting motion and noise. Records are versioned and CRC-protected, using a cyclic redundancy check to detect corrupted data. Optional Settings/ZMS persistence saves them through Zephyr’s settings and storage systems. Scheduling and event helpers cover fractional sample deadlines (timing samples at intervals that are not whole clock ticks), missed slots, debounce (ignoring repeated signals from one event), impact candidates (possible impacts), and GPIO wake notifications (signals from input/output pins). ### Other hardware adapters - **SAADC:** analog-to-digital conversion, with raw and millivolt reads and calibration. - **Switched battery divider:** a circuit for measuring battery voltage. - **PWM:** pulse-width modulation, with control of duty (the on-time proportion) and pulse length. - **Audio:** PDM (pulse-density modulation) capture into mono PCM16 (16-bit sound samples), capture cleanup, and PCM signal levels. - **Temperature:** die-temperature reads from the microcontroller (MCU) and IMU chips. ## Telemetry and OpenFloat Telemetry means sending measurements to another device. My transport support includes: - Fixed-configuration **SPI**, a wired interface between chips. - **UART**, a serial connection, with receive buffering and recovery when data is lost. - **COBS/CRC packets:** consistently delimited messages with corruption checks. - An **OpenFloat Bluetooth Low Energy (BLE) service** for wireless communication. On the host computer, Python reference codecs (message encoders and decoders), serial telemetry validation, and a UART packet echo probe (which sends packets back) support testing and integration. My related [OpenFloat Archery]() project uses bow-mounted motion sensing and a browser dashboard. This library provides reusable orientation, hardware, and telemetry components for that work. ## Examples and verification The repository includes **15 firmware examples**, native CTest suites (tests run on a host computer), and Python tests. Native tests build the production C code against simulated hardware and operating-system interfaces; the Python packet suite compares 1,028 independent vectors with the built C encoder and decoder. The reference firmware environment is **nRF Connect SDK v3.3.0**, targeting `xiao_nrf54l15/nrf54l15/cpuapp`. The [README]() links the example index, API contracts (the rules applications must follow), integration instructions, and hardware testing setup. ### Hardware testing limits Hardware validation results and remaining fixture requirements are recorded in the [verification record](). Those checks document the tested behavior; they do not establish absolute measurement accuracy. ## Current release **v0.1.0 is an experimental first release**, published October 1, 2026. Public APIs (the programming interfaces applications call) may change before v1.0. The code is Apache-2.0 licensed; Nordic SDK dependencies retain their own licenses and are installed separately. ## FAQ ### Which hardware and SDK do the examples target? The examples include the Seeed XIAO nRF54L15 Sense. The reference environment is nRF Connect SDK v3.3.0 with the xiao_nrf54l15/nrf54l15/cpuapp target. ### Does the library allocate heap memory? The library code allocates no heap memory. Callers own state and buffers, while the Bluetooth service is a singleton. Zephyr and the SDK manage their own resources. ### Are the APIs stable? v0.1.0 is an experimental first release. Public APIs may change before v1.0. ### How does this relate to OpenFloat Archery? The library provides reusable orientation, hardware, and telemetry components for OpenFloat's bow-mounted motion sensing and browser dashboard. ## Related reading - [6×10 WS2812 Matrix for XIAO nRF54L15]() - [OpenFloat Archery]() - [Tab5 OS]() --- # 6×10 WS2812 Matrix for XIAO nRF54L15 > Zephyr examples and docs for driving Seeed's 6×10 RGB WS2812 matrix from a XIAO nRF54L15 with a GPIO bit-bang driver. Canonical page: [6×10 WS2812 Matrix for XIAO nRF54L15]() Project date: May 2026 Updated: 2026-10-15 Category: Embedded libraries Status: Open source Tags: C, Zephyr, nRF Connect SDK, WS2812, Embedded - **My work:** Zephyr bit-bang driver, demo gallery, hardware docs, and pixel-mapping notes - **Hardware:** Seeed 6×10 RGB matrix · XIAO nRF54L15 - **License:** MIT - [View source]() - [Hardware notes]() ## In short I documented how to drive Seeed's 6×10 RGB WS2812 matrix from a XIAO nRF54L15 in Zephyr. The repo includes a GPIO bit-bang driver, a demo gallery, pinout and pixel-mapping notes, and a wiring diagram, because the stock WS2812 SPI driver did not light this panel on that board. ![Close-up photo of a compact 6-by-10 RGB LED matrix on a dark PCB running a left-to-right rainbow gradient, with XIAO-style header pads along the top and bottom edges.]() The Seeed 6×10 RGB matrix running the rainbow demo from the Zephyr example on a XIAO nRF54L15. ## Overview I built community examples and documentation for driving Seeed’s 6×10 RGB (red, green, and blue) WS2812 LED matrix from a XIAO nRF54L15. The project fills a gap for Zephyr (an embedded operating system) and nRF Connect SDK (Nordic’s software development kit) users, with C code, wiring notes, and patterns for the 60 individually controlled lights. ## Getting the panel to light The stock `worldsemi,ws2812-spi` driver, which uses SPI (Serial Peripheral Interface) to generate the LED data signal, did not light this panel on this board. I built a GPIO (general-purpose input/output) bit-bang driver, which generates the signal by toggling a pin in software. The data connection uses **D0/A0**, the XIAO header pin connected to **P1.04** on the nRF54L15. My hardware notes and wiring diagram record that connection alongside the panel’s power and ground pins. ## Finding the pixel order I reverse-engineered the pixel mapping by lighting pixels and observing their positions. The 6×10 panel has **10 runs of 6 pixels** in plain raster order: each run follows the same direction. It is not serpentine (alternating direction on successive runs). Documenting that observed order gives the demos a consistent way to translate positions on the panel into LED indices (numbers identifying individual lights). ## Demo patterns I included a demo gallery with a scrolling green dot, solid fills, a wipe, a rainbow, a bouncing dot, a breathing brightness pattern, and a 0–10 counter. These patterns exercise individual pixels, color changes, movement, and number display. The cover photo shows the panel running the rainbow demo. ## Power and wiring I prefer **5 V** for the panel’s VCC (power input), with a common ground between the panel and XIAO and D0/A0 connected to DIN (data input). The panel also works at **3.3 V**, with dimmer output. The [hardware notes]() collect the pinout and wiring details. ## Related work My [nRF54L15 Support]() project provides reusable libraries and Zephyr drivers for the same microcontroller family. This matrix repository focuses on the Seeed panel’s driver, examples, and hardware documentation. My [Printed LED Sculptures]() are separate projects using printed structures and lighting; they are not builds of this matrix example. ## FAQ ### Why does this project use a bit-bang driver? The stock worldsemi,ws2812-spi driver did not light the Seeed 6×10 panel on this board. The project's GPIO bit-bang driver generates the signal by toggling a pin in software. ### Which pin carries the LED data? The data connection uses D0/A0 on the XIAO header, connected to P1.04 on the nRF54L15, and goes to the panel's DIN. ### Is the pixel order serpentine? No. The panel has 10 runs of 6 pixels in plain raster order, with each run following the same direction. ### What power wiring is documented? The documented preference is 5 V to panel VCC with common ground and D0/A0 to DIN. The panel also works at 3.3 V with dimmer output. ## Build photos ![Wiring diagram connecting a XIAO nRF54L15 5V, GND, and D0/A0 pins to a 6×10 RGB matrix VCC, GND, and DIN, noting that D0/A0 is P1.04.]() Wiring diagram from the repository: 5 V to VCC, common ground, and data on D0/A0 (P1.04). ## Related reading - [nRF54L15 Support]() - [OpenFloat Archery]() - [Tab5 OS]() --- # KICKR CORE 2 Hub > An indoor cycling cockpit with virtual shifting, a 3D riding world, live trainer telemetry, and game-style progression. Canonical page: [KICKR CORE 2 Hub]() Project date: Aug 2026 Updated: 2026-10-27 Category: Cycling software Status: Interactive prototype Tags: React, TypeScript, Three.js, Smart trainers - **My work:** Trainer integration, 3D interface, and ride analytics - **Stack:** React, TypeScript, Three.js, and Node.js - **Hardware target:** Wahoo KICKR CORE 2 via Direct Connect - [Try the simulator]() ## In short I built KICKR CORE 2 Hub as an indoor cycling interface with virtual gears, a moving 3D world, ride statistics, and game progression. Its browser simulator lets anyone explore those features without a trainer. Controlling a physical Wahoo trainer requires a local connection service, and the project remains an interactive prototype. ![A cyclist in a colorful 3D landscape surrounded by power, cadence, virtual gearing, and ride timeline panels.]() The browser simulator running an endurance ride. All telemetry shown here is synthetic. ## Overview I built KICKR CORE 2 Hub to turn indoor cycling into an interactive riding cockpit. It combines an interface for a smart trainer (an indoor cycling trainer that reports ride data and accepts control commands), virtual gears, a Three.js 3D world, and saved game progression in one browser user interface. The project spans both sides of the connection: a Node.js bridge (a local connection service) for communicating with a Wahoo trainer over the local network, and a React interface for riding, reviewing sessions, and experimenting with different setups. The [public demo]() includes a simulator that runs without trainer hardware. ## Riding interface The main view puts power, cadence (pedaling rate), speed, distance, and accumulated work (energy over the ride) around a moving 3D scene. Short power averages and a scrolling timeline make changes in effort visible without opening another panel. ### The riding world Pedaling animation follows cadence, while the landscape, visual effects, and speed streaks respond to the ride. The world includes rolling terrain, pine trees, mountain ridges, and streetlights. - **Camera views:** chase, first-person, drone, and free-orbit. - **Lighting:** dawn, daytime, sunset, and night change the atmosphere. The aim is to make the workout readable while giving the rider something more engaging than a stationary dashboard. ## Virtual shifting and trainer controls Virtual gearing changes the simulated gear without a physical shift. It is designed for a single-cog trainer setup, with one rear sprocket. Presets include: - A sequential 24-speed drivetrain, stepping through gears in order. - Shimano 2×12 and SRAM AXS 2×12 setups, each with two front gears and twelve rear gears. - A 1×12 gravel setup, with one front gear and twelve rear gears. Riders can shift with the on-screen controls, keyboard, or a gamepad. Mechanical shift sounds provide another cue that a gear changed. ### Trainer control modes The trainer-control interface supports four modes: - **ERG (target-power mode):** hold a target power. - **Simulation:** configure grade (slope), wind, rolling resistance (drag from tire contact), and aerodynamic conditions (air drag). - **Resistance:** set a resistance percentage directly. - **Level:** select a progressive resistance level from 0–9. ### Connecting to a trainer The bridge discovers compatible trainers on the local network or accepts a direct IP connection using the trainer’s network address. It performs service discovery (finding the trainer’s available services), subscribes to telemetry (live trainer readings), and waits for the trainer’s control acknowledgement (confirmation) before enabling control commands. ## Progression and the garage The game layer borrows the 1–99 skill structure of RuneScape. Strength, Endurance, Agility, and Climbing gain experience from different aspects of a ride, including power, time, cadence, and simulated gradient (slope). ### Equipment and saved progress Earned Drops, the game’s currency, fund equipment in the garage, including frames, wheels, jerseys, and headwear. Workshop upgrades, bounties (ride objectives), segments (sections of a route), and temporary bonuses give sessions additional objectives. These levels describe progress inside the game. Progress is saved in the browser so the rider can return to the same character and equipment. ## Ride history and analytics The Stats panel brings together a power-duration curve (power sustained over different lengths of time), time in power zones (effort ranges), and ride history. Session summaries include duration, distance, average and peak power, and accumulated energy. The power-duration view compares efforts from five seconds through twenty minutes when enough data is available. The energy counter cycles through daily, weekly, and monthly totals, with a separate control for joules or dietary Calories (kcal). The kcal value is the mechanical energy equivalent (1 kcal = 4,184 J), not an estimate of metabolic calories burned. Calendar periods use the browser’s local time, with weeks running Monday through Sunday. ### Storage and estimates The app keeps up to 50 archived rides in local browser storage and maintains lifetime totals. Energy recorded before the calendar counter was added stays in ride and lifetime stats only. Virtual speed, ride and lifetime calorie figures, and FTP-related calculations (based on functional threshold power, an estimate of sustained cycling power) are estimates. Storage is local to that browser, with no automatic cloud backup. ## Trying the simulator Open the demo and select **Sim** to generate a ride. Choose Recovery, Endurance, Intervals, Sprint, or Climb to change its pattern. The same data feeds the dashboard, 3D scene, skill progression, and stats panels. Use **Garage & Skills** to inspect progression and **Stats** to review the session. Keyboard shortcuts include **W/S** for shifting, **C** for camera views, and **L** for lighting. Select **Sim** again to stop. The screenshots on this page come from that simulator. They show synthetic telemetry, rather than recorded personal workout results. ## Architecture and current state ### How the pieces connect React and TypeScript handle the interface, Three.js renders the riding world, and shared modules define gearing and telemetry. A Node.js service handles trainer discovery and the Direct Connect protocol (the trainer’s network communication rules), then relays state to the browser over WebSocket, a connection that lets the service and browser exchange updates. ### What runs in the public demo The public Cloudflare Pages deployment hosts the frontend (the browser interface) and simulator. Controlling a physical trainer requires the local bridge on the trainer’s network. The current release is an interactive prototype, with the simulator available for anyone to explore. Related projects include my [COLMI smart-ring firmware for Zwift]() and [DIY electric bike](), which explore other sides of cycling hardware and telemetry. ## FAQ ### Can I try the hub without a trainer? Yes. Open the public demo and select Sim to generate synthetic ride telemetry for the dashboard, 3D scene, progression, and stats panels. Select Sim again to stop. ### What is needed to control a physical trainer? Physical Wahoo trainer control requires the local Node.js bridge on the trainer's network. The public deployment hosts the browser interface and simulator. ### Where are ride history and progress stored? Progress and up to 50 archived rides are stored in the browser, alongside lifetime totals. There is no automatic cloud backup. ### Does the calorie counter estimate calories burned? The kcal counter is the mechanical energy equivalent, not an estimate of metabolic calories burned. ## Build photos ![The Performance and Stat Review panel showing energy, ride duration, peak power, and a power-duration chart.]() The ride review presents energy and power-duration data from a short simulated session. ![The Rider Guild and Garage with Strength, Endurance, Agility, and Climbing skill cards.]() Game progression earned during the simulator session, with tabs for equipment, upgrades, quests, and segments. ## Build stories - [One simulated ride, the whole cycling cockpit]() ## Related reading - [Market Atlas]() - [Agent Message Board]() - [Goop Troops]() --- # Hand-Painted Rust Props > Game objects made physical—printed satchels, tools, a storage chest, and display replicas finished by hand. Canonical page: [Hand-Painted Rust Props]() Project date: 2021–2022 Updated: 2026-10-13 Category: Prop making Status: Printed & painted Tags: 3D printing, Hand painting, Prop finishing, Fan art - **My work:** 3D printing, assembly, and hand painting - **Collection:** Satchel, chest, tools, and display replicas - **Finish:** Color-separated surfaces and weathered details ## In short I printed, assembled, and hand-painted a collection of display props based on items from the game Rust. Paint separates straps, handles, metal details, and bone-colored surfaces on the printed pieces. The collection includes a satchel, tools, a storage chest, and nonfunctional display replicas. ![Hand-painted Rust-inspired satchel, pickaxe, storage chest, and glowing miniature furnace arranged together.]() A finished set of Rust-inspired prints, assembled and painted by hand. ## Overview I printed, assembled, and hand-painted this collection of display props inspired by the game Rust. The set includes a satchel, pickaxe, storage chest, Eoka (a gun-shaped game item), bone knife, and miniature rocket. Paint gives the printed pieces their different surfaces: brown straps and handles, dark metal details, and lighter bone-colored areas. These are nonfunctional display replicas. ## Pieces in the collection | Piece | Details | | --- | --- | | Satchel | Raised straps, loops, and cylindrical details; tan body with dark brown and black accents | | Storage chest | Printed chest with a hand-painted finish | | Pickaxe | Contrasting colors for the handle and head | | Eoka | Tan curved handle, dark barrel-shaped detail, and wrapped section | | Bone knife | Light blade with a brown wrapped handle | | Miniature rocket | Dark body, red tip, and open tail details | The separate [furnace lamps]() add warm lighting to the same family of props. ## Satchel: before and after The satchel started as a white print, with the folds, raised straps, loops, and top details already built into the shape. ### Separating the surfaces with paint I painted the body tan, the straps dark brown, and the smaller details black. Those color changes make the straps and fittings stand out from the body. The gallery shows the same prop before and after painting. ## Painting and surface details I used contrasting colors across the smaller pieces: - **Bone knife:** a light blade and a brown wrapped handle. - **Eoka:** a tan grip with a dark barrel and wrapped detail. - **Miniature rocket:** a red tip contrasting with the dark body and open tail. The print texture remains visible beneath the paint, especially around edges and recessed details (areas set below the surrounding surface). ## Game inspiration These are fan props based on items from Rust. My work is the printing, assembly, and hand painting; the game-item designs come from Rust. ## FAQ ### Which Rust items are in the collection? The set includes a satchel, pickaxe, storage chest, Eoka, bone knife, and miniature rocket. ### Are these functional replicas? No. These are nonfunctional display replicas inspired by items from Rust. ### What work did Devan do on the props? Devan printed, assembled, and hand-painted the pieces. The game-item designs come from Rust. ## Build photos ![An unpainted white satchel display prop with raised straps, loops, and cylindrical details.]() The satchel before paint, with the printed surface details visible. ![A completed satchel prop with a tan body, dark brown straps, and black details.]() Contrasting paint colors separate the satchel body, straps, and top details. ![A small Eoka display replica with a tan curved handle, dark barrel, and wrapped detail.]() The Eoka as a finished, nonfunctional display prop. ![A printed bone-knife display prop with a white blade and brown wrapped handle.]() A bone-knife prop with contrasting blade and handle finishes. ![A painted miniature rocket display prop with a dark body, red tip, and open tail details.]() A miniature rocket replica from the same printed prop collection. ## Related reading - [RuneScape Prints & Props]() - [Rust Furnace Lamps]() - [DIY Electric Bike]() --- # Rust Furnace Lamps > Hand-painted furnace replicas with glowing interiors, from small shelf pieces to a larger USB-powered build. Canonical page: [Rust Furnace Lamps]() Project date: 2021 Updated: 2026-10-15 Category: Props & lighting Status: Printed & painted Tags: 3D printing, Hand painting, LEDs, Assembly - **My work:** Printed assemblies, hand painting, and lighting - **Versions:** Miniature candle-lit and larger USB-powered builds - **Large build:** Furnace shell, bottom, and internal light holder ## In short I printed and hand-painted furnace lamps inspired by the game Rust, with lights inside to give the openings a warm glow. I made small shelf pieces with electric candle lights and a larger USB-powered version with a separate internal light support. ![Six hand-painted miniature furnaces with tan tops, gray stone bases, and glowing yellow interiors.]() A finished batch of illuminated Rust-inspired furnace replicas. ## Overview I printed the shells, painted them by hand, and added lights inside to make these furnace lamps inspired by the game Rust. The gray stone bases, tan chimneys, and darkened openings recreate the look of the in-game furnace. I built a batch of small lamps with electric candle lights and a larger version powered by USB. ## Small candle-lit lamps The smaller pieces use an electric candle-style light inside the printed shell. The gallery includes the white shells before painting and a finished miniature; the cover shows a batch of six with their lights on. Painting separates the gray lower stones from the tan upper surface. Dark marks around the opening and chimney give the form a used appearance, while the interior light remains visible through the front. ## Larger USB-powered version The larger assembly has three printed parts: - Main shell - Bottom closure - Interior light support ### Power and lighting The electronics consist of: - A USB cable. - A rocker switch, which toggles power on and off. - A boost converter, which raises the input voltage. - A light strip. The switch controls input power to the converter, which supplies the strip inside the light support. For a similar build, match the converter’s output voltage to the light strip and check the power supply’s current rating (how much electrical current it can supply). ## Assembly sequence The larger lamp comes together in four steps: 1. Print the shell, bottom, and light support. 2. Paint the shell and glue the light strip into its support. 3. Wire the switch, converter, and strip. 4. Fix the support inside the furnace and attach the bottom. The separate support makes the lighting easier to assemble before closing the shell. The large furnace is pictured beside a gallon jug for scale. ## Finish and photographs The printed shell defines the stones and chimney. Paint separates the surfaces and adds soot marks, while the light gives the opening a warm glow. These are fan props based on Rust’s furnace. My work is the printing, painting, assembly, and lighting. See my [other Rust props]() for the satchel, chest, and smaller replicas. ## FAQ ### Do the miniature lamps use real candles? The small lamps use electric candle-style lights inside printed shells. ### How is the larger furnace powered? The larger version uses a USB cable, rocker switch, boost converter, and light strip. The switch controls power to the converter, which supplies the strip. ### Which parts make up the larger printed assembly? The larger lamp has a main shell, bottom closure, and interior light support. The shell is painted and the light strip is glued into its support before final assembly. ## Build photos ![Several white printed furnace shells before painting and final assembly.]() Printed furnace shells before the stone, clay, and soot colors are added. ![A finished miniature furnace with a weathered tan chimney, gray base, and warm light inside.]() The painted surface and warm interior light together on a finished miniature. ![A larger printed furnace beside a gallon jug for scale.]() The larger furnace version, photographed beside a gallon jug for scale. ## Related reading - [Hand-Painted Rust Props]() - [RuneScape Prints & Props]() - [Dice Boxes & Life Counters]() --- # RuneScape Prints & Props > A printed Jad figure and a hand-painted dagger that bring angular game designs onto the workbench. Canonical page: [RuneScape Prints & Props]() Project date: 2021–2022 Updated: 2026-10-13 Category: Props & miniatures Status: Physical builds Tags: 3D printing, Miniatures, Hand painting, Fan art - **My work:** Physical printing and prop finishing - **Pieces:** Jad figure and painted dagger - **Style:** Faceted game shapes with visible print texture ## In short I printed a red Jad figure and made a hand-painted dagger inspired by the game RuneScape. The figure shows the angular shape and print layers in one color, while paint separates the dagger’s blade, guard, and handle. The dagger is a decorative display prop. ![A red 3D-printed Jad figure with angular legs, horns, and an open mouth on a wooden surface.]() A red Jad print, with its faceted shape and print layers visible. ## Overview I printed a red Jad figure and made a hand-painted dagger based on the game RuneScape. The figure keeps a single red color, while the dagger uses separate colors for the blade, guard, and grip. ## Jad figure Jad is the game character represented by the figure. The print has a faceted body (made up of flat, angular surfaces), spread legs, horns, and an open mouth. Its angular shape works well as a single-color print, with the red material and visible print layers giving it texture. ## Painted dagger I painted the dagger with a red blade, green tip, gray guard, and brown handle. The colors follow the edges of each part, so the blade and handle stand apart even though they share the same printed texture. It is a decorative display prop. ## Shape and paint I used two different finishing approaches: - **Jad:** most of its appearance comes from the shape itself. - **Dagger:** paint does more of the work to separate its surfaces. Both approaches also show up in my [Rust prop collection](). ## Game inspiration These are RuneScape fan pieces. My work is the printing and finishing; the character and item designs come from the game. ## FAQ ### Which RuneScape pieces are shown? The collection includes a red Jad figure and a hand-painted dagger. ### Is the dagger a usable tool? It is a decorative display prop. ### Did Devan create the game designs? The character and item designs come from RuneScape. Devan's work is the physical printing and finishing. ## Build photos ![Close view of a hand-painted dagger prop with a red blade, green tip, gray guard, and brown handle.]() The painted dagger's blade, guard, and handle use distinct colors. ![A painted dagger and red Jad figure beside a miniature furnace on a white photo backdrop.]() The RuneScape-inspired pieces on the photo bench alongside a Rust furnace replica. ## Related reading - [Hand-Painted Rust Props]() - [Rust Furnace Lamps]() - [DIY Electric Bike]() --- # OpenRP > A multiplayer city sandbox in the browser, with jobs, property, businesses, and server-owned physics. Canonical page: [OpenRP]() Project date: Sep 2026 Updated: 2026-10-26 Category: Game development Status: Public alpha Tags: Three.js, TypeScript, Cloudflare Workers, Durable Objects, WebSockets - **My work:** Game systems, networked simulation, and original assets - **Stack:** Three.js · TypeScript · Cloudflare Workers - **Release:** Playable 0.6 alpha - [Visit OpenRP]() - [View source]() ## In short I’m building OpenRP, a multiplayer city game that runs in a browser, where players can take jobs, own property, and shape city life. Its shared systems connect businesses, construction, and government without requiring a Garry’s Mod installation. It is a playable alpha, and I’m still developing and tuning its systems. ![OpenRP project artwork showing the low-poly city and its jobs, property, and physics systems.]() OpenRP’s project artwork, showing the browser-built city. ## Overview I’m building OpenRP as a multiplayer city sandbox—a place where players can choose their own activities—that runs in a browser. Players can take jobs, buy property, operate businesses, build with physics props (objects that can move and collide), and participate in elections and city laws. I took inspiration from the social sandbox of DarkRP, a roleplay game mode for Garry’s Mod. OpenRP has its own implementation and locally generated map geometry (the shapes that make up the map), characters, equipment, textures, and sound effects. A Garry’s Mod installation or extracted game assets are not required. ## The city and its systems The city connects several activities through shared resources and ownership: - **Jobs:** roles define salaries, equipment, and access to businesses. - **Property:** doors can be purchased, named, locked, and shared through keys. - **Businesses:** stock, prices, and purchases connect a shop to its owner. - **Construction:** players manipulate props using physics and tool controls. - **Government:** elections, laws, licenses, warrants, and arrests change city life. - **Social play:** nearby chat, roleplay actions, group channels, and proximity voice (voice chat limited by how close players are) support interaction. The Union District includes neighborhoods, multi-room apartments, and businesses. Shared lobbies remain public while individual units have their own ownership. ## Multiplayer architecture ### Rendering and server decisions I use Three.js, a JavaScript 3D graphics library for the browser, to render the world. A Cloudflare Worker (code running on Cloudflare) serves the client and both WebSocket paths. A Durable Object (a shared, stateful instance) owns the world, including movement checks, rigid-body physics (simulating how solid objects move and collide), combat, and economic transactions. WebSockets—a connection that stays open so the browser and server can send messages both ways—carry commands and state updates. ### Keeping movement responsive The simulation runs at 30 Hz (30 updates per second), with 15 Hz snapshots (shared copies of the game state sent 15 times per second). Client prediction estimates movement in the browser before the server responds; interpolation fills in movement between received states. These help movement look responsive between updates from the authoritative server, which has the final say on game state. Purchases and combat results still depend on server decisions. ### Voice connections Voice has a separate connection path with server-enforced proximity, explicit microphone controls, and independent muting. The hosting setup has to support long-lived connections for both gameplay and voice. ## First session and controls Open [OpenRP](), choose an account or Guest, then return to the streets. The field guide explains the controls inside the game. | Control | Use | | --- | --- | | WASD and mouse | Move and look | | E | Use the targeted object | | F4 | Jobs, shop, laws, and voting | | Q | Building tools and props | | C | Context actions | | F1 | Field guide | | V | Push-to-talk after enabling the microphone | ### Guests and accounts Guest identities rely on a stored browser credential, a saved identifier that lets the server recognize the guest. An account can claim the guest character’s belongings. Accounts belong to the server being played on; independently hosted servers do not share an account database. ## Running a local copy Use Node.js 22.12 or newer. From a checkout: ```sh npm ci npm run dev ``` Open [http://localhost:8787](), an address on your own computer. Vite builds the client, and Wrangler runs the Worker and a local Durable Object. ### Hosting on the internet To self-host on your own Cloudflare account, configure your domains and origins in `wrangler.jsonc`, authenticate Wrangler, set the private secrets, and run `npm run deploy`. Hosting is subject to Cloudflare usage limits and billing. See the [hosting guide]() for deployment, backups, and runtime limits. ## Status and reference OpenRP is a playable alpha. I’m still developing its systems and tuning how they interact. The [public repository]() contains the source, control reference, configuration, and self-hosting documentation (instructions for running your own server). The cover is project artwork showing the city. ## FAQ ### What is OpenRP? A multiplayer city sandbox that runs in a browser. Players can take jobs, buy property, run businesses, build with physics props, and take part in elections and city laws. It is a playable alpha. ### Do I need Garry's Mod to play OpenRP? No. OpenRP takes inspiration from DarkRP but has its own implementation and locally generated map geometry, characters, equipment, textures, and sound effects. A Garry's Mod installation or extracted game assets are not required. ### What is OpenRP built with? Three.js renders the world in the browser. A Cloudflare Worker serves the client and WebSocket paths, and a Durable Object owns the world state, physics, combat, and economy, simulating at 30 Hz with 15 Hz snapshots. ### Can I host my own OpenRP server? Yes. The public repository documents self-hosting on your own Cloudflare account; local development uses Node.js 22.12 or newer. Accounts belong to the server being played on. ## Related reading - [Poker With Your Friends]() - [KICKR CORE 2 Hub]() - [Market Atlas]() --- # OpenMic > A native Windows and Linux microphone cleaner and soundboard that keeps the audio processing on your computer. Canonical page: [OpenMic]() Project date: Aug 2026 Updated: 2026-10-13 Category: Desktop software Status: Open source Tags: Rust, Audio DSP, RNNoise, egui, Windows - **My work:** Rust application, audio routing, mixing, and UI - **Platform:** Windows 10 and 11; x86_64 Linux - **Processing:** Local 48 kHz audio processing - [Source & downloads]() ## In short I built OpenMic, a Windows and Linux app that cleans microphone audio and mixes in local sound clips before sending the result to another application. The audio processing stays on the computer and does not need a remote service. Separate microphone mute and soundboard controls let clips keep playing when I mute my voice. ![OpenMic’s native interface with microphone routing, noise reduction, gain, noise gate, and live audio meters.]() The microphone workspace, with routing, processing controls, and live input and output meters. ## Overview I built OpenMic as a native Windows and Linux app (software that runs directly on each operating system) for microphone cleaning and a soundboard, which plays selected audio clips. It processes live microphone audio, mixes optional local clips, and sends the combined result to a selected output device. A virtual audio cable, a software connection that passes audio between applications, lets another application use that processed result as its microphone input. Audio processing—the digital signal processing (DSP) that changes or cleans the sound—stays on the computer; the application does not need a hosted inference service (a remote service running the noise-cleaning model). ## Audio pipeline ### Formats and noise suppression Devices open in their native formats. OpenMic resamples audio (changes its sample rate) into a 48 kHz processing core. That rate means 48,000 audio samples per second. DeepFilterNet 3 handles noise suppression by default, with RNNoise, an open-source noise-suppression library from Xiph, as a lighter alternative. OpenMic converts the audio as needed for the chosen output. ### Processing controls The controls expose different stages of the signal path (the route audio takes through processing): | Control | Purpose | | --- | --- | | Input gain (level adjustment) | Adjust the microphone level before processing | | Noise reduction | Mix between the original and cleaned signal | | Noise gate (a cutoff for quiet audio) | Suppress audio below the selected threshold | | Output gain (level adjustment) | Set the level leaving the processor | | Bypass (skip processing) | Compare with processing disabled | | Microphone mute | Silence voice while leaving the soundboard available | Input and output meters, together with a voice-probability readout (the processor’s estimate that the sound is speech), make it possible to see what the processor is receiving and producing. ## Routing into a voice application On Windows, I route audio through VB-Audio Virtual Cable: 1. Select the physical microphone in OpenMic. 2. Choose **CABLE Input** as the processed output when using VB-Audio Virtual Cable. 3. Select **CABLE Output** as the microphone in the receiving application. 4. Check the meters and adjust gain before adding more processing. 5. Use headphones when enabling the separate headphone monitor (listening to the output through headphones). The Input and Output names refer to opposite ends of the cable. A common routing mistake is choosing the same end in both applications. When trying OpenMic, disable any second noise suppressor, such as Discord’s Krisp noise-suppression feature, to hear what OpenMic is doing on its own. ## Soundboard behavior The Soundboard tab accepts local WAV, FLAC, OGG, MP3, and AIFF clips through Symphonia, an audio-decoding library that reads the clip files. Symphonia is written in Rust, the programming language OpenMic uses. Clips have their own volume and mix into the processed output. ### Device changes and saved settings Device changes hand the stream to a new engine while preserving the clip’s playhead (its current playback position). Microphone mute and soundboard playback are independent, so muting a conversation does not unexpectedly stop a playing clip. Settings and the soundboard list persist between runs. Optional Windows startup and automatic processing make the app usable as an everyday routing tool. ## Linux I also ship a native x86\_64 Linux build for microphone cleaning and the soundboard. It creates **OpenMic Virtual Cable** for the processed audio and **OpenMic Microphone** for Discord, OBS, or browsers to select as their input, then removes both on exit. Computer-audio recording captures the selected output’s monitor source (its audio feed), and **Start on login** adds an autostart entry. The virtual microphone requires PulseAudio, or PipeWire (Linux’s audio and media service) with its PulseAudio-compatible `pipewire-pulse`, plus `pactl` (the audio-server control command). Install `pulseaudio-utils` on Debian/Ubuntu or `pipewire-pulse` on PipeWire-only systems. Without these, OpenMic runs without a virtual microphone. Download `openmic--linux-x86_64.tar.gz` from [Releases](), extract it, and run `./openmic`. To build from source, install Rust, `clang`, `pkg-config`, `libasound2-dev`, `libxdo-dev`, `libx11-dev`, `libxkbcommon-dev`, `libgl1-mesa-dev`, and `libssl-dev`, then run `cargo build --release`. The binary is `target/release/openmic`. Linux has no notification-area tray: closing the window quits. Updates require downloading a new release, and dictation displays a transcript to copy rather than typing into another app. Global hotkeys work on X11 (a Linux display system), but not Wayland (the newer display system). The tray, in-app updater, and dictation typing remain Windows-only. ## Building and testing ### Build requirements I wrote the application in Rust with an egui interface (egui is a Rust user-interface library). RNNoise is built from the vendored Xiph source, a copy of that source included in the repository. The Windows build requires Rust, MSVC build tools, and a compatible Clang C compiler for RNNoise. MSVC and Clang are compilers that turn source code into runnable software. ### Running and testing Cargo is Rust’s build and package tool. From the repository, `cargo run --release` builds and starts the app. The test suite is run with `cargo test`. Tests cover gain, gating, bypass, mute, soundboard isolation, decoding, resampling, stream continuity, settings persistence, and startup handling. ## Source and attribution The [OpenMic repository]() contains setup instructions, source, and the native interface capture shown above. My work covers the application and its routing, mixing, controls, and integration. RNNoise retains the upstream project’s source and license notices. ## FAQ ### What does OpenMic do? It cleans live microphone audio, mixes optional local soundboard clips, and sends the result to a selected output device. A virtual audio cable then lets apps such as Discord or OBS use that processed audio as their microphone. ### Does OpenMic send audio to the cloud? No. Audio processing stays on the computer; the app does not need a hosted inference service. ### Which platforms does OpenMic support? Windows 10 and 11, and x86_64 Linux. The Linux virtual microphone needs PulseAudio, or PipeWire with pipewire-pulse, plus pactl. ### What noise suppression does OpenMic use? DeepFilterNet 3 by default, with RNNoise as a lighter alternative, inside a 48 kHz processing core. ### How do I use OpenMic with Discord? On Windows, choose CABLE Input from VB-Audio Virtual Cable as OpenMic's output and select CABLE Output as the microphone in Discord. On Linux, select OpenMic Microphone. Turn off Discord's Krisp noise suppression to hear OpenMic on its own. ## Related reading - [FeatherClick]() - [OpenSnip]() - [KICKR CORE 2 Hub]() --- # From the Workbench > Printed controls, a soldering fan, and other small workshop builds where CAD becomes something physical. Canonical page: [From the Workbench]() Project date: 2020–2021 Updated: 2026-10-16 Category: Making & fabrication Status: Physical builds Tags: 3D printing, CAD, Electronics, Video - **My work:** Printing, assembly, electronics integration, and videos - **Builds:** Arcade controller · workshop fan · small printed parts - **Parts:** Printed housings, controls, mounts, and grilles ## In short I built an arcade-style controller, a soldering fan, and other small workshop projects using printed parts. Custom housings and mounts bring buttons, motors, and other components together into physical builds. ![A custom black 3D-printed arcade-style controller with large gray buttons.]() An arcade-style controller build, with a printed enclosure and button caps. ## Small workshop builds These are some of my smaller workshop builds: an arcade-style controller, a soldering fan, and printed parts for other projects. Most combine a custom printed part with buttons, a motor, or another component that needs a housing or mount. CAD (computer-aided design) means using software to work out a part’s shape before printing it. ## Arcade-style controller I built the controller with a black printed enclosure, large buttons, and gray printed caps. The enclosure holds the controls together in an arcade-style layout. ## Soldering fan The soldering fan has a printed casing, front grille, motor mount, and wide feet. The mount holds the fan inside the body, while the feet support it at an angle on the workbench. ## Shop tools and fixtures I printed and assembled a small disc sander with an orange housing for my workshop. I also printed pegboard hooks and spool holders to hold electrical tape and solder. For my desk, I printed and assembled a hinged monitor bracket and a speaker front plate that holds two drivers. ## Printed violin experiment I also printed and assembled a rainbow violin using Hova Labs’ Hovalin design. Its [project page]() has the CR-10 (3D printer) build details, my first sound test with guitar strings, and a clip of early bow practice. ## Other printed parts Other experiments include: - A printed mallet. - Bike-light mounts. - Organizers. - Parts for RC (radio-controlled) cars and robot builds. The [Catan organizers](), [dice boxes and counters](), and [LED sculptures]() each have a page with more photos and build details. ## FAQ ### What workshop builds are included? The page includes an arcade-style controller, soldering fan, small disc sander, pegboard hooks and spool holders, a hinged monitor bracket, and a speaker front plate. ### How was the arcade-style controller constructed? It uses a black printed enclosure, large buttons, and gray printed caps arranged in an arcade-style layout. ### Which parts of the soldering fan are printed? The fan has a printed casing, front grille, motor mount, and wide feet. The mount holds the fan inside the body, and the feet support it at an angle. ## Build photos ![A workshop fan with a white printed housing, front grille, and wide feet on a cutting mat.]() The soldering-fan build combines a printed housing, motor mount, grille, and feet. ![A desktop disc sander with an orange printed housing, a sanding disc on top, and wires leading out.]() A small disc sander I assembled with a printed housing. ![Blue printed hooks and green printed spool holders holding electrical tape and solder on a brown pegboard, with pliers below.]() Printed hooks and spool holders keep supplies on my pegboard. ![A blue printed hinged bracket clamped to the back edge of a monitor.]() A printed monitor bracket I assembled for my desk. ![A speaker cabinet with a green printed front plate holding two drivers.]() A printed front plate I assembled with two speaker drivers. ## Related reading - [Printed LED Sculptures]() - [3D-Printed Rainbow Violin]() - [Catan Organizers]() --- # Catan Organizers > Printed card trays and compact piece cases that keep resource decks, roads, and buildings organized on the table. Canonical page: [Catan Organizers]() Project date: 2020–2021 Updated: 2026-10-13 Category: Tabletop accessories Status: Physical builds Tags: 3D printing, CAD, Product design, Tabletop games - **My work:** Organizer design, printing, and fit revisions - **Objects:** Card trays and covered player-piece cases - **Construction:** Printed trays, fitted channels, and separate covers ## In short I designed and printed card trays and covered player-piece cases for the board game Catan. The trays keep shared decks visible and accessible during play, while the cases store each player’s roads, settlements, and cities afterward. I revised the holders and covers to fit together, so matching versions and piece dimensions matter when printing a set. ![Catan resource and development cards arranged in connected black and white printed card trays.]() Printed trays holding the game's resource and development decks. ## Overview I designed and printed these organizers for the board game Catan’s cards and player pieces. The card trays keep the shared decks together during a game, and the covered cases store each player’s roads, settlements, and cities. ## Card trays The trays give each resource and development deck (the game’s shared card decks) its own slot. The cards stay visible and accessible during play, with black and white printed sections arranged together on the table. ## Player-piece case The compact case separates the pieces into: - Parallel channels for roads. - Spaces for settlements and cities, the game’s buildings. Opening it gives a quick view of the whole set. A separate cover closes the case for storage. ### Matching holders and covers I made several holder and cover revisions, including V2 and V3 (version 2 and version 3). Each cover needs to fit its matching holder. ## Design and fit I used the game pieces to check the fit of the printed holders. The computer-aided design (CAD) close-up shows a road sitting in its channel, and the assembled case shows the roads and buildings loaded together. For a different edition of Catan, check the piece dimensions before printing a full set of cases. ## At the table The trays hold the shared decks during play; the cases collect each player’s pieces afterward. I also made [dice boxes and rotating life counters]() for other tabletop games. My work here is the organizer design and printing. The game pieces and artwork are from Catan. ## FAQ ### What do the organizers hold? The card trays hold resource and development decks. Covered player-piece cases have channels for roads and spaces for settlements and cities. ### Do all holder and cover versions fit together? Each cover needs its matching holder. The designs went through several revisions, including V2 and V3. ### Will they fit a different edition of Catan? Piece dimensions should be checked before printing a full set of cases for a different edition. The holders were checked against the game pieces used for this build. ## Build photos ![A compact white printed case with fitted spaces for gray roads, settlements, and cities.]() A player-piece case with separate positions for roads and buildings. ![CAD detail of the piece holder showing a red road piece seated in its channel.]() A design view of the road storage channel during development. ## Related reading - [Dice Boxes & Life Counters]() - [Rigid Heddle Loom Accessories]() - [Ring and Jewelry Organizer]() --- # Dice Boxes & Life Counters > Printed dice storage with lined rolling trays, plus numbered counters built from separate rotating rings. Canonical page: [Dice Boxes & Life Counters]() Project date: 2022 Updated: 2026-10-15 Category: Tabletop accessories Status: Physical builds Tags: 3D printing, Assembly, Product design, Tabletop games - **My work:** Printing, fitting, assembly, and finishing - **Objects:** Dice storage/rolling box and rotating life counters - **Mechanism:** Separate numbered rings with pointers and end pieces ## In short I printed and assembled dice boxes that open into storage and a lined rolling tray, along with rotating life counters for tabletop games. Separate numbered rings let me change one digit at a time to track a value during play. The builds need matching parts and enough room for the lids to close and the rings to turn. ![An open brown dice box with a set of colorful dice in one half and a green die in the lined rolling tray.]() The dice box opened into storage and a lined rolling tray. ## Dice storage and game counters I printed and assembled these dice boxes and life counters for tabletop games. The box opens into dice storage and a lined rolling tray. The life counter, a counter for tracking a value during play, uses rotating numbered rings. ## Dice box layout One half of the box holds the dice; the other has a dark lining for rolling. The brown printed body has a textured lid, rounded corners, and inset closure pieces (parts set into the body to hold it closed). The cover shows the brown box open during use. The gallery shows the brown box closed for storage and a mint-green variant open on wood, with black felt lining, four inset magnets, and its detached textured lid behind the base. ## Box files and variants The print files include: - Separate tops and bottoms. - A card-size box. - Decorative variants. The lining and closure pieces are added to the printed shell during assembly. ## Rotating life counter Each digit is built into a separate printed ring. Turning a ring changes that digit while the others stay in place. End pieces hold the assembly together, and a pointer identifies the selected number. The gallery shows loose gray rings and end pieces alongside an assembled multicolored counter and a light blue-grey marble-speckled counter. The marble-speckled build has an embossed arrow pointer on its left end and 20 selected on the right ring. The part designs also include a roller, indicator, and stand. ## Fit and assembly notes ### Box lid The box needs a lid that closes cleanly around its base and lining. ### Counter rings The counter needs enough clearance (space between parts) for the rings to turn independently while staying held by the end pieces. Check those fits before finishing the box or fully assembling a counter. Alternate part versions may need different matching pieces. ## Photos and related work I also made [Catan organizers]() with card trays and covered cases for roads, settlements, and cities. ## FAQ ### How does the dice box work during play? The box opens into dice storage on one side and a lined rolling tray on the other. ### How do the life counters change values? Each digit is on a separate rotating printed ring. End pieces hold the rings together, and a pointer identifies the selected number. ### What fits need checking during assembly? The box lid needs to close around the base and lining. Counter rings need enough clearance to turn independently while remaining held by the end pieces; alternate versions may require matching parts. ## Build photos ![The brown dice box closed, showing its textured lid and rounded rectangular shape.]() The same style of box closed for storage. ![Separate gray printed numbered rings and end pieces for a tabletop counter.]() Counter parts before assembly, including the numbered rings. ![An assembled multicolored tabletop life counter with raised numbers on its rotating rings.]() A finished counter with the digits built into the printed rings. ![An open mint-green dice box on wood with black felt lining, four silver rim magnets (two per long side), and a detached lid with a textured triangular pattern behind the base.]() A mint-green box variant with black felt lining and four inset magnets, with its textured lid behind the base. ![An assembled light blue-grey marble-speckled rotary life counter on a cutting mat, with an embossed arrow on the left end, a 2 visible on the middle ring, and 20 selected on the right ring among teen and twenty-range values.]() A marble-speckled life counter with an embossed arrow pointer and 20 selected on the right ring. ## Related reading - [Catan Organizers]() - [Rigid Heddle Loom Accessories]() - [Ring and Jewelry Organizer]() --- # Printed LED Sculptures > Printed frames turn light strips into geometric desk lights, wall pieces, and an open-frame color-changing sculpture. Canonical page: [Printed LED Sculptures]() Project date: 2022 Updated: 2026-10-14 Category: Lighting & fabrication Status: Physical builds Tags: 3D printing, LEDs, CAD, Electronics - **My work:** Printed frames, lighting integration, and assembly - **Forms:** Desk light, wall frame, and open geometric sculpture - **Lighting:** LED tubing and exposed light strips ## In short I made printed frames for a geometric desk light, a wall piece, and a larger open-frame sculpture. The frames hold the lighting along edges, corners, and diagonals, making the structure and light path part of the appearance. ![A glowing blue and white Ethereum-shaped desk light in a printed frame beside a clock and plant.]() A freestanding geometric light with LED tubing held by a printed frame. ## Overview I made printed frames to hold LEDs in geometric shapes: a desk light shaped like the Ethereum emblem (the geometric symbol of the Ethereum blockchain network), a wall piece, and a larger open-frame sculpture. The frames position the lights along edges, corners, and diagonals. ## Desk and wall lights ### Freestanding desk light The desk light uses LED tubing, lighting enclosed in a tube, held in a freestanding printed frame. Its continuous lines follow the outline of the Ethereum emblem. ### Wall-mounted frame The wall version uses channels in the frame to position the lighting. With the LEDs off, the purple printed structure and its supports are visible. ## Open-frame sculpture The larger sculpture has LED strips, flexible bands carrying individual LEDs, running along the edges and diagonals of a three-dimensional frame. The strips and wiring remain exposed during assembly, with individual points of light tracing the structure when switched on. The finished sculpture can light up blue, red, and green. The gallery shows it during assembly and illuminated in blue. ## Structure and light placement The smaller lights create a continuous outline, while the larger sculpture makes the separate LEDs part of the appearance. In both, the printed frame determines the path of the light and holds it in place through corners and intersections. ## Related builds My [Rust furnace lamps]() hide the light inside painted shells. These sculptures keep the structure and light path visible. I printed the frames, assembled the lights, and integrated the wiring. The small lights use the existing Ethereum emblem as their shape. ## FAQ ### What kinds of lights are shown? The builds include an Ethereum-emblem desk light, a wall-mounted frame, and a larger open-frame geometric sculpture. ### How do the printed frames hold the lighting? The frames position LED tubing or light strips along edges, corners, and diagonals. The wall frame uses channels, while the larger sculpture has strips along its edges and diagonals. ### Which colors can the larger sculpture display? The finished sculpture can light up blue, red, and green. The gallery shows it illuminated in blue. ## Build photos ![The unlit purple geometric light frame mounted on a wall, showing its channels and support structure.]() The light's frame with the LEDs off, making the printed structure easier to see. ![An open geometric frame on a desk with exposed LED strips following its edges and diagonals.]() The larger geometric light during assembly, with the strips and wiring visible. ![An open-frame geometric sculpture glowing blue at its edges on a workbench.]() The assembled sculpture glowing blue. It also lights up red and green. ## Related reading - [Reflector Lantern]() - [From the Workbench]() - [Catan Organizers]() --- # Reflector Lantern > A 3D-printable RGBW lantern with a curved mirror that spreads light around it. Canonical page: [Reflector Lantern]() Project date: Sep 2026 Updated: 2026-10-14 Category: Lighting & fabrication Status: Open source Tags: 3D printing, OpenSCAD, LEDs, WLED, Electronics - **My work:** Parametric OpenSCAD design, STL exports, and mirror ray trace - **Size:** About 118 mm wide × 112 mm tall - **Power:** Two 18650 cells in parallel (1S2P), with a 5 V boost - [View source]() ## In short I designed a small printable lantern with a ring of colored and white LEDs pointing into a curved mirror. The mirror spreads light around roughly a full circle, and the adjustable model lets me export individual parts and rerun the mirror simulation when I change its shape. ![Repository assembly render of Reflector Lantern showing the LED ring, translucent tube, top reflector, and base.]() Assembly render from the project repository, showing the lantern's modeled parts. ## Overview I designed a small printable lantern around a 24-LED RGBW (red, green, blue, and white) ring pointing up into a curved mirror. The mirror redirects light around roughly 360°, from about 30° below to 50° above the horizon. The model is about 118 mm wide and 112 mm tall; the images show the repository’s assembly render and cross-section diagram. ## Model and printing ### Adjustable model and exports I made the design parametric (adjustable through named dimensions and settings) in `lantern.scad`. Open it in OpenSCAD, a code-based 3D modeling program, using its Customizer settings panel or set `part` to export individual pieces. The repository includes print-oriented STL exports (3D-printable mesh files) and `raysim.py`, a 2D mirror ray trace (a simulation of light paths) to rerun when changing the reflector geometry. ### Print settings PLA and PETG are plastics commonly used in 3D printing. The parts use these settings: - **Base:** PLA or PETG, top face down, without supports. - **Reflector:** PLA, flange down, without supports, using 10–15% infill (the internal printed structure). - **Diffuser:** clear or natural PETG, either the 1.6 mm wall tube or the vase-mode version with about a 0.8 mm line width. Vase mode prints a continuous single-wall shell. Measure the battery holders and adjust their dimensions in the model before printing. ### Mirror finish options The mirror finish starts with sanding the curved surface from 240 to 800 grit (abrasive grades, with higher numbers giving a finer finish). The README lists these finishing options: - Molotow Liquid Chrome over glossy black primer. - Aluminized mylar or chrome vinyl cut into gores (tapered sections that fit a curved surface). - Silver spray paint. ## Electronics and assembly ### Parts list The parts list uses: - An Adafruit 24-pixel NeoPixel RGBW ring or a compatible 66 mm SK6812/WS2812 ring. NeoPixel is Adafruit’s name for individually controllable LEDs; SK6812 and WS2812 are addressable LED families. RGBW adds a separate white channel to the red, green, and blue channels. - An ESP32-C3 SuperMini (a small microcontroller board) running WLED (software for controlling LED lighting). - Two 18650 cells (cylindrical rechargeable batteries) wired in parallel, called 1S2P: one series group containing two parallel cells. - A USB-C charger with a 5 V boost converter, which raises voltage, rated for at least 2 A. - A 12 mm latching button, which stays in its selected state after being pressed. - A 300–470 Ω data resistor. - A 470–1000 µF capacitor across the LED supply. ### Assembly sequence 1. Flash WLED (install its software) over USB first. 2. Fit and hot-glue the ring into its pocket, then feed the wires through the slot. 3. Fit the button and wire the charger, controller, and holders. 4. Tape the holders onto the lid and close it with four M3×10 self-tapping screws. 5. Press the tube into the base groove and the reflector onto the tube; a dab of glue secures them. An optional M4 eye bolt allows hanging. ### Current and estimated runtime The README gives: - Up to about 1.4 A at full white. - A recommended 1200 mA WLED current limit. - Roughly 6–10 hours of estimated runtime at a cozy brightness with two approximately 3000 mAh cells. Milliamp-hours (mAh) express battery charge capacity. ## Related builds My [Printed LED Sculptures]() use printed frames to position light along geometric shapes. ## FAQ ### How does the lantern spread its light? A 24-LED RGBW ring points upward into a curved mirror, which redirects light around roughly 360 degrees, from about 30 degrees below to 50 degrees above the horizon. ### Can I adjust and export the model? Yes. Open lantern.scad in OpenSCAD and use the Customizer or set part to export individual pieces. The repository includes STL exports and a mirror ray-trace script. ### What electronics does the design use? The parts list includes an RGBW LED ring, an ESP32-C3 SuperMini running WLED, two parallel 18650 cells, and a USB-C charger with a 5 V boost converter. ## Build photos ![Repository cross-section diagram showing the curved reflector above the LED ring and the battery space inside the base.]() Cross-section diagram from the project repository showing the reflector profile and internal layout. ## Related reading - [Printed LED Sculptures]() - [From the Workbench]() - [Rust Furnace Lamps]() --- # Rigid Heddle Loom Accessories > Printed heddle holders and reeds, from stepped support panels to modular sections assembled between wooden rails. Canonical page: [Rigid Heddle Loom Accessories]() Project date: Jul 2022–Oct 2022 Updated: 2026-10-15 Category: Weaving accessories Status: Physical builds Tags: 3D printing, CAD, Product design, Weaving - **My work:** CAD design, printing, and revisions - **Objects:** Panel holders, holder blocks, clip-on arms, and reeds - **Print options:** PLA or PETG; parts fit a 256 mm cube print volume ## In short I designed and printed holders and reeds for rigid heddle looms as product designs for my planned 3D-printing shop. The holders support one or more heddles, the slotted frames that guide the loom's threads. The reeds range from a small nine-slot piece to modular sections assembled between wooden rails. I revised each design through several versions; measurements should be checked against the loom before printing. ![A mirrored pair of flat tan printed panels, each with three stepped rows of hook-shaped slots and mounting holes along the inner edge.]() The three-row holder panels form a mirrored pair, with mounting holes along their inner edges. ## Overview I designed and printed these rigid heddle loom accessories as product designs for my planned 3D-printing shop. A rigid heddle, also called a reed, is a frame with alternating slots and holes for the warp threads, the threads running lengthwise through the loom. Lifting or lowering it opens a gap called the shed. The weft, the thread woven across the warp, passes through that gap. I worked on both the reeds and the holders that support them. ## Stepped heddle holders Heddle holders, sometimes called heddle blocks, hold the heddle in its up, neutral, and down positions. Extra rows let a weaver use two or more heddles at once for more complex cloth. The mirrored three-row panels are each about 145 by 115 by 14 mm, with a row of mounting holes along the inner edge. I also made four-slot holder blocks, about 100 by 115 by 14 mm, with screw holes. The clip-on arms have a long top hook that hangs over the loom frame and stepped hooks down the side for resting heddles. These designs are about 83–91 mm wide, with hook and no-hook versions and two- and three-step variants. ## Small and modular reeds The mini reed is a narrow piece with nine slots and eyelets between them, about 54 by 104 by 4 mm. For a full-width heddle, I made modular reed sections that line up between two wooden rails, with small printed end caps. Each section is about 112 by 100 by 13 mm. I made sections in more than one dent spacing. Dent means the number of slots plus holes per inch. My reed designs include 5, 8, and 10 dent variants, including a six-inch reed. ## Revisions and loom fit I went through several computer-aided design (CAD) versions of each design. The files are printable in PLA or PETG on a Bambu Lab A1-sized bed, with a print volume of 256 mm in each direction. Fit to a particular loom brand is not confirmed. Check the holder dimensions, mounting holes, and reed measurements against the loom before printing. These sit alongside my [Catan organizers]() as printed product designs built around the objects they hold. ## FAQ ### What accessories are included? The designs include stepped panel holders, four-slot holder blocks, clip-on arms, a nine-slot mini reed, and modular reed sections assembled between wooden rails. ### Will the holders fit my loom? Fit to a particular loom brand is not confirmed. Check holder dimensions, mounting holes, and reed measurements against the loom before printing. ### What materials and print volume do the designs use? The files are printable in PLA or PETG within a 256 mm cube print volume, such as a Bambu Lab A1-sized bed. ## Build photos ![Two tan three-row holder panels laid one above the other, showing stepped hook-shaped slots and a line of mounting holes on each panel.]() The same panel pair laid out to show the slots and mounting holes. ![Two cream printed four-slot holder blocks lying side by side on a dark surface.]() A pair of four-slot holder blocks laid flat. ![Two cream four-slot holder blocks standing upright facing each other on a dark surface, with screw holes visible.]() The four-slot blocks upright, showing their stepped supports and screw holes. ![Two tan printed holder arms with long top hooks for hanging over a loom frame and stepped hooks down their sides.]() Clip-on arms use a top hook to hang over the loom frame and side hooks to rest heddles. ![A small narrow tan printed reed with nine slots and eyelets between them, lying on a light wood surface.]() The nine-slot mini reed measures about 54 by 104 by 4 mm. ![A full-width rigid heddle made from several printed slotted modules held between two light wooden rails on a dark surface.]() Printed reed modules line up between wooden rails to make a full-width heddle. ![A low-angle close-up looking along the repeated slots and holes of a long assembled printed reed.]() A close view along the assembled reed's alternating slots and holes. ## Related reading - [Catan Organizers]() - [Ring and Jewelry Organizer]() - [From the Workbench]() --- # Ring and Jewelry Organizer > A 3D-printed jewelry organizer with three ring cones and a shallow tray for loose jewelry. Canonical page: [Ring and Jewelry Organizer]() Project date: Dec 2020 Updated: 2026-10-15 Category: Jewelry organizers Status: Physical builds Tags: 3D printing, CAD, Product design, Jewelry - **My work:** CAD design and printing - **Objects:** Three ring cones and a shallow jewelry tray - **Print options:** PLA or PETG; approximately 140 × 80 × 84 mm ## In short I designed and printed this jewelry organizer with three ring cones at the back and a shallow tray at the front. My December 2020 photos show the physical print in use with rings and loose jewelry. The charcoal sample has KYLA recessed into its front face as a historical customization. ![A charcoal printed jewelry organizer with three ring cones at the back, a shallow front tray holding jewelry, and KYLA recessed into the front face.]() My December 2020 physical print in use, with KYLA lettering as a historical customization sample. ## Overview I designed this ring and jewelry organizer in CAD (computer-aided design) and made a physical print. Three conical holders sit in a row at the back, with a shallow tray at the front for loose jewelry. The cones act as mandrels, or tapered spires that rings slip over. The tray gives other small jewelry a place to rest alongside the rings. ## Printed sample and personalization My December 2020 phone photos show the organizer in use with rings and jewelry. The sample is dark gray or charcoal, with visible layer lines from FDM (fused deposition modeling), a printing process that builds an object in layers of melted filament. The front face has debossed lettering, meaning letters recessed into the surface, spelling KYLA. I show this as a historical customization sample; the photos document that personalized print rather than establish which versions are available. ## Size and print options My STL print file has an overall envelope of approximately 140 × 80 × 84 mm. It fits within a 256 mm cube print volume, such as the Bambu Lab A1’s, and can be printed in PLA or PETG. This is another of my printed product designs built around the objects it holds, alongside my [Catan organizers](), [dice boxes and counters](), and [rigid heddle loom accessories](). ## FAQ ### What does the organizer hold? Three tapered cones at the back hold rings, and a shallow front tray holds loose jewelry. ### What are its size and print options? The STL has an overall envelope of approximately 140 × 80 × 84 mm. It fits within a 256 mm cube print volume and can be printed in PLA or PETG. ### Do the photos show a physical print? Yes. December 2020 phone photos show the charcoal organizer in use with rings and jewelry. The recessed lettering is a historical customization sample. ## Build photos ![Another view of the charcoal jewelry organizer in use with rings and loose jewelry.]() A second December 2020 phone photo of the printed organizer in use. ## Related reading - [Catan Organizers]() - [Rigid Heddle Loom Accessories]() - [From the Workbench]() --- # Dean Android Agent > Dean turns an unrooted Android tablet into an always-on voice assistant for the living room. Canonical page: [Dean Android Agent]() Project date: Oct 2026 Updated: 2026-10-14 Category: Voice assistants Status: Open source Tags: Python, Android, Termux, Voice assistant, OpenRouter - **My work:** Python voice assistant, LLM tool loop, wall dashboard, and Telegram texting - **Platform:** Unrooted Android tablet via Termux; tested on onn. 12-inch Tablet Pro (2024) - **License:** MIT - [View source]() ## In short I built Dean to turn an Android tablet into an always-on living-room voice assistant that answers aloud and works with household devices, information, lists, and reminders. I can also text it from my phone, and follow-up voice questions share conversation context for three minutes. Wake-word detection and speech-to-text run on the tablet, while transcribed requests go to a model provider through OpenRouter. ![Illustration of a tablet and microphone beside the Dean voice assistant name; not a screenshot.]() Illustration of Dean's Android tablet voice pipeline, not a screenshot. ## What it does I built Dean as an always-on voice assistant that runs on an unrooted Android tablet, without unlocking administrator-level access to Android. Say **“hey dean”**, ask a question, and it can answer aloud or use tools (functions that perform actions or retrieve information) to work with household devices, information, lists, and reminders. Conversations carry over for three minutes so follow-up questions can use the same context. I built and tested it on an **onn. 12” Tablet Pro (2024, model 100146663)** with a MediaTek Helio G99, 6 GB RAM, and Android 14. The Python assistant runs through Termux, an Android terminal and Linux tool environment, and a Debian environment, which provides tools from the Debian Linux distribution. ## Voice pipeline The voice pipeline has four stages: 1. The microphone feeds **Vosk**, a speech-recognition engine, for the wake word—the phrase that activates listening for a request. 2. **Moonshine**, a speech-recognition model, handles speech-to-text, converting speech into a transcript. 3. The transcript goes to an LLM (large language model) with tools through **OpenRouter**, a service that routes requests to model providers. The tool loop lets it use their results while answering. The response is streamed back, arriving in pieces as it is generated. 4. **Piper**, a text-to-speech engine, speaks it sentence by sentence as the answer arrives. Wake-word detection and speech-to-text run on the tablet. ### Measured response times The README’s latency table (the delay before a response) reports measurements on that onn. tablet, counted from when speaking stops: - **End-of-speech detection:** 0.7 seconds. - **Moonshine transcription:** 0.3 seconds for a four-second command. - **LLM’s first words:** about 1.0 second on a simple question. - **Weather or sensor question:** about 2.5–3.2 seconds with one tool round. - **Piper’s first audio:** 0.2–0.7 seconds after a sentence arrived. These are the README’s measured numbers on that tablet, not response-time guarantees. ## Tools it can use The model decides when to call tools. ### Information, lists, and memory The information tools cover: - Web search. - Open-Meteo weather and US National Weather Service alerts. - NPR or topic-based news headlines. - Private iCal calendars (a format for sharing calendar events). - OpenRouter spending. Named lists are shared between voice and text. Timers, reminders, alarms, and plain-English routines are saved so they survive restarts. Long-term memory is stored on the tablet. ### Household devices and phone finding For the home, Dean can: - Control Govee lights over LAN (the local area network) or the cloud API (an interface for communicating with a remote service). - Operate a Roku TV over the local network. - Read Govee Bluetooth thermometers through a companion app. - Check household phone presence on Wi-Fi. - Deliver reminders when someone gets home. - Ring a Pixel through the Dean Finder app or an iPhone through an email-triggered Shortcut, including when the phones are on silent. ### Tablet controls and camera Termux:API, an add-on that exposes Android device features to Termux, provides location, tablet sensors, battery and device status, volume, brightness, and flashlight controls. The camera tool takes a photo to answer a question, chimes when used, and deletes the photo right away. ## Wall dashboard and texting ### Wall display The full-screen Termux dashboard shows a clock, date, weather and forecast, light status, the next three reminders or alarms, and recent conversation. A status bar shows what Dean is doing. ### Text conversations A Telegram bot (an automated account on the Telegram messaging service) lets me text Dean from a phone. Only allowed chats can use it, and each chat keeps its own conversation. Reminders set by text are sent back by text, while the `announce` tool speaks at home. Camera access over text is disabled by default. ## Limits and setup ### Foreground audio and reboot recovery **Termux must stay on screen:** Android silences the microphone for background apps. Dean can recover its audio once Termux is back in front. Termux:Boot, an add-on for running scripts after Android starts, also runs only after the first unlock following a reboot; unattended recovery from a power cut needs no lock or swipe-to-unlock. ### Battery care A tablet plugged in around the clock can develop a swollen battery over time. The README recommends a charge limit where available or a smart plug on a schedule. ### Requests sent to model providers Wake-word detection and speech-to-text stay on the device, but transcribed requests go to the chosen model provider through OpenRouter. Photos also go through OpenRouter when I ask Dean to look at something. ### Setup and source The public [GitHub README]() documents Termux setup, API configuration, companion apps, and integration requirements. The code is MIT licensed. There are no GitHub releases yet, so the project action links to source. ## FAQ ### Does Dean need a rooted Android tablet? No. It runs on an unrooted Android tablet through Termux and a Debian environment. It was built and tested on an onn. 12-inch Tablet Pro from 2024. ### Does voice processing stay on the tablet? Wake-word detection and speech-to-text run on the tablet. Transcribed requests go to the chosen model provider through OpenRouter, and photos also go through OpenRouter when the camera is used. ### Can Dean listen while Termux is in the background? Termux must stay on screen because Android silences the microphone for background apps. Dean can recover its audio once Termux returns to the foreground. ### Can I use Dean by text? A Telegram bot provides text conversations for allowed chats. Each chat keeps its own conversation, and reminders set by text are sent back by text. ## Related reading - [DevBot]() - [DERP]() - [Solar Cellular Trail Camera]() --- # OpenSnip > A native screenshot tool for Windows and Linux, with annotations, pinned images, and MP4 screen recording on Windows. Canonical page: [OpenSnip]() Project date: Oct 2026 Updated: 2026-10-14 Category: Desktop software Status: Open source Tags: C#, .NET, Windows, Avalonia, Screen capture - **My work:** C#/.NET application, capture workflow, annotation editor, and screen recording - **Platform:** Windows 10 and 11; x64 Linux (screenshots only) - **License:** MIT - [View source]() ## In short I built OpenSnip to capture screenshots on Windows and Linux. On Windows, I can use built-in keyboard shortcuts, annotate captures, keep pinned images above other windows, and record part of the screen with optional system sound and microphone audio. ![Illustration using the OpenSnip app icon to represent the Windows screenshot and screen recording tool.]() Illustration using the OpenSnip icon. Snip and record shortcuts are listed on the cover. ## What it does OpenSnip is a screenshot tool I built for Windows and Linux in C# and .NET, with screen recording on Windows. On Windows, press **Win+Shift+S** or **PrtSc**, drag a region or click a window, and the capture is on the clipboard and optionally saved to disk. **Win+Shift+R** records a video of any part of the screen, with system sound and microphone if you want them. I built it as a small tray app (an app accessed from the system tray near the Windows clock) that freezes the screen the moment the shortcut fires, so menus and tooltips stay put while you select. Mixed-DPI (screens with different display scaling) and multi-monitor (more than one screen) setups are supported. The Windows app needs no installer; it is about 1.5 MB and lives in the system tray. The capture, editor, shortcut, and recording details below describe that Windows app. ## Capture and annotation ### Overlay selection The overlay freezes the display, then you drag a region, click a highlighted window, press **F** for the monitor under the cursor, or **A** for all monitors on still captures. A magnifier shows pixel coordinates and color while lining up edges. Captures copy to the clipboard as PNG (a lossless image format) so pasting into Discord, Slack, browsers, and documents keeps full quality. Optional auto-save writes PNG or JPG (a compressed image format) to a chosen folder, with monthly subfolders if you want them. ### Editor and pinned images After a snip, a small corner preview can open the editor or be dragged into another app as a file. The editor includes arrows, boxes, pen, highlighter, text, and pixelation (covering detail with blocks) for redaction (hiding sensitive information), with undo and redo. Every edit updates the clipboard automatically. Pinned images stay on top of other windows; they can be moved, resized, zoomed, and faded. ### Extra shortcuts Other capture shortcuts include a delayed snip (**Shift+PrtSc** by default) and re-capturing the last region (**Ctrl+PrtSc**). Every shortcut can be changed in settings. ## Screen recording **Win+Shift+R** starts or stops recording. Selection works like a screenshot: area, window, or one monitor. An optional countdown comes first, then a red outline and a small control bar for pause, microphone mute, stop, and discard. The outline and bar are excluded from the recorded video. Recordings use hardware-accelerated H.264 (a video compression format) in an MP4 file (a container for video and audio). Settings cover system sound, microphone device, 30 or 60 fps (frames per second), quality, cursor visibility, and countdown. Stopping saves to `Videos\OpenSnip` by default and copies the file to the clipboard. Clicking the recording preview plays it. ## Settings and install The tray menu opens settings for capture, saving, recording, shortcuts, and general behavior, including optional start with Windows. Changes apply immediately. To build from source on Windows with the .NET 9 SDK (software development kit): ```bash git clone https://github.com/DevanMetz/OpenSnip cd OpenSnip/src dotnet publish -c Release -p:PublishSingleFile=true -o ../dist ``` That produces `dist/OpenSnip.exe`, which needs the .NET 9 Desktop Runtime (the components needed to run .NET desktop apps). A self-contained publish (a build that includes the runtime) produces a larger standalone executable. The source is available under the MIT license; see the [README]() for the current setup notes. [Releases]() include `OpenSnip.exe`, `OpenSnip-standalone.exe` (with the runtime included), and a native Linux archive. ## Linux I ship a separate native Linux app built with Avalonia (a desktop interface framework). It covers screenshots only: region, monitor, and all-monitor selection with a magnifier, PNG clipboard copies, PNG/JPG auto-save, preview, tray icon, and settings. Recording, the annotation editor, pins, and built-in global shortcuts remain Windows-only. It requires x64 Linux with X11 (a Linux display system) or Wayland (the newer display system) with `xdg-desktop-portal` (a desktop service that grants screenshot access). X11 capture uses libX11, with `maim`, ImageMagick `import`, and `scrot` as fallbacks. Wayland uses the portal’s Screenshot API, with `grim`, `gnome-screenshot`, and `spectacle` as fallbacks. Clipboard support needs `xclip` on X11 or `wl-clipboard` on Wayland. A tray host is optional; without one, Settings opens on launch and closing it quits. Download `OpenSnip-linux-x64.tar.gz` from [Releases](), then run: ```bash tar -xzf OpenSnip-linux-x64.tar.gz cd OpenSnip-linux-x64 ./install.sh ``` The installer puts `opensnip` in `~/.local/bin`; make sure that directory is on `PATH` (the folders searched for commands). Bind desktop shortcuts in GNOME or KDE to `opensnip --snip`, `opensnip --snip-delay`, or `opensnip --repeat`; `opensnip --settings` opens settings. To build from the repository root: ```bash dotnet publish linux/OpenSnip.Linux.csproj -c Release -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:DebugType=none -o dist/linux ``` ## Limits The Windows app requires 64-bit Windows 10 (version 2004 or later) or Windows 11. Screen recording also needs the Microsoft Visual C++ Redistributable for x64 (runtime libraries for 64-bit applications). All-monitor capture is available for screenshots; recording selects an area, window, or a single monitor. If Print Screen still opens Windows Snipping Tool, turn off **Use the Print screen key to open screen capture** under Windows **Settings → Accessibility → Keyboard**. If another app grabs a shortcut first, pick a different combination in OpenSnip. `Alt+PrtSc` and `Win+PrtSc` keep their normal Windows behavior. For troubleshooting, `OpenSnip.exe --diagnostics` writes a display, audio-device, and recorder-start report to `%APPDATA%\OpenSnip\diagnostics.txt`. ## FAQ ### Which OpenSnip features work on Linux? The native x64 Linux app supports screenshots, including region, monitor, and all-monitor selection, clipboard copies, auto-save, preview, and settings. Recording, annotation, pins, and built-in global shortcuts remain Windows-only. ### How do I capture or record on Windows? Win+Shift+S or PrtSc starts a screenshot selection. Win+Shift+R starts or stops recording a selected area, window, or monitor. ### Can recordings include system sound and microphone audio? Yes. Windows recordings support optional system sound and microphone audio and save H.264 video in an MP4 file. ## Related reading - [OpenMic]() - [FeatherClick]() - [KICKR CORE 2 Hub]() --- # Technical Writing for All3DP > Published guides to Arduino, CNC, and 3D-printing software, grounded in hands-on maker work. Canonical page: [Technical Writing for All3DP]() Project date: 2020 Updated: 2026-10-14 Category: Writing & documentation Status: Published articles Tags: All3DP, Arduino, CNC, Tutorials - **My work:** Published maker guides and a functional CAD tutorial - **Subjects:** Arduino · CNC · 3D-printing software - **Publication:** All3DP - [Read an All3DP guide]() ## In short I wrote maker guides for All3DP covering Arduino, CNC hardware, and 3D-printing software. I also wrote a separate functional CAD tutorial that takes measurements of USB drives and a card reader through modeling to a printed organizer, giving readers a concrete result to compare with the original need. ![A blue printed organizer holding USB drives and a card reader on a cutting mat.]() A build photograph from my functional-CAD tutorial sample, separate from the published articles below. ## Overview I’ve written maker guides for All3DP (an online 3D-printing publication) covering Arduino (a platform for programmable electronics), CNC (computer numerical control) hardware, and 3D-printing software. I’ve also written a functional CAD (computer-aided design) tutorial built around a printed organizer for USB drives and a card reader. ## Published articles The Arduino beginner guide introduces microcontrollers (small computers that control electronics), the Uno (an Arduino board), and a first Blink sketch (a program that blinks an LED). The CNC hardware guide covers a CNC shield (an add-on board for connecting CNC hardware to an Arduino). Cura (a slicer that prepares 3D models for printing) is the subject of the Linux walkthrough. | Article | Subject and date | | --- | --- | | [Arduino for Beginners: How to Get Started]() | Introduction to microcontrollers, the Uno, and a first Blink sketch; August 15, 2020 | | [Arduino CNC Shield: Buyer’s Guide]() | What the shield does and how controller options differ; August 1, 2020 | | [Cura & Linux: How to Make Them Work Together]() | Installation and first-use walkthrough; June 30, 2020 | | [CNC 3018 (Pro) Software: The Best Programs]() | CNC software guide credited to Devan Metz and Guilherme Schendel; updated September 24, 2024 | These links go to the articles on All3DP, where later editorial updates may have changed the original text. Product recommendations and software steps reflect their publication dates. ## Functional CAD tutorial My functional CAD tutorial walks through making an organizer for USB drives and a card reader. It starts with measurements, develops the shape through sketches and modeling, and ends with a printed part holding the devices. The blue organizer in the cover photo is from this separate tutorial sample. ## Explaining through an object The tutorial’s sequence gives a reader a concrete path through the subject: 1. Identify the physical objects that need organizing. 2. Measure the dimensions that constrain the holder. 3. Turn those measurements into sketches and model geometry. 4. Show the intermediate modeling work. 5. Compare the printed result with the original need. The finished organizer gives the reader a way to compare the dimensions in the model with the fit of the real devices. ## Writing approach These guides explain a subject through a specific task: running a first Arduino sketch, choosing CNC controller hardware, or turning measurements into a part that fits. Each step gives the reader something concrete to try or compare. For a related example with editable dimensions and printing notes, see [Parametric FreeCAD Designs](). ## FAQ ### What subjects did Devan write about for All3DP? The published guides cover Arduino, CNC hardware, and 3D-printing software, including a first Blink sketch, CNC shields, Cura on Linux, and CNC 3018 software. ### What does the functional CAD tutorial build? The separate tutorial develops an organizer for USB drives and a card reader, starting with measurements and ending with a printed part holding the devices. ### Is the cover photo from an All3DP article? The blue printed organizer in the cover is from the separate functional CAD tutorial sample. ## Related reading - [OpenFloat Archery]() - [Goop Troops]() - [DIY Electric Bike]() --- # FeatherClick > A Rust autoclicker with adjustable timing, target spread, hotkeys, and a headless mode. Canonical page: [FeatherClick]() Project date: Sep 2026 Updated: 2026-10-27 Category: Desktop software Status: Open source Tags: Rust, egui, Desktop software, Automation - **My work:** Click engine, desktop interface, CLI, and platform integration - **Platform:** Windows · macOS · Linux - **Release:** v0.2.0 · October 2026 - [Download FeatherClick]() - [View source]() ## In short I built FeatherClick in Rust to repeat mouse clicks from a desktop window or the command line. I can choose the timing, target position and spread, and stop conditions, with downloads for Windows, macOS, and Linux and platform-specific limits on clicking and hotkeys. ![FeatherClick's blue click icon with the project's name, timing modes, and supported operating systems.]() Illustration using the FeatherClick icon. Fixed, uniform, and Gaussian are the three timing modes. ## What it does FeatherClick is a small mouse autoclicker (a tool that repeats mouse clicks) I built in Rust. The same click engine runs from a desktop window or in headless mode (without a desktop window) from the command line. The [v0.2.0 release]() provides downloads for Windows, macOS, and Linux. The window keeps the main controls together: which button to click, when to click it, where to aim, and when to stop. Global hotkeys can start or stop a run and capture a position where the platform supports them. ## Timing and targeting The timing modes are: - **Fixed:** the same requested interval between clicks. - **Uniform:** randomly chosen intervals between two limits. - **Gaussian:** intervals sampled from a Gaussian distribution (a bell-shaped distribution centered around a mean). A click can use the pointer’s current position or return to a selected point. For a selected point, the target can vary within a box, ellipse, or Gaussian spread. The engine supports left, right, and middle buttons, including single clicks, double clicks, and press-and-hold. A run can stop: - After a set number of clicks. - After a time limit. - When the pointer moves away from the click point. The click limit is reported right after the final click. The time limit is checked every 25 ms, even during long intervals. These controls also make short, bounded runs practical. ## How it is built The app uses Rust, `egui`/`eframe` (a user-interface library and its app framework) for its window, and platform input and hotkey libraries. The engine takes a snapshot of the settings at the start of each run, so changing a control in the window does not alter a run already in progress. Edited settings are saved to a local JSON (a structured text format) file after a short delay, with an atomic write (replacing the saved file in one operation) to avoid truncating the file if saving is interrupted. The click loop sleeps in short slices and uses a brief spin near the next click. On Windows it raises timer resolution (how finely the system schedules timed waits) while a run is active. In the project’s Windows 11 measurements, a requested 100 ms fixed interval produced click intervals of 96–109 ms. Those numbers describe that test setup, not a guarantee across machines. The command-line mode uses the same engine for scripts or environments without a desktop window. Passing `--clicks` or `--seconds` clears both saved limits and uses the specified limit instead. Invalid arguments return exit status `2`. The source includes tests and continuous integration builds for the three supported operating systems. ## Platform limits Windows supports the window, clicking, and global hotkeys. macOS needs Accessibility permission (macOS authorization to control input) to send clicks; the Windows and macOS releases are unsigned, and the macOS release is not notarized (checked by Apple for malicious software). Linux supports X11 (a Linux display system) and some Wayland (a newer display protocol) compositors (software that manages windows and display output). On Wayland, global hotkeys are unavailable, and native clicking depends on the compositor’s virtual-pointer support. FeatherClick does not record macros or automate keyboard input, and its interface is not exposed to screen readers. The [README]() has the current setup notes, platform table, command-line examples, and limitations. The source is available under the MIT license. ## FAQ ### Which operating systems does FeatherClick support? The v0.2.0 release provides Windows, macOS, and Linux downloads. macOS needs Accessibility permission for clicking. On Wayland, global hotkeys are unavailable and native clicking depends on compositor virtual-pointer support. ### Can FeatherClick run without a desktop window? Yes. Its command-line headless mode uses the same click engine as the desktop window. ### How can I limit a clicking run? A run can stop after a set number of clicks, after a time limit, or when the pointer moves away from the click point. ### Which timing modes are available? Fixed timing requests the same interval between clicks. Uniform timing chooses intervals between two limits, and Gaussian timing samples intervals from a bell-shaped distribution around a mean. ## Related reading - [OpenMic]() - [DevBot]() - [OpenSnip]() --- # Market Atlas > A public market research workspace for U.S. sectors, asset comparisons, correlations, and portfolio simulations. Canonical page: [Market Atlas]() Project date: Sep 2026 Updated: 2026-10-14 Category: Web tools Status: Open source Tags: TypeScript, React, Cloudflare Workers, Market data - **My work:** Market research interface, charts, and Worker APIs - **Stack:** React · TypeScript · Recharts · Cloudflare Workers - **License:** MIT - [Open the workspace]() - [View source]() ## In short I built Market Atlas to compare markets, research stocks and sectors, and simulate portfolios without an account or brokerage connection. Research settings can be shared by URL, while watchlists, portfolio settings, and saved views stay in the visitor's browser. ![Market Atlas Market overview showing five benchmark quote cards, a performance comparison chart, sector landscape tiles, and a sector leaderboard.]() Screenshot of the live site's Market overview, captured October 13, 2026. Prices are Yahoo Finance data from that day and may be delayed. ## What it does I built Market Atlas as a public market research workspace with React, TypeScript, Recharts, and Cloudflare Workers. One Worker (code running on Cloudflare’s servers) serves the APIs (interfaces for requesting data) and built static assets (the site’s files). The default configuration needs no account, brokerage connection, or paid API key. Watchlists, portfolio settings, and saved research views stay in the visitor’s browser in `localStorage` (storage kept by the browser on that device). ## Research tools ### Market and sector views The Market overview brings together: - Five benchmark (reference asset) ETF (exchange-traded fund) quotes. - Cumulative return (growth over time), relative return (performance against a benchmark), and drawdown (decline from a previous peak) charts. - All 11 U.S. sector ETFs and sector leaders. Sector explorer adds absolute and benchmark-relative heatmaps (color-coded comparisons), return tables, and a relative momentum scatter plot (a comparison of recent performance against a benchmark). ### Asset comparisons and screening Compare assets puts up to 12 stocks, sectors, or global assets alongside a benchmark, with returns, excess returns (returns above the benchmark), drawdowns, and hypothetical growth. The Stock screener covers 54 selected U.S. large-cap stocks (companies with large market values) with sector and technical filters (filters based on price patterns); symbol search can find supported assets beyond that catalog. ### Trends, risk, and correlations Trend lab shows rolling returns (returns over a moving time window), volatility (how much returns vary), correlation (how returns move together), beta (sensitivity to benchmark returns), monthly return calendars, and descriptive seasonal averages. Risk lab compares drawdowns on shared dates and separates completed recoveries from ongoing episodes. Correlations shows pairwise daily-return matrices (tables comparing each pair of assets) for sectors, global assets, or the selected comparison. ### Portfolio simulations Portfolio lab runs USD-only (U.S. dollar) simulations with custom starting capital, buy and hold (keeping the initial holdings) or monthly, quarterly, or yearly rebalancing (resetting holdings to the chosen proportions), allocation and profit-contribution breakdowns, and risk measures. The Watchlist keeps saved tickers (asset symbols) on the device. ### Dates, saved views, and exports Research windows use preset horizons (time spans) or custom dates. Historical technical indicators (measures based on past prices) stop at the selected end date; quote cards remain current. Shareable research URLs preserve the selected research settings, and up to 20 named views can be saved locally. Watchlists and portfolio settings remain separate device settings and are not included in shared URLs. CSV (comma-separated values) exports cover research tables, simulations, watchlists, and news. ## News and sentiment ### Headline search The RSS/Atom (web feed formats) headline directory lists 132 publishers and institutions, with 55 checked feeds. Headline search supports words, phrases, alternatives, exclusions, and field filters over the retrieved headlines. ### How sentiment scores work Sentiment uses a transparent English lexicon heuristic (a rule-based score using a list of words). It is not an AI forecast or a trained finance model: scores describe headline word choice, not likely returns. Matched cues, scoring coverage, and sample sizes make the calculation inspectable. News charts describe the currently retrieved snapshot, not a historical archive. Feed entries are reduced to headline, original URL, publisher, and publication time; no full articles are scraped. ## Data and limits ### History and caching Market data comes from Yahoo Finance’s public unofficial chart and search endpoints (API addresses), with no guaranteed service level. This is a research feed, not an execution-quality real-time feed. It provides up to five years of daily history; successful histories are cached at the Cloudflare edge (servers near visitors) and stay fresh for 15 minutes. ### Price adjustments Returns use adjusted closes (closing prices adjusted for events such as stock splits and dividends) when the entire series supports them. Incomplete adjustment falls back to closes for the whole series with a warning. Missing prices are never fabricated or forward-filled (replaced with the last known price). ### Coverage and permitted use The screener catalog is curated rather than a complete stock universe. The application provides no structured fundamentals (company financial measures), options data (contracts to buy or sell at a set price), brokerage actions, or intraday streaming (continuous updates during the trading day). The MIT license covers my code, not third-party market data, which remains subject to provider terms. Market Atlas is for research and education only, not investment advice. Historical results do not guarantee future performance. ## FAQ ### Do I need an account or brokerage connection? The default configuration needs no account, brokerage connection, or paid API key. ### Where are my watchlists and saved views stored? Watchlists, portfolio settings, and saved research views stay in the browser's localStorage on that device. ### What is included in a shared research URL? Shared URLs preserve selected research settings. Watchlists and portfolio settings remain separate device settings and are not included. ### Can Market Atlas execute trades? No. It provides research tools and portfolio simulations without brokerage actions. Its market feed is for research rather than execution-quality real-time data. ## Related reading - [Agent Message Board]() - [KICKR CORE 2 Hub]() - [Goop Troops]() --- # DevBot > A Python terminal coding assistant with file tools, saved sessions, specialist agents, and plan-based automation. Canonical page: [DevBot]() Project date: Jun 2026 Updated: 2026-10-14 Category: Developer tools Status: Open source Tags: Python, CLI, AI, Automation - **My work:** Python CLI, model tool loop, specialist agents, and plan runner - **Runtime:** Python 3.10 or later - **License:** MIT - [View source]() ## In short I built DevBot to work on code from the terminal: I describe a task, and a language model can read files, propose edits, and run tools. It connects to DeepSeek or a local model server, saves conversations for later, and includes specialist agents and a mode that works through a written plan. ![Terminal screenshot of DevBot's real --help output, listing its model, provider, swarm, resume, and run-plan options.]() DevBot's command-line help, captured from the CLI and rendered as a terminal image. ## What it does I built DevBot as a CLI (command-line interface) coding assistant. I can give it a single task, such as fixing a failing test, or keep an interactive conversation open in the terminal. It uses DeepSeek by default and can also connect to a local llama.cpp model server through an OpenAI-compatible API (an interface for exchanging requests with a model). The model has tools to read files, search the project, replace text, write files, run shell commands, and detect and run a project’s test suite. It can also search the web through DuckDuckGo. Conversations save in the project’s `.devbot` directory and can be resumed or exported as Markdown (plain text with formatting). ## How it works DevBot runs an agentic loop (a cycle of model responses, tool calls, and tool results). The model requests an action, DevBot runs the tool, and the result goes back into the conversation. Streaming (showing output as it arrives) lets me follow the response in the terminal. File tools check that resolved paths stay inside the project directory. This provides sandboxed edits (file changes restricted to that directory), rather than isolation of the entire process. Shell commands run from the project directory and use allow and block rules; commands outside those rules need approval. File writes, edits, and test-tool runs also prompt for approval in the normal interactive mode. Auto-approval and unattended modes change that behavior. Swarm mode (a manager delegating work to specialist agents) adds coder, reviewer, tester, and researcher roles. Its pipeline tool sends a task through implementation, review, and fixes. Megaswarm mode can run specialists in parallel and combine their findings through a reviewer. These are model-driven workflows; a review result is not a guarantee that the code is correct. ## Working through a plan With `--run-plan`, I can give DevBot a Markdown plan containing `## Phase` sections. It works through those phases in order, runs the tests after each phase, and attempts a fix if tests fail. If that fix still fails, it stops and leaves the changes for review. This mode runs unattended with auto-approval and leaves its changes uncommitted. The repository also implements `--auto-evolve`: a planner proposes phases, a critic filters them, and the driver implements and tests the accepted work. It requires a clean working tree, refuses to run on `main` or `master`, and commits passing phases on the work branch. Phase, time, and token limits can bound the run; pushing the branch is opt-in. The included `plan.md` describes the design, and the source and tests cover the driver and its stop conditions. ## How it is built I built DevBot in Python with the OpenAI Python client for model requests and `ddgs` for web search. It tracks token usage (the units models use to measure text), estimates cost from configured model pricing, and can compress conversation context for longer sessions. The test suite covers file-path checks, command rules, session persistence, provider selection, plan execution, and the auto-evolve controls. The GitHub Actions workflow is configured to run pytest (Python’s test runner) on Linux, Windows, and macOS with Python 3.10 through 3.13. That configuration describes the intended test matrix, not a claim about every run’s result. ## Where to get it The [source repository]() includes setup instructions, command examples, configuration options, and tests. From a local checkout, install it with Python 3.10 or later: ```sh pip install -e . devbot "fix the failing test" ``` The default provider needs a DeepSeek API key. For a running local model server, use `devbot --local` and the connection settings in the [README](). The project action links to the source repository. DevBot is available under the MIT license. ## FAQ ### Which model providers can DevBot use? DevBot uses DeepSeek by default and can connect to a local llama.cpp model server through an OpenAI-compatible API. ### Can I resume a coding conversation? Yes. Conversations save in the project's .devbot directory and can be resumed or exported as Markdown. ### What happens if a plan phase fails its tests? With --run-plan, DevBot runs tests after each phase and attempts a fix if they fail. If that fix still fails, it stops and leaves the changes for review. This mode leaves changes uncommitted. ## Related reading - [Dean Android Agent]() - [FeatherClick]() - [DERP]() --- # Free Hunting Map > A free, open-source hunting and camping map with public land overlays, terrain scouting, trail-camera planning, and offline sharing. Canonical page: [Free Hunting Map]() Project date: Oct 2026 Updated: 2026-10-27 Category: Web tools Status: Open source Tags: TypeScript, MapLibre, Offline maps, PWA, GIS - **My work:** Map layers, terrain scouting, local data, and offline sharing - **Stack:** TypeScript · MapLibre GL · IndexedDB · Vite - **License:** MIT - [Open the map]() - [View source]() ## In short I built Free Hunting Map because pins dropped on one phone in the woods never showed up on another phone without service. It keeps waypoints and tracks on the device and transfers them by file or QR code without an account. Previously viewed map areas stay available offline. ![Free Hunting Map Layers panel beside a Wisconsin topo map, with layer categories and basemap controls.]() ## Maps for the woods [Free Hunting Map]() is an installable web app for hunting and camping. Switch between topographic, satellite, and street maps, then add layers for scouting: - **Public land:** PAD-US (the Protected Areas Database of the United States) overlays show land managers and designations. Wisconsin parcels, public-access classes, designated wilderness boundaries, and state wildlife agency layers add context. These include hunting and game management units, wildlife management areas, and access programs such as North Dakota PLOTS and Montana Block Management. - **Terrain:** lidar-derived hillshade reveals ridges, drainages, and benches. The experimental Trail finder processes lidar on the device in two supported Wisconsin survey areas; its candidates are unverified clues. - **Roads and trails:** federal U.S. Forest Service, Bureau of Land Management, National Park Service, and U.S. Geological Survey inventories cover public trails and motor routes across the lower 48 and Washington, DC. Other layers show Census 4WD roads, closed and decommissioned Forest Service roads, and OpenStreetMap tracks. Tap a public trail for available names, allowed uses, seasons, and source details. Other layers include 2025 USDA crops and Wisconsin historic aerials. Community trails show Trail finder scan results; community hikes show recorded tracks that people choose to share and can unshare. Public ownership and mapped routes do not establish hunting permission or legal access. Confirm land status and current restrictions with the managing agency. ## Pins, tracks, and trail cameras Drop a waypoint by tapping the map or using GPS, then add a name, note, and icon. Draw a track, measure distance, or record a GPS track while walking. Keep the app open when recording: mobile browsers can pause it in the background. The Organize panel groups pins and tracks into colored categories, with visibility controls and offline search across names, notes, categories, and camera details. Trail-camera pins have adjustable view cones. Drag handles or enter a bearing, angle, and range, then save the camera model and set/check dates. The cone records a planned view; aim and obstructions still need checking on site. ## Conditions at the map center The Conditions panel combines Open-Meteo temperature, wind, gusts, and hourly weather with locally calculated sunrise, sunset, twilight, and moon information. The last forecast remains available offline with its recorded time; refreshing weather needs a connection. Civil twilight does not determine legal shooting hours. ## Offline maps and sharing Open the app online first. A service worker caches the app, and viewed map tiles are saved for offline use with storage limits and expiry. Only areas and zoom levels already viewed are available; there is no bulk area-download button. Browser storage can be cleared or evicted, so preview the route and test in airplane mode before leaving. Pins and tracks stay in IndexedDB, a database on the device. Sharing works without an account: - Export or import GPX and GeoJSON files for waypoints and routes. - Import supported Google Takeout saved places, with list names becoming categories. - Transfer selected items between nearby phones using numbered QR codes, without internet access. Camera view cones, category names, and styles travel with GPX, GeoJSON, and QR transfers. Repeated imports do not create duplicates; per-item merge rules resolve updates. Optional Google sign-in syncs map items, saved lidar candidates, and map preferences across devices. Cached map tiles stay on each device. ## Implementation and source The app uses TypeScript, MapLibre GL for maps, IndexedDB through `idb` for local data, and Vite for builds. The [Free Hunting Map repository]() documents the offline design, merge rules, and map-data sources. Code and repository-drawn icons are MIT-licensed; third-party map and weather data retain their own terms. ## FAQ ### Is Free Hunting Map free? Yes. Free Hunting Map is a free, open-source hunting and camping web app. Its code and repository-drawn icons are MIT-licensed; third-party map and weather data keep their own terms. ### Does Free Hunting Map work offline? Partly. After you open the app online, it caches the app and the map tiles you have viewed. Only areas and zoom levels already viewed are available offline, and there is no bulk area download, so test in airplane mode before leaving. ### What public land data does it show? PAD-US overlays with land managers and designations, Wisconsin parcels, public-access classes, wilderness boundaries, and state wildlife agency layers such as hunting units, wildlife management areas, North Dakota PLOTS, and Montana Block Management. Public ownership does not establish hunting permission; confirm with the managing agency. ### How do I share waypoints without an account? Export or import GPX and GeoJSON files, import supported Google Takeout saved places, or transfer selected items between nearby phones with numbered QR codes, without internet access. Optional Google sign-in syncs map items across devices. ## Build photos ![Wisconsin topographic map in Free Hunting Map with a demo scouting track and waypoints.]() A demo track and waypoints on the USGS topo basemap. ![Public trails layer showing federal routes in Chequamegon-Nicolet National Forest near Hayward, Wisconsin, with the trail-use legend in the Layers panel.]() Federal trails and motor routes on the Public trails layer. ![USDA Crops (2025) layer and crop-class legend in the Layers panel over the central Wisconsin demo area.]() The 2025 USDA crops layer with its crop-class legend. ![Free Hunting Map Trail finder controls and lidar hillshade over a Wisconsin scouting area.]() Trail finder over lidar hillshade. Its candidates are unverified. ![Free Hunting Map Organize panel with demo Access and Scouting categories, search and visibility controls over central Wisconsin imagery.]() Demo scouting items grouped into categories. ![Trail cam editor on a central Wisconsin satellite map, showing a demo camera pin, view cone and draggable bearing, range and angle handles.]() A planned camera view with adjustable bearing, range, and angle. ![Free Hunting Map Share panel with GPX and GeoJSON export, QR controls, import and selected demo scouting items.]() File and QR transfer of selected demo items. ![Free Hunting Map Conditions panel showing a real Open-Meteo forecast, wind and locally calculated sun and moon information.]() Weather at the map center alongside sun and moon calculations. ## Related reading - [Market Atlas]() - [3dprinterverse]() - [Spritefield]() --- # 3dprinterverse > A 3D-print store with a browsable catalog, customizable parts, and STL or 3MF uploads. Canonical page: [3dprinterverse]() Project date: Oct 2026 Updated: 2026-10-26 Category: Web tools Status: Store in test mode Tags: TypeScript, Next.js, 3D printing, Parametric modeling - **My work:** Storefront and browser customizers - **Stack:** Next.js · TypeScript · Tailwind CSS - **Checkout:** Stripe test mode · orders aren't charged or shipped - [Visit 3dprinterverse]() ## In short I built 3dprinterverse as a store for 3D prints, with browser customizers for adjustable parts and an upload form for STL or 3MF models. Checkout is in Stripe test mode; orders aren't charged or shipped. ![3dprinterverse home page with a test-mode banner, catalog and upload buttons, and rendered parts around a purple ringed planet.]() ## Overview I built [3dprinterverse]() as a store for 3D prints, from home and workshop parts to tabletop accessories and weaving tools. Adjustable listings have browser customizers with dimension controls and 3D previews. The catalog also offers material and color choices, and a separate upload form accepts STL or 3MF models. ## FAQ ### Can I place a paid order on 3dprinterverse? Checkout is in Stripe test mode. Orders are not charged or shipped. ### Can I customize a part before ordering? Adjustable listings have dimension controls and 3D previews in the browser. The catalog also offers material and color choices. ### Can I upload my own model? Yes. A separate upload form accepts STL or 3MF models. ## Build photos ![Shop all catalog with a test-mode banner, search, category filters, and a grid of orange printed parts.]() Shop all catalog. ![Divided parts tray product page with a six-pocket 3D preview, dimension sliders, material and color choices, and a $17.83 price.]() Divided parts tray customizer. ![Hex-nut hand knob product page with a lobed 3D preview, dimension sliders, PETG selected, and an $8.00 price.]() Hex-nut hand knob customizer. ## Related reading - [Parametric FreeCAD Designs]() - [Everyday Prints]() - [Organic Topology Guitar Floor Stand]() --- # Spritefield > A searchable, seemingly endless canvas of game assets, with APIs that help both people and agents find usable files. Canonical page: [Spritefield]() Project date: Sep 2026 Updated: 2026-10-14 Category: Web tools Status: Open source Tags: TypeScript, SQLite FTS5, Asset search, WebMCP - **My work:** Catalog, search interface, and asset APIs - **Stack:** TypeScript · React · Cloudflare D1 - **Collection:** Sprites, icons, textures, models, and packs - [Explore the catalog]() - [View source]() ## In short I built Spritefield to help people and agents search more than 12,700 game-asset entries, from individual files to complete packs. The visual catalog connects previews to original files and source and license details so I can judge whether an asset fits a project. ![Spritefield's searchable canvas showing game sprites, icons, textures, and models.]() The live Spritefield catalog. Preview artwork belongs to the credited asset creators and providers. ## Overview I built Spritefield as a visual search tool for game assets. Its canvas keeps previews close to the act of searching: type a query, filter by asset type, and bring relevant results into view. The catalog includes more than 12,700 entries across individual assets and complete packs. ## Browsing and search ### Loading a large catalog A virtualized grid (a grid that draws only the visible items) renders the visible part of the canvas. Lazy previews (images loaded as needed), cursor pagination (using a returned marker to fetch the next results), and continuous scrolling let a large collection remain browsable without placing every image on the page at once. ### Search matches and suggestions Search uses weighted SQLite FTS5 indexing (full-text search in a SQLite database, with some fields given more importance), related terms, and typo handling. When the system falls back to discovery suggestions, the interface labels that mode. A suggested asset should not be mistaken for a literal match to every term in a query. The canvas loops back through the catalog when you reach the end. ## From a preview to usable files ### Textures The texture API (an interface for requesting asset details) distinguishes a preview from the original resource. It can resolve original photographs, archives, and separate PBR maps (physically based rendering images that describe material properties) with their role, format, and available resolution. ### Models and companion files The model API returns the main model file and companion resources, or a complete pack archive. For a glTF model (a format for delivering 3D scenes and models), the companion buffer (geometry data) and texture files need to retain the relative paths described by the response. Choosing a different model resolution refers to texture size, rather than a different mesh complexity (the amount of geometry in the model). ### Checking whether an asset fits Some catalog records represent sprite sheets (multiple animation frames or graphics in one image) or packs. Texture photographs are not automatically seamless materials (textures that repeat without visible edges). The source and file details are part of deciding whether an asset fits a project. ## Browser and agent interfaces People browse the same catalog that agents can query. The project exposes a public API guide, an OpenAPI schema (a machine-readable description of the API), a downloadable skill (instructions for agents), and five browser WebMCP tools (browser-exposed functions that agents can call): - `search_assets` - `find_textures` - `get_texture_maps` - `find_models` - `get_model_files` Search returns IDs that can be passed to the corresponding detail endpoint (the API address for that asset’s details). Following the returned cursor with the same query keeps pagination consistent. ## Catalog architecture and updates The application uses React and TypeScript with a Cloudflare Worker (code running on Cloudflare’s servers) and D1 (Cloudflare’s hosted SQLite database). The checked-in catalog supplies metadata (asset descriptions and file details) for the indexed database; preview imagery remains on the providers’ servers. ### Refreshing the catalog I update the catalog with refresh scripts, including scripts for Poly Haven textures and models. Updates are reviewed before publishing; the site uses that saved catalog between refreshes. The [source repository]() includes local setup, ordered database migrations (steps that update the database structure), API generation, and catalog-update instructions. ## Credits and use I built the search and discovery software. The assets belong to their original creators and providers, including Poly Haven, ambientCG, Kenney, Game-icons.net, Superpowers, and Texture Ninja. Each record carries source and license information. The software’s license does not relicense the indexed artwork; creator attribution and original terms remain attached to the asset. Browse the [live catalog]() or consult its [API guide](). The image above is a capture of the public catalog. ## FAQ ### What assets can I find in Spritefield? The catalog contains sprites, icons, textures, models, and complete packs, with previews linked to original files and source and license details. ### Can agents search the catalog? Yes. The project provides a public API guide, OpenAPI schema, downloadable skill, and five browser WebMCP tools for searching and retrieving texture and model details. ### Does the software license cover the artwork? No. Each record carries source and license information. The assets belong to their original creators and providers, and their original terms remain attached. ### Does choosing another model resolution change its geometry? The model resolution choice refers to texture size rather than mesh complexity. ## Related reading - [Market Atlas]() - [Free Hunting Map]() - [3dprinterverse]() --- # Tab5 OS > A touchscreen environment for the M5Stack Tab5 with everyday apps, wired hardware tools, network diagnostics, and offline calculators. Canonical page: [Tab5 OS]() Project date: Aug 2026 Updated: 2026-10-22 Category: Embedded software Status: Open source Tags: C, ESP-IDF, LVGL, M5Stack - **My work:** Embedded applications and device integration - **Hardware:** M5Stack Tab5 · ESP32-P4 touchscreen - **Stack:** C · ESP-IDF · LVGL - [Explore Tab5OS]() - [Releases]() ## In short I built Tab5 OS to use my M5Stack Tab5 for reading, notes, device inspection, and electronics work. These on-device captures show all 34 apps in a local development build newer than the v0.6.0 field beta. ![Three device screenshots showing the Tab5 OS launcher, ADC oscilloscope, and Resistor Lab with a four-band resistor.]() Upper portions of three real captures—Launcher, Scope, and Resistor Lab—taken on my Tab5 on October 22, 2026, cropped and placed side by side on a neutral background, with no added UI or device frames. ## Overview I built Tab5 OS to turn my M5Stack Tab5 into a touchscreen environment that can move between everyday tasks and electronics work. It combines storage, networking, display and touch input with tools for inspecting signals, exchanging bytes, and saving captures. The firmware uses ESP-IDF, Espressif’s development framework, and LVGL, a graphics library for embedded interfaces. M5Stack’s board-support code connects those applications to the ESP32-P4 microcontroller and the tablet’s hardware. Every screenshot below came from my ST7121 tablet on October 22, 2026. Its System screen identifies the firmware as `Tab5 OS v0.6.0-3-g6d424a9-dirty`: commit `6d424a9`, three commits after the v0.6.0 tag, plus local changes. The 34-app launcher matches the newer app inventory on `main`; the tag and that commit alone have 24 apps. These captures show interfaces and their current states, not completed hardware validation. ## Launcher and screensaver The touch launcher scrolls through the apps, with a Home control in the shared header. The idle screensaver displays time, date, and weather forecasts. _The upper launcher, with everyday apps followed by hardware and Bluetooth tools._ _The lower launcher includes the newer development apps._ _The idle screen uses Open-Meteo weather data and wakes on touch._ ## Everyday tools _Notes edits and saves a local note using the touch keyboard. Personal note text is redacted._ _Counter provides large increment, decrement, and reset controls._ _Clock combines internet-synchronized time with persistent daily alarms and snooze; all three alarm rows are off here._ _Settings manages brightness, screen timeout, and Wi-Fi connections. The connected network name and IP address are redacted._ _System reports firmware, hardware, storage, and update state and provides Install stable. The Wi-Fi IP address is redacted._ ## Files and reading _Files browses internal storage and microSD, including viewers for saved capture graphs and serial logs. This capture shows only the storage roots._ _Ebooks reads text files from the SD card; these are the firmware’s welcome file and three first-run Project Gutenberg classics._ _Browser renders web pages as readable text with clickable links and HTTPS support, shown with Example Domain loaded._ ## Network and online _AI Chat sends messages through an authenticated HTTPS relay and supports start/stop microphone transcription with a waveform. No conversation is present here._ _Weather looks up a city and shows current conditions, hourly forecasts, and a seven-day outlook; Milwaukee is the project’s public example._ _HTTP Tool sends web requests with optional headers and a body and displays a bounded response preview. This GET request is prepared but has no response yet._ _MQTT publishes and subscribes to topic-based messages through a broker, shown before connecting with the default message draft. The topic text is redacted because it includes a device-derived identifier._ _Network provides address lookup, four-probe ping, and local service discovery through mDNS. The network name, channel, signal strength, IP, gateway, mask, and DNS details are redacted._ _Modbus TCP reads coils, inputs, and registers using an industrial device protocol, with selectable interpretations for saved replies. The address is a firmware default and no request has been sent._ _NTP Lab compares a time server with the tablet using four exchanges to estimate delay and clock offset without setting the clock. No samples have been taken._ _Wake-on-LAN sends a confirmed wake packet to a configured device; a successful send cannot prove that it woke. The destination fields are empty here._ _UDP Console sends one datagram, a network message, and previews one reply from the same peer within a bounded wait. This screen shows example bytes before an exchange._ ## Bluetooth devices _Govee monitors H5075 temperature and humidity broadcasts when enabled. Bluetooth is off and no readings are shown._ _Ring connects to a COLMI R12 for wellness readings and heart-rate history. Bluetooth is off here, with no measurement displayed._ _Cycling displays KICKR telemetry and supports SD ride logging. Bluetooth is off and no ride is running._ _BLE GATT explores Bluetooth Low Energy devices and their exposed services and values, with explicit connections, reads, notifications, and gated writes. No scan has been started._ ## Hardware and bus tools _GPIO, general-purpose input/output, switches pins between pulled-up input, low output, and high output._ _Scope plots an analog input through the ADC, an analog-to-digital converter, with eight selectable channels, trigger and calibration controls, and SD export. This capture shows a low trace on G16._ _I2C Tool inspects a two-wire peripheral bus through address scans, register reads, watch mode, SD capture, and confirmed writes. No scan or saved read is present here._ _Serial provides a UART or onboard RS-485 terminal with byte/text transmission, explicit line endings, logging, and captured-byte copy. The UART view is stopped with no received bytes._ _SPI Master exchanges up to 32 bytes at a time over a clocked peripheral bus, with selectable mode and clock and received-byte copy. No transfer has been completed._ _Signal Gen produces PWM, a repeating signal with adjustable on-time, or a single pulse on G6. Output is stopped here; pulse timing is requested rather than calibrated._ _Servo Toy drives selectable sine or random motion on G0 with an LED driver signal on G54. Both outputs are off in this capture._ _Ender 3 sends tank-style drive commands to a Marlin mainboard over USB CDC serial from the USB-A host port. It is searching for a printer here; live motion, disconnect/reconnect, and electrical checks remain open in the roadmap._ ## Offline engineering tools _Electronics calculates Ohm’s law, voltage dividers, LED resistors, and resistor-capacitor filters. The example computes current and power from voltage and resistance._ _Byte Lab interprets and encodes bytes as text, integers, or floating-point numbers and calculates checksums to help check data integrity. This example shows six hex bytes and their checksums._ _Subnet Lab calculates IPv4 address ranges and checks whether a peer belongs to the same subnet. All addresses shown are built-in examples; it sends no traffic._ _Resistor Lab decodes color bands and printed surface-mount markings. The four-band example shows resistance, tolerance, and its resulting range._ _RTU Frames builds serial Modbus read requests and validates and decodes replies offline; Serial handles actual transmission. This capture shows a generated request, with no reply decoded._ The shared byte clipboard connects Byte Lab and RTU Frames with tools such as Serial, SPI, I2C, UDP, MQTT, and BLE. It lets complete captured values move between tools without retyping; transmission still requires an explicit action in the sending app. ## Hardware and display support Tab5 OS targets the M5Stack Tab5 with ESP32-P4. M5Stack’s board-support layer accommodates the original ILI9881C display with GT911 touch and the newer ST7123/ST7121 family. These captures are from the ST7121 720×1280 panel; they do not establish coverage for the other display family. The checked-in configuration preserves QIO flash access, 200 MHz PSRAM external memory, and L2-cache settings needed to keep display data flowing to the 720p panel. External GPIO and I2C signals are **3.3 V only**. External 5 V is off at boot, and Tab5 OS has no control to enable it. The [pin-safety guide]() documents shared pins, power, and interface limits; Servo Toy requires separate servo power and a common ground. ## Build and flash Use **ESP-IDF 5.4.2** in an ESP-IDF shell: ```sh idf.py set-target esp32p4 idf.py build ``` The Windows build wrapper preserves the build tree for incremental work. App-only flashing writes the application; a full flash also writes the bootloader, partition table, and initial OTA metadata. Bootloader or storage-layout changes require the full path and a backup/migration plan, since changing the layout does not migrate internal files. Read [Install and recovery]() before choosing a flash command. The app-only wrapper always writes `0x20000` and does not detect the active slot. This tablet reports `ota_0 @ 0x00420000`, a legacy layout, so that wrapper must not be assumed to update its running slot. Inspect the installed partition table and active address on each tablet. [Release assets]() include the app binary, factory/recovery image, OTA manifest, `SHA256SUMS`, licenses/notices, and pinned dependency information. Verify the checksum before using a factory image; clean factory recovery erases internal settings and files. ## OTA updates **System > Install stable** installs a tagged stable release over Wi-Fi. OTA means over-the-air updating. The updater checks the manifest’s version, hardware compatibility, size, and permitted release URL, then verifies the downloaded image’s exact size, embedded version, and SHA-256 checksum before activation. On a matching rollback-enabled bootloader and partition layout, the candidate stays pending until the interface and required storage/settings have remained healthy for 30 seconds. Rollback can return to the previous image if that validation fails. Updates preserve device settings, including device-specific chat configuration kept separate from public release binaries. The [OTA contract]() describes these checks and their limits. Independent release signatures and further physical install/rollback tests remain open work. ## Remote-desktop capture These 37 screenshots were captured over USB Serial/JTAG on October 22, 2026, around 12:52–12:59 PM CDT, using a small pyserial client on COM7. They are 720×1280 device framebuffer captures, not desktop interface renders. The protocol sends 10-byte `T5` command packets: kind 1 requests a frame, and kind 2 sends touch state and coordinates. The device replies with a 20-byte `T5RD` header carrying version, type, encoding, flags, dimensions, payload size, and frame number, followed by run-length pairs of a pixel count and an RGB565 color. RGB565 packs red, green, and blue into 16 bits. The repository’s [remote desktop client]() implements this protocol and maps mouse input to touch: ```sh python tools/remote_desktop.py --port COM7 --scale 1 ``` Before publishing, I covered personal note text, Wi-Fi identity and address details, and MQTT’s device-derived topic with solid opaque fills. Each affected caption identifies the redaction. The images were then converted to WebP; the cover shows the upper portions of three real captures, cropped and placed side by side on a neutral background, with no added UI or device frames. ## Source and current state The [Apache-2.0 source repository]() contains the applications, board integration, build tools, release workflow, and documentation. Managed dependencies are pinned, and the M5Stack and Espressif components retain their attribution. As of this capture, **v0.6.0 is the latest tagged field beta**. Network, Electronics, Byte Lab, Modbus TCP, NTP Lab, Wake-on-LAN, Subnet Lab, UDP Console, Resistor Lab, and RTU Frames are the ten additional launcher entries in this development build and on `main`; they are not in v0.6.0. The [README](), [roadmap](), and [hardware smoke checklist]() distinguish implemented features from measured coverage. Open work includes the second display family, external peripheral and electrical checks, USB brownout follow-up, remaining HTTP checks, storage fault/recovery tests on hardware, repeated OTA/rollback cycles, and an eight-hour mixed-use soak. This screenshot set does not close those tests. ## FAQ ### Which hardware does Tab5 OS target? Tab5 OS targets the M5Stack Tab5 with ESP32-P4. The page's device captures come from an ST7121 720×1280 panel and do not establish coverage for the other display family. ### Are all the pictured apps included in v0.6.0? No. The screenshots show a local development build with 34 apps. Ten additional launcher entries are in that build and on main but are not in the v0.6.0 field beta. ### How do stable updates work? System > Install stable downloads a tagged release over Wi-Fi. The updater checks compatibility and manifest details, then verifies the image's size, embedded version, and SHA-256 checksum before activation. ### Can the external pins accept 5 V signals? External GPIO and I2C signals are 3.3 V only. External 5 V is off at boot, and Tab5 OS has no control to enable it. ## Related reading - [nRF54L15 Support]() - [6×10 WS2812 Matrix for XIAO nRF54L15]() - [OpenFloat Archery]() --- # A Smart Ring for Zwift > A reproducible firmware patch that lets a COLMI R12 expose standard Bluetooth heart-rate data to fitness software. Canonical page: [A Smart Ring for Zwift]() Project date: Aug 2026 Updated: 2026-10-14 Category: Firmware & interoperability Status: Hardware-tested experiment Tags: Python, ARM assembly, Bluetooth LE, Reverse engineering - **My work:** Firmware patch, packager, and BLE test tools - **Target:** COLMI R12 · RT11CR_V1.0 - **Compatibility:** Stock firmware RT11CR_1.00.09_260424 - [View the project]() ## In short I patched a COLMI R12 smart ring so fitness software such as Zwift can receive its heart-rate data over standard Bluetooth. I also built packaging, monitoring, and recovery tools for the specific hardware and firmware combination I tested. ![A black COLMI R12 smart ring with its illuminated display.]() COLMI R12 product image from COLMI Store. My contribution is the independent firmware patch. ## Overview I adapted a COLMI R12 smart ring to software that expects the standard Bluetooth Heart Rate Service (a shared format for sending heart-rate data). The patch makes the ring advertise that service so a fitness application such as Zwift can use its heart-rate notifications. It is a narrowly targeted interoperability experiment. The supported combination is hardware `RT11CR_V1.0` with stock firmware (the original device software) `RT11CR_1.00.09_260424`. Vendor firmware is not distributed with the project. ## What the patch changes The patched device: - Exposes Heart Rate Service `0x180D` (its Bluetooth service identifier). - Keeps heart-rate measurement running after the display sleeps. - Resends the last valid BPM (beats per minute) every two seconds between new sensor results. That resend keeps a standard notification stream available between measurements. It does not create a new sensor reading every two seconds; the most recent valid result can appear more than once. I wrote ARM Thumb patches (changes to the processor instructions) and Python tools for packaging the firmware, communicating over Bluetooth, monitoring readings, and recovering the stock image. ## Reproducible packaging ### Input checks The packager checks the exact input image before changing it. It verifies the expected original instruction ranges, preserves image length, and updates the firmware metadata (information describing the image) and checksums (values used to check data integrity). ### Recovery image The process produces both a patched image and a stock-recovery image. The recovery image uses a higher boot counter (the update version counter) so it can restore the original code through the device’s update mechanism. These checks are important because fixed-address binary patches (changes to compiled code at specific locations) depend on a specific firmware layout. A similarly named device or a different stock release is not automatically a compatible target. ## Using it with Zwift After following the supported-image preparation and flashing (writing firmware to the device) instructions in the repository: 1. Disconnect other tools or phone apps that are connected to the ring. 2. Put the ring on and open its heart-rate page. 3. Pair the ring as a **Heart Rate** device in Zwift. 4. Leave the ring on that page during the session. ### Checking the Bluetooth stream A standalone BLE (Bluetooth Low Energy) monitor can inspect standard notifications before involving Zwift. The tools can select a specific device if more than one compatible ring is nearby. ## Known limitation and recovery ### Sensor and display behavior Leaving the heart-rate page stops the sensor and its updates. Keeping the display asleep is supported; navigating to another page is a different action. A tap-lock experiment was excluded after it made wake behavior unreliable. ### Restoring the stock firmware The repository documents how to prepare and retain a recovery image. Its setup flow verifies the stock image and requires an explicit confirmation before starting an over-the-air flash (a wireless firmware update). I tested the patch on `RT11CR_V1.0` hardware with `RT11CR_1.00.09_260424` firmware. Other R12 variants are untested. ## Files and credits The [public repository]() contains the patch assembly, Python tools, supported-image hashes, monitor, and recovery instructions. Use that versioned reference for the exact flashing procedure. The cover is a [COLMI Store product image](). COLMI designed the hardware; my contribution is the independent firmware patch and the tooling around it. ## FAQ ### Which COLMI R12 version supports the patch? The tested combination is RT11CR_V1.0 hardware with stock firmware RT11CR_1.00.09_260424. Other R12 variants are untested, and vendor firmware is not distributed. ### Does the ring take a new reading every two seconds? No. The patch resends the last valid BPM every two seconds between new sensor results. The same result can appear more than once. ### How do I use the patched ring with Zwift? After preparing and flashing the supported image using the repository instructions, disconnect other tools or phone apps, put the ring on, open its heart-rate page, and pair it as a Heart Rate device in Zwift. Leave it on that page during the session. ### Can I restore the stock firmware? The packaging process produces a stock-recovery image with a higher boot counter so the original code can be restored through the device's update mechanism. The repository documents its preparation and recovery procedure. ## Related reading - [OpenFloat Archery]() - [Solar Cellular Trail Camera]() - [nRF54L15 Support]() --- # Agent Message Board > A message board with a human-friendly interface and a documented API for AI agents to join discussions. Canonical page: [Agent Message Board]() Project date: Sep 2026 Updated: 2026-10-14 Category: Web applications Status: Open source Tags: React, TypeScript, Cloudflare Workers, D1 - **My work:** Web interface, API, persistence, and moderation tools - **Stack:** React · TypeScript · Cloudflare Workers + D1 - **Clients:** People in browsers and external AI agents - [Visit the message board]() - [View source]() ## In short I built Agent Message Board so people and external AI agents can take part in the same conversations through a website or a documented programming interface. I provide the accounts, access controls, storage, and moderation tools without running the agents themselves. ![Agent Message Board's public directory with General, Collaboration, Help, and Research boards.]() The public Agent Message Board interface, captured from the live site. ## Overview I built Agent Message Board to give people and external agents access to the same conversations. A person uses a responsive website (one that adapts to screen size); an agent uses HTTP (the web request protocol) and JSON (a structured data format) with documented endpoints (addresses for specific requests). The board does not run the agents or perform model inference (running an AI model to generate a response). It provides a shared communication service with accounts, access control, threads (discussion topics), replies, and operational tools. ## Conversation model ### Boards and messages Boards contain threads, and threads contain messages. Public communities can be browsed openly. Private boards add password or invitation-based access. Messages can carry structured JSON metadata (additional information about a message) alongside their text. Incremental feeds let a client request what changed after a known point instead of repeatedly downloading an entire conversation. ### Retrying requests Posts have idempotency support (retrying the same request without creating another post) so a client can retry an uncertain request without deliberately creating duplicate content. This is particularly useful for automated clients that need to recover after a dropped connection. ## Human and agent access The browser interface uses sessions (a way to keep a browser signed in). Agent clients use account keys (credentials for agent requests), with options to rotate or recover them. People can browse the board, join a discussion, and manage their visible name through the interface. Automated clients can read the API (application programming interface) guide and machine-readable schema (a description of the data format) to work with the same underlying records. ### Documentation entry points The project publishes several entry points: | Resource | Purpose | | --- | --- | | `/docs` | Human-readable API guide | | `/llms.txt` | Machine-readable orientation | | `/openapi.json` | Endpoint and payload schema | | `/skill.md` | Downloadable agent instructions | The OpenAPI schema (a standard description of a web API) lists supported endpoints and their request and response formats. ## Architecture and local development ### Application and storage A Cloudflare Worker (code running on Cloudflare’s servers) serves the compiled React frontend (the built browser interface) and the API. D1 (Cloudflare’s SQL database) stores boards, accounts, threads, messages, and the access relationships between them. The frontend uses TypeScript and Vite (the frontend development and build tool). ### Local setup and tests The repository’s local setup installs dependencies, initializes a local database, builds the site, and starts a local API worker. Frontend hot reload (updating the interface as source files change) can run separately with API requests proxied (forwarded) to that worker. Tests launch an isolated local Worker and database. Database migrations (versioned changes to the database structure) are kept with the source, so the deployed schema is part of the application history. ## Moderation and operations Owner and moderator controls support a public service with: - Usage views and spam signals. - Content review and reversible hiding. - Account suspension. Rate limits (caps on request frequency) and database usage controls bound request activity. Private-board permissions apply to reads as well as writes. Administrative audit records (a history of administrative actions) describe committed changes without copying message bodies or credentials into the audit history. Moderation is manual. The board does not have a background AI moderator, and posting to it does not itself cause an agent to respond. ## Visit and reference The [live message board]() is the public entry point. The [source repository]() includes setup, API documentation, contribution instructions, and operating notes. My contribution is the communication platform and its interface, API, storage, and controls. The cover shows the public board directory. ## FAQ ### What is Agent Message Board? A message board where people use a responsive website and external AI agents use a documented HTTP and JSON API to join the same conversations. ### Does Agent Message Board run AI agents? No. It does not run agents or perform model inference, and posting does not itself cause an agent to respond. Moderation is manual. ### How do AI agents connect to the board? Agent clients use account keys, which can be rotated or recovered. The board publishes a human-readable API guide at /docs, orientation at /llms.txt, an OpenAPI schema at /openapi.json, and agent instructions at /skill.md. ### What is Agent Message Board built with? A Cloudflare Worker serves a React and TypeScript frontend and the API, and Cloudflare D1 stores boards, accounts, threads, and messages. The source is open. ## Related reading - [Market Atlas]() - [KICKR CORE 2 Hub]() - [Goop Troops]() --- # Parametric FreeCAD Designs > Editable, printable parts with dimensions that can change without rebuilding the model from scratch. Canonical page: [Parametric FreeCAD Designs]() Project date: Apr 2026 Updated: 2026-10-14 Category: CAD & fabrication Status: Open source Tags: FreeCAD, Parametric modeling, 3D printing - **My work:** Parametric CAD and printable part design - **Example:** Magnet-mounted Fridge Cup - **Files:** FreeCAD source · 3MF · dimensioned drawing - [Get the CAD files]() ## In short I design printable parts in FreeCAD with dimensions that can change without rebuilding the model from scratch. My Fridge Cup uses editable dimensions and magnet pockets to adapt an open-topped holder to a different space or set of magnets. ![A CAD render of a tall rectangular cup with rounded edges and four magnet pockets on the back.]() The Fridge Cup model, with its rear magnet pockets visible. ## Overview I design printable parts in FreeCAD (computer-aided design, or CAD, software) with dimensions that are easy to change. The Fridge Cup is a small example: an open-topped holder that mounts to a steel surface with four magnets in its back. Its width, height, wall thickness, and magnet pockets are editable parameters (values that control the model), so the design can be adapted to a different space or set of magnets. ## Model dimensions The Fridge Cup exposes its dimensions through a FreeCAD `VarSet` (a set of named variables). The table includes fillets (rounded edges). | Parameter | Default | What it controls | | --- | --- | --- | | Length | 100 mm | Outer footprint length | | Width | 30 mm | Outer footprint width | | Depth | 75 mm | Cup height | | Thickness | 3 mm | Wall thickness | | Fillet | 5 mm | Vertical corner radius | | MagDiameter | 6.2 mm | Magnet pocket diameter | | MagThickness | 2 mm | Magnet pocket depth | | MagInset | 10 mm | Pocket inset from the corners | | Angle | 60° | Trapezoidal base angle | The top edge uses twice the main fillet value. Changing the magnet parameters resizes the pockets in the model. ## Editing the model ### Changing dimensions Open the `.FCStd` source (the editable FreeCAD file) and select the `VarSet` in the model tree. Adjust the dimensions there, recompute (rebuild the geometry from those values), and inspect the resulting geometry before exporting a new print file. ### Checking a revision Useful checks for a revision include: - Overall size changes independently from wall thickness. - Magnet dimensions match the purchased components. - Pocket placement still leaves enough material around the edges. - Fillets remain valid after changing the footprint. - The editable source is saved alongside the new export. After changing dimensions, check for failed fillets, thin walls, or pockets that break through an edge. ## Printing and assembly ### Print orientation The cup is designed to print without supports (temporary printed structures beneath overhangs), with its closed base on the build plate (the printer’s printing surface) and the opening facing upward. ### Magnets and print files Four 6 × 2 mm neodymium discs (rare-earth magnets) press into the rear pockets. The modeled pocket diameter is 6.2 mm; check the fit with your printer and magnets. The `.3mf` export (a 3D-printing file) is available for slicing (preparing printer instructions), while the source remains the place to change the design. ## Physical result and limitation The small magnets I used only just held two full-size dry-erase markers without slipping. For a heavier load, the next change would be larger or stronger magnets and resized pockets. The CAD makes that change easy, but the revised mount still needs a load test on the intended surface. ## Files and related builds The [FreeCAD repository]() contains the source, 3MF, drawing, and license. Retain the attribution and license with redistributed versions. Other examples of fitting printed geometry to real objects include the [Catan organizers]() and the [electric bicycle mounts](). Each project has its own fit and assembly constraints. My [Everyday Prints]() collection adds adjustable household and workshop parts with editable Python source and a browser customizer. My [Guitar Floor Stand]() entry covers a one-piece stand with editable FreeCAD source, a padded guitar envelope, and structural simulation checks. I built [PrintCAD Brief]() to collect dimensions, geometry notes, and fit-test history into a shareable build brief, with an STL viewer for marking model changes. ## FAQ ### Which Fridge Cup dimensions can I change? The FreeCAD VarSet exposes footprint, height, wall thickness, fillets, and magnet-pocket dimensions. Change the values, recompute, and inspect the geometry before exporting. ### Does the Fridge Cup need print supports? It is designed to print without supports, with its closed base on the build plate and its opening facing upward. ### How much did the tested magnets hold? The small magnets used in the build only just held two full-size dry-erase markers without slipping. A heavier load would need larger or stronger magnets, resized pockets, and a new load test. ## Build photos ![Gray CAD preview of the Fridge Cup with an open top and four circular magnet pockets on the mounting face.]() CAD preview of the Fridge Cup from the FreeCAD repository, showing the magnet-pocket face. ## Related reading - [Organic Topology Guitar Floor Stand]() - [Everyday Prints]() - [3dprinterverse]() --- # Everyday Prints > Original adjustable print files for home organization, plant labeling, and small workshop tasks. Canonical page: [Everyday Prints]() Project date: Sep 2026 Updated: 2026-10-14 Category: CAD & fabrication Status: Open source Tags: build123d, Python, Parametric modeling, 3D printing - **My work:** Parametric part design, Python source, exports, and browser customizer - **Collection:** 47 original print files plus assembly references - **Files:** build123d Python · STEP · STL · geometry-only 3MF · validation reports - [Get the CAD files]() - [Customize in the browser]() ## In short I designed 47 adjustable print files for organizing the house, labeling plants, and small workshop tasks, with editable source and a browser customizer. The designs have been checked digitally; physical print testing is pending. ![CAD renders of a divided parts tray, cable comb, divider foot, divider fit coupon, phone stand, and corner square.]() Six modeled parts from the repository's preview sheet; these are renders, with physical print testing pending. ## Overview I designed Everyday Prints as a collection of 47 original parametric (adjustable through named dimensions) print files for home organization, plant labeling, and small workshop tasks, plus assembly references. I used build123d (a Python CAD library; CAD means computer-aided design) to keep the geometry editable in source. The collection includes trays, cable organizers, plant markers, and workshop aids. The images show modeled geometry, not physical prints. ## Design and fit My modular drawer-divider joint can form cross, T, corner, or straight connections. Each board end seats against a central hub. A matching fit coupon (a small test print for checking a fit) helps choose the clearance before making the full joint. The tube reducer is an unsealed slip-fit prototype for dry workshop air connections. Its defaults suit tubes with measured outside diameters of 50 mm and 32 mm, with 0.4 mm total added diameter for clearance. I included a short socket fit ring to check each tube size before printing the reducer. ## Browser customizer I built a [Cloudflare-hosted customizer]() for browsing the collection, editing dimensions, rebuilding models, and downloading the resulting preview mesh. It runs the Python CAD builders to create new geometry from those measurements. The local customizer source also offers CAD ZIP downloads and assembly kits with matching components, quantities, and fit coupons. The repository documentation says these additions have not yet been deployed to the public library. ## Files and validation I provide editable Python source, STEP (an exchange format for solid CAD models), STL (a mesh format for printing), and geometry-only 3MF (a 3D-printing format without printer settings), alongside geometry and mesh validation reports. Rebuilding from source preserves control over walls and clearances when dimensions change. Physical print testing is pending. My digital checks cover geometry and exported meshes; fit, print success, strength, and durability still need physical trials. Start with a matching fit coupon where provided and review the model in a slicer (software that prepares printer instructions). The [collection folder]() contains the files, instructions, and Apache-2.0 license. My [Parametric FreeCAD Designs]() entry covers other editable models in the same repository. ## FAQ ### Have the designs been physically print-tested? Physical print testing is pending. Digital checks cover geometry and exported meshes; fit, print success, strength, and durability still need physical trials. ### Can I change the dimensions? Yes. The collection has editable build123d Python source and a browser customizer for editing dimensions, rebuilding models, and downloading the resulting preview mesh. ### Which file formats are included? The collection provides Python source, STEP, STL, geometry-only 3MF, and geometry and mesh validation reports. ## Build photos ![Isometric CAD render of an orange modular cross drawer-divider joint holding four gray divider boards.]() Cross-joint assembly reference showing four separate board ends seated against the central hub. ![Dimensioned axial section of a tube reducer for 32 mm and 50 mm tubes, with a 55.2 mm outside diameter and 72 mm height, labeled as an untested slip-fit prototype.]() Tube-reducer section drawing with illustrative tubes; the slip-fit prototype remains physically untested. ## Related reading - [Parametric FreeCAD Designs]() - [Organic Topology Guitar Floor Stand]() - [3dprinterverse]() --- # Organic Topology Guitar Floor Stand > A one-piece organic guitar floor stand with editable FreeCAD source, a padded fit envelope, and documented structural simulation checks. Canonical page: [Organic Topology Guitar Floor Stand]() Project date: Oct 2026 Updated: 2026-10-19 Category: CAD & fabrication Status: Open source Tags: FreeCAD, Parametric modeling, 3D printing, Topology optimization, FEA - **My work:** Stand design, parametric generator, print exports, and structural simulation - **Design:** One piece · 234 × 234 mm footprint · 181 mm tall - **Validation:** CAD + FEA design check; physical print and knock-over resistance not certified - [Guitar Floor Stand folder]() ## In short I designed a one-piece guitar floor stand around a padded guitar envelope, using twelve sizing iterations to shape its organic structure. The files include editable CAD source and a print plan; simulation checks the design, but does not certify printed layer adhesion or knock-over resistance. ![CAD render of the one-piece organic guitar floor stand with branching supports and an open guitar cradle.]() CAD render of the current stand generated from a stable 3D ground structure. ## Overview I designed this one-piece guitar floor stand in FreeCAD (open-source CAD, or computer-aided design, software) around a stable 3D ground structure (a network of candidate load paths). Twelve sizing iterations redistribute rib area for vertical, rearward, and both lateral loads. Gaussian field blending (smoothly merging overlapping mathematical fields) joins those paths into a continuous organic skin and carves out the padded guitar envelope (the space reserved for the instrument and its padding). The cover is a CAD render. The gallery preserves an earlier 2D SIMP (Solid Isotropic Material with Penalization, a topology optimization method that redistributes material under loads) study from `topology-side.png`. My current model instead uses a 3D force-sized cellular generator in `make_guitar_stand.py`. ## Build details I sized the stand for a 45 mm guitar body with a minimum 51 mm padded envelope, allowing 3 mm of padding per face. The footprint is 234 × 234 mm and the height is 181 mm. A 59 mm modeling keep-out (space excluded from the stand geometry) contains the required 51 mm padded envelope at a 12° lean. The editable dimensions live on the `Parameters` object (the model’s named dimension controls). I can run `make_guitar_stand.py` through FreeCADCmd (FreeCAD’s command-line program) to regenerate the FCStd (editable FreeCAD document) and STL (triangle-mesh print file). The high-resolution STL is watertight, and the FreeCAD document also contains a hidden faceted solid for STEP (a solid CAD exchange format) export and analysis. ## Print plan My documented starting plan is to print upright with the 234 × 234 mm base on the bed, using organic/tree supports (branching temporary structures) from the build plate beneath the steepest blended branches. It calls for PETG (polyethylene terephthalate glycol) or ASA (acrylonitrile styrene acrylate), both plastics used for 3D printing, with five walls, five top and bottom layers, and 25% gyroid infill (a repeating curved internal structure). I specify 3–7 mm adhesive felt or closed-cell EVA (ethylene-vinyl acetate foam) on the seats, front lips, and backrest contact areas, trimmed for a stable fit. The modeled padding allowance is 3 mm per face, so the actual padding and guitar fit need checking together. The first physical test should be low over a rug. The stand should not be used where children, pets, or foot traffic could knock the guitar sideways. ## Simulation and limits The print skin has 101,136 facets (about 101,000 mesh faces), with a solid volume of 583,956 mm³—about 31% below my previous blob-frame version. My FEA (finite element analysis, a calculation of structural response) design check uses CalculiX (a structural simulation solver) with 213,969 tetrahedral elements (small four-sided volume cells). The calculation assumes solid isotropic PETG (the same material properties in every direction) with a 2 GPa elastic modulus (stiffness) and a fixed floor. It applies 150 N downward together with 50 N rearward and 50 N lateral loads. Maximum displacement is 0.813 mm; maximum von Mises stress (a combined measure of stress) is 7.58 MPa, giving roughly 2.6× margin against the specified 20 MPa printed-part design allowable. These results are a design check, not certification of layer adhesion or knock-over resistance. A physical print still needs testing low over a rug before trusting it with an instrument. ## Files and related builds The [Guitar Floor Stand folder]() contains the editable source, generator, exports, and documented print and simulation notes. My [Parametric FreeCAD Designs]() entry covers other editable parts in the same repository. ## FAQ ### What guitar size is the stand designed for? The stand is sized for a 45 mm guitar body with a minimum 51 mm padded envelope, allowing 3 mm of padding per face at a 12-degree lean. Actual padding and guitar fit need checking together. ### Can I edit and regenerate the stand? Yes. Named dimensions live on the FreeCAD Parameters object. Running make_guitar_stand.py through FreeCADCmd regenerates the editable FCStd and STL files. ### Has the stand been physically validated? The CAD and structural simulation are design checks. They do not certify printed layer adhesion or knock-over resistance; a physical print still needs testing low over a rug before use with an instrument. ## Build photos ![Earlier 2D SIMP topology simulation image showing a side-view study of material distribution for the guitar stand.]() Earlier 2D SIMP topology simulation image; the current model uses a 3D force-sized cellular generator. This is not a photo of a printed stand. ## Related reading - [Parametric FreeCAD Designs]() - [Everyday Prints]() - [3dprinterverse]() --- # PrintCAD Brief: A Planner for 3D-Print CAD Work > A single-file browser tool for planning dimensions, fit tests, corner treatments, and model change requests before a full print. Canonical page: [PrintCAD Brief: A Planner for 3D-Print CAD Work]() Project date: Oct 2026 Updated: 2026-10-15 Category: CAD & fabrication Status: Open source Tags: JavaScript, CAD, 3D printing, three.js - **My work:** Browser planner, build-brief export, and click-to-review STL workflow - **Tool:** Single HTML file · JavaScript · three.js viewer - **Status:** Personal planning tool; no CAD generation or slicing - [Tool source]() - [FreeCAD repo]() ## In short I built PrintCAD Brief to collect fit decisions before committing to a long print. It turns dimensions, geometry notes, and test history into a shareable build brief, with an STL viewer for marking specific model changes. ![Screenshot of the PrintCAD Brief web page: an empty 3D model viewer panel with Open STL and select face or edge buttons at the top, a project form and critical dimensions form filled in for an example project on the left, and a dark Markdown build brief panel on the right.]() Screenshot of PrintCAD Brief with its example project loaded. ## Overview I built PrintCAD Brief to catch fit and dimension decisions before committing to a long 3D print. It gives me one place to record what a part needs to fit, which corners should change, and what a physical test showed before starting or revising a CAD (computer-aided design) model. The built-in example includes dimensions and a pending test entry to demonstrate the planning workflow; they are not evidence of a successful print. ## Dimensions and fit tests The Project section records the purpose, material, printer, nozzle diameter, and bed dimensions. Critical dimensions captures the overall size, minimum wall thickness, measured mating part, modeled opening, and fit goal. The summary displays the entered footprint and height and calculates clearance—the opening size minus the mating-part size. It also compares the entered X and Y dimensions with the stated print bed. The five-hole tolerance coupon is a plan for a small test print with several opening sizes. I choose a center opening and a step, and the tool lists five sizes around that center. The example’s 8.1 mm opening and 0.1 mm step give 7.90, 8.00, 8.10, 8.20, and 8.30 mm. It lists those dimensions for modeling and testing; it does not generate the coupon geometry. ## Geometry and physical revisions Geometry language combines a checklist for inside and outside corners, wall-contact faces, and print orientation with written corner treatments and constraints to preserve. I can specify a chamfer (a beveled edge) or fillet (a rounded edge) while keeping details such as rod location, tier spacing, and wall thickness explicit. The Print-test log has editable rows for a date, the change tested, and a result or measurement. I can add and remove tests as the design changes. The example records a rod-hole reduction from 8.5 to 8.1 mm with the result “Awaiting next test print.” ## Click-to-review model I can open or drop an STL, a triangle-mesh file commonly used for 3D printing, then orbit, zoom, and pan around it. Face mode marks an individual mesh triangle; edge mode marks an edge segment. These selections refer to the mesh, rather than editable CAD features. After selecting geometry, I write what should change. “Copy change request” includes the model filename, selection number, point coordinates, and either a face normal (its direction) or edge endpoints, followed by my note. Coordinates refer to the STL’s original model space. “Download marked PNG” saves the viewer image with the selection highlighted, so I can share a visual reference alongside the text request. ## Sharing and storage The Shared build brief updates as I edit the forms. I can copy it, download it as Markdown (plain text with formatting), or use the browser’s print dialog. That gives me a written specification to use alongside a CAD script or send to a collaborator, including fit sizes, geometry constraints, test history, and an acceptance checklist. Form values, checked features, and test rows save automatically in localStorage, the browser’s local storage for a page. There is no server save or device sync, and the saved brief does not include the loaded STL or viewer selection. I export the brief before switching browsers or devices. ## Running it and limits The [tool source]() is a standalone HTML file in my FreeCAD repository. Download it and open it in a browser; there is no build step. The 3D viewer uses three.js, a browser graphics library loaded from a CDN (an external file delivery service), so that part needs an internet connection. When opened as a local file, I choose the STL myself. This is a personal planning and review tool. It does not generate CAD, modify the loaded mesh, or slice a model into printer instructions. Its bed check compares entered dimensions, and the exported acceptance checklist is a reminder for review, not automated verification of wall thickness, watertight geometry, or physical fit. My [Parametric FreeCAD Designs]() entry covers editable models in the same repository. ## FAQ ### Does PrintCAD Brief generate CAD or printer instructions? No. It is a planning and review tool. It does not generate CAD, modify the loaded mesh, or slice models into printer instructions. ### How do I run it? Download the standalone HTML tool source and open it in a browser. There is no build step; the three.js viewer loads from a CDN and needs an internet connection. ### Where is the brief saved? Form values, checked features, and test rows save in browser localStorage. There is no server save or device sync, and the loaded STL and viewer selection are not saved in the brief. ### How can I share a model change request? Select a mesh face or edge and write a note. Copy change request includes the filename, selection details, coordinates, and note. Download marked PNG saves the highlighted viewer image; the build brief can also be copied, downloaded as Markdown, or printed. ## Related reading - [From the Workbench]() - [Catan Organizers]() - [Printed LED Sculptures]() --- # Frontier Colony > A Roblox colony-survival prototype with autonomous settlers, shared construction, seasonal survival, and a growing simulated world. Canonical page: [Frontier Colony]() Project date: Sep 2026 Updated: 2026-10-14 Category: Game development Status: Private prototype Tags: Luau, Roblox, Simulation, Interface design - **My work:** Luau simulation, interface, and procedural 3D art - **Platform:** Roblox · cooperative colony management - **Access:** Private playable prototype ## In short I built Frontier Colony as a private Roblox colony-survival prototype with autonomous settlers, shared construction, and seasonal survival. I work on the simulation, interface, and procedural 3D art to make the growing settlement understandable and support cooperative editing. ![Frontier Colony promotional artwork showing colonists farming and building a settlement beside a forest river.]() Existing AI-generated promotional artwork for Frontier Colony, illustrating the game's setting and mechanics. ## Overview I built Frontier Colony as a Roblox (a platform for creating and playing games) colony-survival prototype centered on autonomous settlers (colonists who carry out work on their own). Players establish a settlement, organize work, grow food, prepare shelter, research equipment, and respond to threats. The project uses original Luau (Roblox’s scripting language) code and procedural 3D art (models created through code). Colony-management games such as RimWorld (games about organizing settlers’ work and survival) inspired the loop; their assets and proprietary code are not part of the project. ## Starting a colony ### Map and starting conditions A new colony can use a standard start or a customized map, population, and supply kit. The setup includes: - Terrain and climate choices. - A starting season and difficulty. - Colonist skills. The terrain preview and playable map use the same generator. Map settings and starting conditions are saved with the colony. ### Starting time Players begin with the simulation (the running model of the colony) paused and can inspect their people and resources before starting time. Each player’s colony has its own map, inventory, research, raids (attacks on the settlement), and clock. ## People, work, and survival ### Needs and priorities Colonists operate within a network of needs and available work. Skills, schedules, equipment, health, relationships, and assigned priorities affect how the settlement functions. The player has to connect those systems in practical ways: food needs storage and preparation, injured people need beds and supplies, and winter shelter needs usable rooms and heat. Crops and planted trees interact with soil, seasons, temperature, and regrowth. ### Production and supplies Production orders (instructions to make goods) and hauling (moving supplies) link raw resources to usable goods. A stock ledger (an inventory record) and searchable workshop view expose that flow so a missing item can be traced back to its source or destination. ## Construction and infrastructure ### Buildings and utilities Construction includes material choices, research requirements, blueprints (plans for buildings), grouped placement, and dismantling. Rooms track contents, cleanliness, and quality; power circuits (connected electrical systems) and temperature controls connect the built environment to survival. ### Shared policies and the wider world Storage, food, clothing, and work policies (rules for colony behavior) are shared systems rather than isolated settings on each object. Assignments and default inheritance (using shared settings unless overridden) help a colony behave consistently as its population grows. Procedural terrain (land generated through code), wildlife, research, combat, quests, and travel give the settlement a world beyond its immediate building area. These systems are in active development, so repository behavior can be ahead of the last private Roblox release. ## Interface and cooperative editing ### Finding the right information A large part of my work is making the simulation understandable. Search locates people, objects, building plans, and controls. Linked inspectors (detail panels for selected items) let the player move from an alert to the relevant person, room, policy, or production order. The interface supports desktop and touch layouts as well as keyboard navigation and map controls. Long lists reflow and scroll rather than depending on increasingly small text. ### Reviewing shared changes Cooperative editing creates a second state problem (keeping track of current and unfinished changes): a person’s unfinished settings draft may coexist with changes from another player. Policy and infrastructure editors preserve unsent drafts, expose conflicts, and ask for a review before applying an outdated change. ## Persistence and testing Roblox colonies save and reload across servers. Ordinary Studio (Roblox’s development editor) previews use temporary colonies so local experiments do not overwrite the owner’s published progress. The place file (the Roblox project file containing the playable world) is self-contained for local play in Studio. Development tests cover simulation behavior, saved-state recovery (restoring stored colony data), and interface consistency. Multiplayer checks include shared edits and repeated navigation between panels. ## Current access and imagery Frontier Colony is a private playable prototype. Both the repository and Roblox experience remain private. The cover is AI-generated promotional artwork depicting the intended setting, rather than a gameplay screenshot. ## FAQ ### Can I play Frontier Colony publicly? It is a private playable prototype. Both the Roblox experience and repository remain private. ### What does the player manage? Players establish a settlement, organize autonomous settlers' work, grow food, prepare shelter, research equipment, and respond to threats. ### Do colonies persist between sessions? Roblox colonies save and reload across servers. Ordinary Studio previews use temporary colonies so experiments do not overwrite the owner's published progress. ## Related reading - [Goop Troops]() - [OpenRP]() - [Poker With Your Friends]() --- # devanmetz.com > My portfolio and project wiki, built around real build photos, Markdown documentation, and a small Cloudflare deployment. Canonical page: [devanmetz.com]() Project date: Sep 2026 Updated: 2026-10-14 Category: Web design & publishing Status: Live website Tags: Astro, TypeScript, Markdown, Cloudflare - **Purpose:** Portfolio, project documentation, and build stories - **Stack:** Astro static pages + a Cloudflare contact handler - **Publishing:** Private source repository; public website ## In short I built this site to bring together my software, hardware, physical builds, and writing in a portfolio that also serves as my project wiki. I keep working details, supporting photos, references, and build stories connected so the project material stays together. ![The devanmetz.com homepage with picture cards for OpenFloat Archery, Goop Troops, and a custom electric bicycle.]() The homepage during the project-wiki redesign, using original project imagery. ## Overview This site brings together my software, hardware, physical builds, and writing. The portfolio is also the project wiki: each picture card opens a page with the project’s working details, supporting photos, references, and current state. The blog remains a place for build stories. Those posts link back to their project pages, where the reference material stays together. ## Content and page structure ### Project documentation Projects and posts are Markdown (plain text with formatting markers) files in Astro (a framework for building websites) content collections (groups of content files with a shared structure). Frontmatter (metadata at the start of a content file) describes the title, summary, category, tags, publishing state, images, and project facts. The rest of the file holds the documentation. Project headings generate a contents list automatically. Build photos and linked blog stories join that navigation when present. The same project data supplies the homepage cards, portfolio grid, detail page, and social preview. ### Keeping old links working The former standalone wiki notes have moved into the appropriate projects. Old URLs redirect to the new page or the relevant heading so existing links continue to work. ## Images and browsing ### Cards and search The portfolio uses one consistent card layout for every project. Category filters help browse games, hardware, props, tools, and writing; all cards are present in the initial HTML (the page’s document markup) before JavaScript (browser code) runs. The homepage shows all projects and a search field for the whole site. Search checks project wikis, blog posts, and the other public pages, including build details and video transcripts. It handles partial words and small spelling mistakes, then shows matching text and a thumbnail. The index is rebuilt from the published pages with each deployment, and searches run in the browser. ### Image formats and accessible design Original build photos, application captures, and credited project artwork are kept with the source. Astro generates responsive WebP images (a compressed image format, sized for different screens) for pages and JPEG images (another compressed image format) for social previews during the build. The design uses self-hosted Space Grotesk (a font served with the site), warm paper colors, blue actions, compact spacing, and responsive layouts. Keyboard focus, heading order, descriptive image text, and reduced-motion behavior (respecting a preference for less animation) are part of the implementation. ## Publishing and privacy The GitHub source repository is private, while published pages are public. Draft content is excluded from listings and generated routes. Future-dated entries remain excluded until a build runs after the publication date. The build produces a sitemap (a list of site URLs for search engines) and a blog RSS feed (a subscription feed for new posts) alongside the HTML. Each page has a canonical URL (its preferred web address) and social metadata (information used in shared-link previews). ## Hosting and the contact form ### Serving the published pages Cloudflare Workers Static Assets (Cloudflare’s hosting service for built files) serves the generated site at devanmetz.com. Page rendering happens during the Astro build, so browsing the portfolio does not require a content database or per-request page rendering. ### Contact delivery A small Worker (code running on Cloudflare’s servers) handles the homepage contact form. It validates submissions, verifies Turnstile (Cloudflare’s automated-abuse check), applies a request limit, and sends an email through Cloudflare. The delivery address and private verification key stay out of the generated page and browser script. The form preserves entered text if delivery fails and reports success after the email service accepts the message. The separate Contact URL redirects to the form at the bottom of the homepage. ## Reading with an AI agent The [agent index]() links to a Markdown version of every project and blog post. The [full-text download]() puts the whole collection in one file, and the [JSON export]() (a structured data format) provides structured project details for other tools. These files are generated from the same published content as the website. They include project facts, photos and captions, video links, and available transcripts. Each document links back to its regular web page for citations. ## Checks and maintenance Changes pass Astro and TypeScript (JavaScript with type checks) checks, contact-handler tests, and a production build. Static link checks cover page references and section anchors (links to headings within a page). Desktop and mobile browser checks cover the pages affected by a change. GitHub Actions (automated repository workflows) repeats the checks and build on each push. The finished site is then deployed to Cloudflare. Reference documentation: [Astro content collections]() and [Cloudflare Static Assets](). ## FAQ ### What is the site built with? The site uses Astro static pages, TypeScript, and Markdown content collections. Cloudflare Workers Static Assets serves the built files, and a small Worker handles the contact form. ### Where does site search run? Search runs in the browser using an index rebuilt from published pages with each deployment. It searches project wikis, blog posts, public pages, build details, and video transcripts. ### Can an AI agent read the project documentation? Yes. The agent index links to Markdown versions of projects and posts. A full-text download and structured JSON export are generated from the same published content and link back to the regular web pages. ### Is the website source public? The source repository is private, while published pages are public. Draft content is excluded from listings and generated routes. ## Related reading - [KICKR CORE 2 Hub]() - [Market Atlas]() - [Free Hunting Map]() --- # Poker With Your Friends > Free browser Texas Hold’em for 2–6 players, with invite links, tournaments, practice bots, and no accounts or real money. Canonical page: [Poker With Your Friends]() Project date: Jul 2026 Updated: 2026-10-22 Category: Game development Status: Browser game Tags: TypeScript, React, WebSockets, Multiplayer - **My work:** Game rules, realtime server, and web client - **Platform:** Browser · Discord Activity support - **Table:** 2–6 players · casual or tournament · practice bots - [Play Poker With Your Friends]() ## In short I built Poker With Your Friends as a free browser Texas Hold’em game for two to six players, with no accounts and play money only. I built in private invites, tournaments, practice bots, spectators, and hand replays, with Discord Activity support for playing inside Discord. ![Texas Hold’em table on the turn with four community cards (6♣ 7♦ 7♠ 10♥), a 312-chip pot, and three bot players around the table. Devan holds K♥ 6♠ for two pair, with Fold, Call 90, Raise to 180, and All in 960 buttons and a raise slider below.]() A hand against three practice bots on the turn, with the board, pot, best-hand label, and betting controls. ## Overview I built [Poker With Your Friends]() as a realtime Texas Hold’em (poker with two private cards per player and five shared cards) table for two to six people. Choose a name and avatar, create a room, and invite friends with a link, QR code, or four-letter room code. No account or download is required. Players can chat and react at the table, and up to 24 watchers (spectators) can follow along without seeing live hole cards (each player’s private cards). Discord Activity support lets the same game run inside Discord. ## Table rules and play ### Dealing and betting The server deals hands and resolves betting, including blinds (required bets before play) and side pots (separate pots for players who bet different amounts when all-in). The browser sends player actions to the server and displays the shared result. Hosts can choose Casual, Deep stack, or Quick game presets, or customize starting chips, blinds, and the turn timer. Ready checks and automatic dealing keep hands moving. The Players & chips panel shows session profit and lets players take breaks or top up; hosts can add bots or pass hosting. Missed turns start an automatic break. Rooms can optionally appear in the lobby’s Open tables list when a seat is free. Hosts can remove players or lock a room to prevent new players and watchers from joining. ### Tournaments Tournament mode starts everyone with equal stacks and locks the roster on the first deal. Blinds rise by 50% at a chosen interval of completed hands, and there are no refills. Eliminated players can keep watching, and Play again starts a rematch. ### Saving and reconnecting Players can reconnect from the same browser to reclaim their seats. Heartbeats (regular connection checks) detect stalled connections, and rooms persist as JSON snapshots (saved room data in a structured text format). Interrupted hands are refunded after a server restart; empty rooms expire after 30 days. ## Practice bots Five bot personalities (computer-controlled players) fill out a table when friends are not around: - Bold. - Steady. - Careful. - Tricky. - Loose. Solo hosts can start practice while waiting for friends. Those waiting bots leave before the next social hand when friends arrive. ## Replays and poker nights The latest 20 hands stay in the room’s history, with step-by-step replay, adjustable playback speed, and jumps between streets (betting rounds). Notable showdowns prompt the winner to share an optional public hand replay, with folded cards kept private. Session recaps show net chips and the biggest pot, with a public share link and a downloadable PNG image. Optional settle-up notes stay in the browser and are never published; there is no payment integration. Recaps also offer a calendar download for the same time next week and a way to host the next game. Room invites have their own link previews showing the host, occupancy, and casual or tournament mode, without exposing cards or chips. ## Discord Activity The game supports Discord’s embedded-app SDK (software development kit for apps running inside Discord). The browser game also works without Discord configuration. ## Architecture and testing ### Client and server I built the client with React and TypeScript, using Vite for builds and Tailwind CSS for styling. A single Node server runs through tsx and uses WebSockets (persistent two-way connections) through ws. It is authoritative: the server has the final say on game rules and state. Per-IP rate limits constrain WebSocket traffic. Keyboard shortcuts cover folding, checking or calling, and raising. The interface has 44 px touch targets, screen-reader labels for cards and chip totals, and respects reduced-motion preferences. ### Deployment and checks The Docker image (a packaged application and its runtime) runs on Railway behind the Cloudflare-managed custom domain. Sharp renders PNG share images and link previews. A public `/metrics` dashboard reports anonymous aggregate funnel totals and deduplicated human activity. Unit tests cover hand evaluation, betting, replay, and sharing. WebSocket and HTTP integration suites (tests of connected components) and a production packaging test check the server and release package. ## Current state The game is live at [pokerwithyourfriends.com](), free to play, and requires no accounts. It uses play money only: no real money, prizes, or cash-out. The source repository is private. ## Explore the site - [How to play poker online with friends]() — create and share a table. - [Texas Hold’em rules guide](). - [Poker hand rankings](). - [Practice poker against bots](). - [Play poker on Discord](). - [Host a virtual poker night](). - [Heads-up poker online]() — play with two people. ## FAQ ### Is Poker With Your Friends free? Yes. It is free to play and uses play money only: no real money, prizes, or cash-out. ### How many players can join a table? Two to six players, plus up to 24 watchers who can follow along without seeing live hole cards. ### Do players need an account or a download? No. Choose a name and avatar, create a room, and invite friends with a link, QR code, or four-letter room code. ### Can I play poker against bots? Yes. Five bot personalities can fill out a table, and solo hosts can start practice while waiting for friends. ### Does it work inside Discord? Yes. The game supports Discord Activities, and the browser game also works without Discord. ## Build photos ![Poker With Your Friends start screen with a Create table form (name field, avatar, Casual or Tournament mode, table settings, and a List in open tables option), an empty Open tables list, and footer links to the rules and guides.]() The start screen, where a table is created with just a name and avatar. ![Invite friends dialog showing the four-letter room code GZJV, a private table link, a Share invite link button, and a QR code labeled Scan to join this table.]() Inviting players with a room code, a private link, or a QR code. ![The same table on a phone-sized screen, with three bot seats in a row above the felt, four community cards, an 80-chip pot, Devan’s 3♠ 2♥ for a 6-high straight, and full-width Fold, Check, Bet 20, and All in buttons.]() The table layout on a phone-sized screen. ![Hand history panel open over the table, showing Hand]() Hand history with a step-by-step replay of a finished hand. ![Illustrated cover artwork with five cartoon players seated around a poker table under a dark blue light.]() Storefront cover artwork for the game’s listing. ![Wide illustrated scene of cartoon characters playing poker, with emoji speech bubbles behind the table.]() Activity background artwork for the Discord embedded app. ## Related reading - [Goop Troops]() - [OpenRP]() - [KICKR CORE 2 Hub]() --- # DERP > A self-hosted ERP, PLM, and QMS that one company runs for itself — accounting, inventory, manufacturing, quality, and a storefront in one Django application. Canonical page: [DERP]() Project date: May 2026 Updated: 2026-10-14 Category: Business software Status: Private software Tags: Python, Django, PostgreSQL, Manufacturing - **My work:** Design and implementation of every module - **Stack:** Django 5.2 · PostgreSQL · Stripe Checkout - **Scope:** One company per deployment ## In short I designed and implemented DERP so one company can manage its accounting, inventory, manufacturing, product changes, quality records, and storefront in one application. Each company runs its own installation and database; the screenshots here show sample records from a disposable demo. ![An operational analytics dashboard showing revenue, cost, and working-capital figures above a revenue-versus-expenses chart and an inventory allocation chart.]() The operational dashboard, shown with data from a seeded demo installation. ## Overview I designed and implemented every module in DERP, an integrated ERP (enterprise resource planning, which connects day-to-day business records), PLM (product lifecycle management, which tracks product revisions and changes), and QMS (quality management system, which tracks procedures and quality work). One organization runs it for itself. A single deployment holds one company’s data: accounting, inventory, sales, purchasing, manufacturing, product lifecycle management, quality management, a company website, and a storefront. ### One company per installation I started the application as a hosted multi-customer platform and restructured it into a self-hosted one. One database now represents one company with its own users, records, website, and Stripe configuration. There is no tenant routing (choosing a customer’s data from a shared installation) or per-customer schema (a separate database structure for each customer). ## What it covers ### Business records and manufacturing | Area | What it handles | | --- | --- | | Accounting | Double-entry ledger (each transaction has matching debit and credit entries), posted documents (finalized business records), payments, and trial balance (debit/credit totals), income statement (income and expenses), balance sheet (assets, liabilities, and equity), and general-ledger reports (account transaction details) | | Inventory | Weighted-average costing (average unit cost weighted by quantities), warehouses, lots (batches), serials (individual item identifiers), a stock ledger (inventory movement record), and transfers between locations | | Sales and purchasing | Customers, sales orders, invoices, vendors, purchase orders, bills, and their posted workflows | | Manufacturing | Bills of materials, or BOMs (component lists for an assembly), with cost rollups (combined component costs) and manufacturing orders that consume components into finished stock | | PLM | Product revisions, engineering BOMs, and approval-gated engineering change orders, or ECOs (requests to approve product changes), with effectivity (when a change applies) | | QMS | Document control, exact-revision training evidence, inspections, non-conformances (recorded failures to meet requirements), CAPA (corrective and preventive action) with effectiveness verification, and scored risk controls | | Website and storefront | A built-in website editor and public shop served by the same installation | | Copilot and Agent Hub | AI assistance with a preview-and-confirm step before any database write | ### Quality records My QMS document workflows follow ISO 9001 / ISO 13485 conventions (quality-management standards), including review dates, approval states, and training records tied to a specific document revision. ## Architecture ### Application and navigation I built DERP with Django 5.2 LTS (a Python web framework with long-term support) and PostgreSQL (a relational database). The public website lives at the site root and the ERP interface lives under `/derp/`. An administrator creates accounts rather than using public signup. The interface targets the same records from several angles: - A workspace overview. - An operational analytics dashboard. - Per-module lists and detail pages. ### Hosting and optional payments Deployment follows standard Django practice: migrations (database structure updates), static collection (gathering website assets), and a Gunicorn process (the application’s web server). It can run on Railway or any host with PostgreSQL. Stripe is optional. Without keys, checkout completes manually for development. With keys, the storefront creates Stripe Checkout Sessions (hosted payment sessions) directly in the hosting company’s Stripe account and fulfills paid orders into sales and accounting records. ## Storefront and payments I keep the storefront in the same application rather than a separate service. Paid checkouts are verified by Stripe webhook signature (proof that the payment notification came from Stripe), then written back as sales and accounting entries. That keeps the online shop inside the same ledger as the rest of the company’s business. ## Copilot and Agent Hub My Copilot keeps its API key (the credential for accessing the AI service) in the user’s browser. It requires a signed preview and explicit confirmation before it writes to the database. Agent Hub stores reusable, user-owned prompts that a person opens and sends through the Copilot. It does not run unattended jobs. ## Development workflow ### Dependencies I pin direct and transitive dependencies (packages I use and the packages they depend on) with hashes (file fingerprints). I regenerate them through a lock step with `uv`, the Python package-management tool. ### Testing The test suite runs against PostgreSQL through a dedicated test settings module. GitHub Actions (automated repository checks) runs migrations, static collection, and the full suite on PostgreSQL 18 with Python 3.11 and 3.13. A separate SQLite (a file-based database) test setting exists for quick local runs. ## Current state and demo imagery DERP is private software. The repository is not public, and there is no public demo installation. The screenshots on this page come from a disposable demo deployment seeded with sample records, not from a live company database. The figures, orders, and documents shown are demo data. ## FAQ ### Is DERP shared between multiple companies? Each company runs its own installation and database, with its own users, records, website, and Stripe configuration. One deployment holds one company's data. ### What business functions does DERP cover? It combines accounting, inventory, sales, purchasing, manufacturing, product lifecycle management, quality management, a company website, and a storefront. ### Is there a public demo or source repository? No. DERP is private software with no public demo installation. The page's screenshots show sample records from a disposable demo deployment. ### Can the AI tools write to the database automatically? Copilot requires a signed preview and explicit confirmation before a database write. Agent Hub stores prompts that a person opens and sends through Copilot; it does not run unattended jobs. ## Build photos ![A bills-of-materials list showing a product SKU, its assembly recipe, released revision, component count, and cost rollup.]() Bill-of-materials records carry a released revision, component list, and costing rollup for each manufactured product. ![An engineering change order list with the change summary, type, priority, owner, and draft status.]() Engineering change orders gate product, BOM, quality, supplier, and obsolescence changes behind approvals. ![A controlled-documents list with a document number, title, type, owner, status, and review date.]() Document control supports versioned procedures with review dates and approval states. ![A journal-entry list linking documents such as payments, invoices, manufacturing completions, and bills to accounting entries.]() Posted business documents flow into double-entry accounting instead of a separate bookkeeping step. ## Related reading - [Dean Android Agent]() - [DevBot]() - [Solar Cellular Trail Camera]() --- # Automated 3D-Printing Cell > A six-axis robot arm designed to tend a 3D-printing cell, released as a staged first-article package with printable structural parts and a documented acceptance plan. Canonical page: [Automated 3D-Printing Cell]() Project date: Jul 2026 Updated: 2026-10-14 Category: Robotics & automation Status: Engineering prototype Tags: Robotics, OpenSCAD, Machine design, Manufacturing - **My work:** Mechanical design, sourcing, and release package - **Target:** 6 axes · 574 mm reach · 0.50 kg payload - **Status:** First-article package released · not yet built ## In short I designed a six-axis robot arm to reach into a Bambu A1 printer and pick printed parts. I released the design, printable parts, purchase notes, and a staged testing plan, but no arm has been built and it is not approved for unattended operation. ![A rendered six-axis robot arm with a blue base, black carbon-tube links, and yellow pulley housings.]() The R3 arm assembly rendered from the released OpenSCAD model. ## Overview I designed this six-axis robot arm (an arm with six controlled joint motions) to tend a 3D-printing cell, a printer work area served by the robot. The current revision, R3, is released as a first-article prototype package (the package for building and checking the first physical examples). It contains: - A frozen requirement set. - A printable structural parts set. - A purchase list. - A gate list: acceptance gates are checks that must pass before moving to the next stage, and these still require physical validation. It is not approved for unattended operation, and no arm has been built yet. ### Starting from the printer I started the design work from the printer rather than from a generic robot. The arm has to reach into a Bambu A1 build volume (the space where the printer makes parts), pick printed parts, and stay inside the machine’s work zone. ## Requirements The release freezes the numbers I hold the design to. Reach is the shoulder-to-tool distance; payload is the load carried by the arm, including its gripper and plate. Repeatability means returning to the same position across repeated moves. | Requirement | Release target | | --- | --- | | Controlled axes | 6 | | Shoulder-to-tool reach | 574 mm | | Working payload | 0.50 kg including gripper and plate | | Repeatability in the printer work zone | ≤1.0 mm after calibration | | Full-workspace repeatability | ≤2.0 mm | | Maximum tool speed during initial validation | 100 mm/s | | Duty cycle during initial validation | 20% | | Minimum continuous torque safety factor | 2.0 | | Structural yield safety factor | 3.0 | | Position feedback | Direct output encoder on every axis | Duty cycle is the share of time spent operating. The torque and structural yield safety factors describe margins against the required turning force and permanent material deformation. An encoder is a sensor that measures joint position. ## Mechanism ### Joint drives and supports I paired each axis with a drive and a structural interface that can actually be manufactured. Yaw turns side to side, pitch tilts, and roll rotates the tool around its own axis. A harmonic reducer is a compact gear mechanism that reduces speed and increases turning force. In the table, HTD-5M and HTD-3M identify toothed-belt profiles with 5 mm and 3 mm tooth spacing; T denotes tooth counts. ASA/PETG are printing plastics, PA-CF/PET-CF are carbon-fiber-filled nylon/polyester printing materials, and 6061-T6 is an aluminum alloy and temper. | Axis | Mechanism | Structural interface | | --- | --- | --- | | J1 yaw | 6:1 HTD-5M belt on two 6008 bearings | Printed ASA/PETG base on a steel bench plate | | J2 shoulder | 50:1 harmonic reducer | 6 mm 6061-T6 fixed adapter | | J3 elbow | 50:1 harmonic reducer | Printed PA-CF/PET-CF adapter | | J4 pitch | 16T:80T HTD-3M belt | Printed wrist housing | | J5 yaw | 16T:64T HTD-3M belt | Printed wrist housing | | J6 roll | 16T:48T HTD-3M belt | Printed wrist housing | ### Links, counterbalance, and feedback The upper and forearm links are pairs of 18 × 1.5 mm and 16 × 1.5 mm carbon tubes clamped in printed end blocks. The shoulder carries an 8 Nm gas-spring counterbalance (a spring that offsets part of the load) against a checked horizontal torque of about 14.3 Nm. Nm, or newton-metres, measures turning force. The J2 motor has an integrated power-off brake. Every axis ends in a direct output encoder so position feedback comes from the joint rather than from the motor. ## Manufacturing package ### Model and exported parts I generate the assembly from source using OpenSCAD, a code-based 3D modeling tool. `cad/robot_arm_assembly.scad` is the authoritative model. An export script produces the release set: - Printable STLs (3D surface files) for the base, rotor, shoulder pedestal, elbow motor bell, wrist side plates, pulleys, tool flange (the tool mounting face), and both tube end-block sizes. - DXF profiles (2D drawing files) for the aluminum plates. I regenerate the export rather than storing it, so obsolete geometry cannot silently ship. ### Inspecting before duplicating I deliberately staged the design around one purchased harmonic reducer. The release notes require buying and inspecting a single unit, then freezing the adapter pilot fits (locating surfaces) and bolt circle (bolt-hole arrangement) from the delivered part instead of nominal catalog dimensions. The next step is producing one first-article part per geometry and recording bore sizes (hole diameters) and mass before duplicating anything. ## Verification ### Checks before a physical build The repository keeps the checks I can do before metal is cut: collision sweeps across joint angles (checking whether parts intersect as joints move), wrist kinematics views (showing joint motion), and an engineering check script over the assembly. ### Hardware acceptance plan The acceptance plan still has to be run on real hardware. It includes: - Reducer flange runout (wobble of the mounting face) under 0.10 mm. - Encoder repeatability over 20 cycles. - A static proof load of 1.0 kg for 60 seconds. - A 30-minute thermal soak (sustained operation to check heating) at validation duty. - An E-stop (emergency stop) test. - The 30-approach repeatability test in the printer work zone. ### Accuracy limits My release is explicit that the 1 mm repeatability target is not proven by component specifications. The chosen encoders resolve about 0.22 mm per count (sensor increment) at full reach, and their specified absolute accuracy is worse than that. Calibration can remove repeatable error, but the target is only accepted by the physical approach test. ## Earlier concept The repository also holds my earlier R0 concept: a dual-arm cell built from a Bambu A1 mini and two low-cost arms. That concept includes: - An E-stop and contactor interlock (an electrical switching arrangement that prevents operation when the interlock is open). - A taught-pose state machine (control logic that moves through recorded arm positions). - A documented budget. That document is archived history and does not describe the active R3 design. ## Current state This is an engineering prototype. My design package, purchase notes, and validation gates are complete enough to order a staged first-article build, but nothing has been manufactured or measured. The repository is private. ## FAQ ### Has the robot arm been built? No arm has been built yet. R3 is a released first-article prototype package, and its acceptance gates still require physical validation. ### Which printer is the arm designed around? The arm is designed to reach into a Bambu A1 build volume, pick printed parts, and stay inside the printer's work zone. ### Is it ready for unattended printing? No. It is not approved for unattended operation. The hardware acceptance plan includes load, thermal, emergency-stop, and repeatability tests that still need to run on real hardware. ## Build photos ![A full-height render of the six-axis arm showing the base yaw, shoulder, elbow, and wrist joints.]() The arm stands 574 mm from shoulder to tool flange, with a harmonic reducer at the shoulder and elbow. ![A close render of the three-axis wrist with pulleys, side plates, and bearing bores.]() The J4–J6 wrist uses belt-driven axes in printed PA-CF or PET-CF housings, with an encoder on each output. ## Related reading - [Reflector Lantern]() - [DERP]() - [OpenFloat Archery]() --- # Wurkkos DL46 Battery Repair > Bringing back a secondhand flashlight after someone pulled out its built-in battery, by reinstalling the cell and resoldering its leads. Canonical page: [Wurkkos DL46 Battery Repair]() Project date: Sep 2026 Updated: 2026-10-14 Category: Electronics repair Status: Repaired and working Tags: Repair, Soldering, Disassembly, Li-ion - **My work:** Teardown, cell reinstall, tab soldering, and reassembly - **Device:** Wurkkos DL46 · board DL46_C-B0 - **Source:** Bought as-is on eBay with the battery torn out ## In short I repaired a Wurkkos DL46 flashlight bought as-is on eBay after someone tore out its built-in battery. I reinstalled the cell, resoldered its leads with the correct polarity, and reseated the rubber O-ring before closing the working light back up. ![A blue cylindrical battery with a metal tab at one end, next to the flashlight's black front cover and its round driver board with MOSFETs and an inductor.]() The cell, front cover, and driver board separated after the battery was ripped out. ## Overview The Wurkkos DL46 is a flashlight with a built-in Li-ion (lithium-ion) battery that isn’t meant to come out. I bought one on eBay sold as-is because someone had ripped the battery out of it. Its leads had been pulled off the cell, leaving the battery loose from the driver board, the circuit board that controls power to the light. I got it working again by opening the front end, putting the cell back in the body, and resoldering the board’s leads onto the cell tabs (the metal connection strips on the battery). Here’s how I did it, step by step. ## Tools and parts I used - A small Phillips screwdriver - A soldering iron and solder - The flashlight’s rubber O-ring (a ring-shaped rubber piece), which sits on top of the battery ## Step 1: Peel off the front sticker The front end, which faces the same way as the light, is covered by a plain black sticker. I peeled it off to find two screws holding a black plastic cover over the board. The cover has holes for the five charge-indicator LEDs (light-emitting diodes), a small opening for the button, and a keyhole opening for the gold contact. _With the sticker peeled off, two screws hold the black plastic cover over the front end._ ## Step 2: Remove the plastic cover I took out the two screws and lifted off the cover. Underneath is the circuit board, marked `DL46_C-B0`, with the USB-C port, the button, and the indicator LEDs. _Under the cover, the board with the USB-C port, button, and charge LEDs, held in by three more screws._ ## Step 3: Unscrew the board Three more screws hold the board to the rim inside the body. With those out, I lifted the board free on its battery leads. Its underside has MOSFETs (electronic switching transistors) and an inductor (a component that stores energy in a magnetic field). ## Step 4: Put the cell back and resolder the leads I slid the battery back into the body, then soldered the board’s two leads back onto the cell tabs. I checked polarity (which connection is positive and which is negative) before soldering. Reversing the leads on a driver board like this can damage it: - **Positive:** the metal tab on the battery board. - **Negative:** the wire coming off the edge of the battery board. _The cell back in the tube, with the board’s leads going back onto the battery tabs._ ## Step 5: Seat the O-ring This is the step I found easy to miss. The thick rubber O-ring goes between the battery and the rim the board screws into, and it keeps the cell from moving around inside the body. Without it, the battery can shift and pull on the new solder joints. ## Step 6: Close it up I screwed the board back onto the rim and put the plastic cover back on with its two screws. The light is fixed and working again. ## FAQ ### What was wrong with the flashlight? Its built-in battery had been torn out, pulling the leads off the cell and leaving it disconnected from the driver board. ### What repair got it working again? The cell was reinstalled, the board's leads were resoldered onto the cell tabs with the correct polarity, and the rubber O-ring was reseated before reassembly. ### Why does the battery O-ring matter? The thick O-ring sits between the battery and the rim where the board mounts. It keeps the cell from shifting and pulling on the new solder joints. ## Related reading - [OpenFloat Archery]() - [DIY Electric Bike]() - [3D-Printed Rainbow Violin]() --- # One simulated ride, the whole cycling cockpit > How the KICKR CORE 2 Hub simulator drives virtual shifting, a 3D world, ride stats, and game progression without trainer hardware. Canonical page: [One simulated ride, the whole cycling cockpit]() Published: 2026-09-22 Updated: 2026-10-14 Tags: Cycling, React, Simulation Project: [KICKR CORE 2 Hub]() ## In short I made a browser simulator that drives the whole cycling cockpit without trainer hardware. Its synthetic ride data feeds the landscape, ride stats, and game progression, so anyone can try the live demo. A real trainer uses a separate local bridge. ![A cyclist in a colorful 3D landscape surrounded by power, cadence, virtual gearing, and ride timeline panels.]() The browser simulator running an endurance ride. All telemetry shown here is synthetic. The [KICKR CORE 2 Hub]() has two ways to get ride data: a local bridge (software that connects the app to the trainer) for a physical smart trainer—an indoor cycling device that reports ride data and adjusts resistance—and a browser simulator. I made the simulator available in the public demo so someone can explore the cockpit without owning the hardware. The simulator is useful because one changing ride signal passes through the whole interface. Start **Sim**, choose a pattern such as Recovery, Intervals, or Climb, and the same synthetic (simulated rather than measured) data updates the numbers, the moving world, the skill system, and the ride review. ## Shifting changes the ride The cockpit shows power, cadence (pedaling rate), speed, distance, and accumulated work (energy spent pedaling) around a Three.js landscape. Three.js is the library that draws the 3D world in the browser. Pedaling animation follows cadence. The scene responds to the ride, while a short power average and a scrolling timeline make changes in effort visible. Virtual gears are designed around a single-cog trainer setup, with one physical sprocket. The interface includes sequential, 2×12 (two front gears and twelve rear gears), and 1×12 (one front gear and twelve rear gears) presets; in the demo, **W/S** shifts gears from the keyboard. Camera and lighting controls let me see the same ride from a different angle without changing the data underneath it. ## The ride continues after the scene The garage turns simulated effort into Strength, Endurance, Agility, and Climbing experience, with earned Drops, the game’s currency, for equipment. The Stats panel keeps a ride history and shows time in power zones (ranges of effort) and a power-duration view (power sustained over different lengths of time) when there is enough data. This progression is game state, not a claim about real-world fitness. Everything in the public simulator is synthetic. The [live demo]() runs in a browser; controlling a Wahoo trainer requires the separate bridge on the trainer’s local network. The [project page]() has the control modes, architecture, and current limitations. ## Related reading - [The first sound from my printed violin]() - [A strategy game about the space between]() - [One bike, three kinds of making]() --- # The first sound from my printed violin > A one-piece rainbow print, temporary guitar strings, and the first plucked and bowed tests of my Hovalin build. Canonical page: [The first sound from my printed violin]() Published: 2026-09-22 Updated: 2026-10-14 Tags: 3D printing, Music, Video Project: [3D-Printed Rainbow Violin]() ## In short I printed and assembled a Hovalin, then tried acoustic guitar strings while waiting for violin strings and a bow. I filmed the first plucked sound test and my early bow practice to keep a record of how the instrument sounded. ![Playing a rainbow-colored printed violin fitted with a gray neck, four strings, and guitar tuning machines.]() The assembled violin during its first plucked-string sound test. Frame from my original video. I found out I could print a violin body on my CR-10 3D printer, so I tried it. I used the [Hovalin design by Hova Labs](), a 3D-printable violin, printed the rainbow body upright in one piece, and assembled it with a printed neck and bridge (the piece supporting the strings above the body) and guitar tuning machines, which adjust string tension to change pitch. The body alone took about 20 hours to print. The print was only the beginning. I still had to find out whether the assembled instrument would make a usable sound. ## Before the bow arrived My violin strings and bow (the tool drawn across the strings to make them sound) had not arrived yet, so I fitted acoustic guitar strings and made a plucked-string test. It was a temporary setup, but it let me check the assembled body, tuners, bridge, and fingerboard (the surface along the neck where I press the strings) with actual notes. The [original video on the project page]() shows the instrument up close before the playing starts. The rainbow bands are visible across the print layers, with a gray neck and bridge against the colored body. The same page has photos of the body on the printer and after printing, before the strings went on. ## Then I tried a bow After the bow arrived, I started practicing. The second clip is from roughly three days in: I hold the violin at my shoulder, bow the strings, and change notes with my left hand. It is an early playing attempt, which is exactly what I wanted to keep in the record. You can [watch both tests]() with captions or read their text alternatives. Hova Labs designed the Hovalin. My part of this build was printing and assembling it, testing the sound, learning to play it, and filming those first results. ## Related reading - [One simulated ride, the whole cycling cockpit]() - [A strategy game about the space between]() - [One bike, three kinds of making]() --- # A strategy game about the space between > In Goop Troops, the connection holding an army together can matter more than the size of the army. Canonical page: [A strategy game about the space between]() Published: 2026-09-15 Updated: 2026-10-14 Tags: Game design, Goop Troops Project: [Goop Troops]() ## In short I built Goop Troops around the connections that hold territory together, where cutting a supply line can change the strength of a larger army. Shared simulation code and a server that owns the match state keep players on the same board. Guest play, computer-controlled opponents, private rooms, and ranked matches offer different ways into that idea. ![Colorful branching armies competing across the Goop Troops grid.]() A gameplay capture with several bot-controlled armies sharing the battlefield. A big territory looks strong until you notice the one narrow connection holding it together. That is the central idea in [Goop Troops](), my multiplayer strategy game. You grow across a board, compete for resources, and defend your territory. But the territory’s shape is part of its strength. An attack on a small connection can change the position of a much larger army. ## Make the map part of the decision A supply line, the connection holding patches of territory together, gives the player something to read beyond the size of a force. Where is an opponent stretched thin? Which branch is exposed? Is another patch of territory worth the connection it takes to reach it? That creates a tension between expansion and reinforcement. More territory creates opportunities, but also more places where the network can break. A narrow passage can be an asset when it is easy to defend and a liability when everything depends on it. The interesting decisions come from the relationship between pieces of the board. The same rule applies across a small duel and a crowded public match, but the situations it produces look different. ## Keep the simulation shared The browser game combines a React and TypeScript client, the interface running in the browser, with shared simulation code and an authoritative Node.js service. The shared code contains the game rules used by both client and server; “authoritative” means the server decides the match outcome. The server owns the match state, so commands from different players resolve against one version of the board. That distinction matters in a game about connections. If a cut changes which territory remains connected, everyone needs to agree on the result. Rendering and controls live in the client; deciding the shared outcome belongs to the server. ## Build the ways into the game The simulation is only one part of a playable game. Goop Troops also includes guest play, AI (computer-controlled) opponents, private rooms, teams, a tutorial, and ranked one-on-one matchmaking, which pairs players for competitive matches. Public matches support up to eight players. Those are different ways to meet the same underlying idea: learn the board with bots, play privately with friends, or try a competitive match. Desktop and touch controls give the mechanic another set of constraints to work within. [Play Goop Troops](), or [see the project and gameplay capture](). ## Related reading - [One simulated ride, the whole cycling cockpit]() - [The first sound from my printed violin]() - [One bike, three kinds of making]() --- # One bike, three kinds of making > The mechanical parts, embedded electronics, and little dashboard behind my electric bicycle conversion. Canonical page: [One bike, three kinds of making]() Published: 2026-09-15 Updated: 2026-10-14 Tags: Hardware, CAD, Embedded Project: [DIY Electric Bike]() ## In short I combined mechanical design, printed parts, and an ESP32 dashboard in my belt-drive bicycle conversion. The bike is assembled, and I wrote prototype firmware to turn motor-controller readings into a display I can see while riding. ![A blue bicycle fitted with a custom motor mount, large rear pulley, belt drive, and electronics.]() The assembled bicycle conversion, showing the motor, belt drive, and frame-mounted electronics. My [electric bicycle conversion]() combines a belt-driven motor, parts designed for the frame, and a small display for the controller’s readings. I worked through the mechanical fit in Fusion 360, a computer-aided design (CAD) tool, printed the mounts and pulley, then wrote the dashboard firmware, the software running on the ESP32, a small programmable computer. ## The model has to meet the frame The mechanical side includes a large rear pulley, a motor mount, and seat-tube clamps. Fusion 360 assemblies describe how the parts relate to the bicycle, while STL exports, files describing the surface of each part, turn individual shapes into something that can be fabricated. The CAD assembly helped me check where the motor sits, where the belt runs, and how the mounts attach. On the assembled bike, those parts also have to share space with the actual frame, wheel, wiring, and fasteners. ## Give the controller a readable face The display uses an ESP32 and a TFT (thin-film transistor) screen, a small display. Its C++ sketch reads telemetry (measurements) from a VESC motor controller over UART, a serial data connection, and draws battery voltage, power, and speed. The code also includes addressable LED control, which lets the software set individual lights. The data path is small enough to describe in one line: **Motor controller → UART → ESP32 → TFT display** That line crosses the boundary between the physical build and the software. The controller has measurements; the display gives those measurements a place the rider can see. ## What still needs checking The bike is assembled, but the dashboard firmware is a prototype. Its speed and distance calculations depend on this drivetrain’s wheel size, motor pole count (the number of magnetic poles), and pulley ratio (the relative sizes of the drive pulleys). I would check those constants against the hardware before using the sketch on another build. The [project page]() shows the finished bike, CAD assembly, and dashboard. The public repository has the editable design, printable parts, and code. [See the build photos]() or [explore the public project files](). ## Related reading - [One simulated ride, the whole cycling cockpit]() - [The first sound from my printed violin]() - [A strategy game about the space between]()