mikeayles
9 hr. ago

Show HN: KiDoom – Running DOOM on PCB Traces

I got DOOM running in KiCad by rendering it with PCB traces and footprints instead of pixels.

Walls are rendered as PCB_TRACK traces, and entities (enemies, items, player) are actual component footprints - SOT-23 for small items, SOIC-8 for decorations, QFP-64 for enemies and the player.

How I did it:

Started by patching DOOM's source code to extract vector data directly from the engine. Instead of trying to render 64,000 pixels (which would be impossibly slow), I grab the geometry DOOM already calculates internally - the drawsegs[] array for walls and vissprites[] for entities.

Added a field to the vissprite_t structure to capture entity types (MT_SHOTGUY, MT_PLAYER, etc.) during R_ProjectSprite(). This lets me map 150+ entity types to appropriate footprint categories.

The DOOM engine sends this vector data over a Unix socket to a Python plugin running in KiCad. The plugin pre-allocates pools of traces and footprints at startup, then just updates their positions each frame instead of creating/destroying objects. Calls pcbnew.Refresh() to update the display.

Runs at 10-25 FPS depending on hardware. The bottleneck is KiCad's refresh, not DOOM or the data transfer.

Also renders to an SDL window (for actual gameplay) and a Python wireframe window (for debugging), so you get three views running simultaneously.

Follow-up: ScopeDoom

After getting the wireframe renderer working, I wanted to push it somewhere more physical. Oscilloscopes in X-Y mode are vector displays - feed X coordinates to one channel, Y to the other. I didn't have a function generator, so I used my MacBook's headphone jack instead.

The sound card is just a dual-channel DAC at 44.1kHz. Wired 3.5mm jack → 1kΩ resistors → scope CH1 (X) and CH2 (Y). Reused the same vector extraction from KiDoom, but the Python script converts coordinates to ±1V range and streams them as audio samples.

Each wall becomes a wireframe box, the scope traces along each line. With ~7,000 points per frame at 44.1kHz, refresh rate is about 6 Hz - slow enough to be a slideshow, but level geometry is clearly recognizable. A 96kHz audio interface or analog scope would improve it significantly (digital scopes do sample-and-hold instead of continuous beam tracing).

Links:

KiDoom GitHub: https://github.com/MichaelAyles/KiDoom, writeup: https://www.mikeayles.com/#kidoom

ScopeDoom GitHub: https://github.com/MichaelAyles/ScopeDoom, writeup: https://www.mikeayles.com/#scopedoom

192
21
harryday
2 day ago

Surprisingly, Emacs on Android is pretty good

97
33
exvi
5 hr. ago

Space Truckin' – The Nostromo (2012)

65
16
digital55
11 hr. ago

A new bridge links the math of infinity to computer science

167
63
franczesko
6 day ago

Copyparty, the FOSS file server [video]

12
2
mooreds
3 day ago

Java Decompiler

47
15
agreeahmed
14 hr. ago

Show HN: We built an open source, zero webhooks payment processor

Hi HN! For the past bit we’ve been building Flowglad (https://flowglad.com) and can now feel it’s just gotten good enough to share with you all:

Repo: https://github.com/flowglad/flowglad

Demo video: https://www.youtube.com/watch?v=G6H0c1Cd2kU

Flowglad is a payment processor that you integrate without writing any glue code. Along with processing your payments, it tells you in real time the features and usage credit balances that your customers have available to you based on their billing state. The DX feels like React, because we wanted to bring the reactive programming paradigm to payments.

We make it easy to spin up full-fledged pricing models (including usage meters, feature gates and usage credit grants) in a few clicks. We schematize these pricing models into a pricing.yaml file that’s kinda like Terraform but for your pricing.

The result is a payments layer that AI coding agents have a substantially easier time one-shotting (for now the happiest path is a fullstack Typescript + React app).

Why we built this:

- After a decade of building on Stripe, we found it powerful but underopinionated. It left us doing a lot of rote work to set up fairly standard use cases - That meant more code to maintain, much of which is brittle because it crosses so many server-client boundaries - Not to mention choreographing the lifecycle of our business domain with the Stripe checkout flow and webhook event types, of which there are 250+ - Payments online has gotten complex - not just new pricing models for AI products, but also cross border sales tax, etc. You either need to handle significant chunks of it yourself, or sign up for and compose multiple services

This all feels unduly clunky, esp when compared to how easy other layers like hosting and databases have gotten in recent years.

These patterns haven’t changed much in a decade. And while coding agents can nail every other rote part of an app (auth, db, analytics), payments is the scariest to tab-tab-tab your way through. Because the the existing integration patterns are difficult to reason about, difficult to verify correctness, and absolutely mission critical.

Our beta version lets you:

- Spin up common pricing models in just a few clicks, and customize them as needed - Clone pricing models between testmode and live mode, and import / export via pricing.yaml - Check customer usage credits and feature access in real time on your backend and React frontend - Integrate without any DB schema changes - you reference your customers via your ids, and reference prices, products, features and usage meters via slugs that you define

We’re still early in our journey so would love your feedback and opinions. Billing has a lot of use cases, so if you see anything that you wish we supported, please let us know!

286
162
joshwcomeau
15 hr. ago

New layouts with CSS Subgrid

162
41
jonbaer
7 hr. ago

CS234: Reinforcement Learning Winter 2025

76
8
pseudolus
19 hr. ago

Trillions spent and big software projects are still failing

400
354