NOW LET US – AI RAG SaaS Studio TP.HCM
NOW LET US
Digital Product Studio
Back to news
DEV-TOOLS...7 min read

A whole boss fight in 256 bytes

Share
NOW LET US Article – A whole boss fight in 256 bytes

Endbot is a 256-byte DOS intro that features a robot sprite with damage effects, explosions, and a MIDI soundtrack, showcasing extreme code optimization.

256-byte DOS intro · HellMood/Desire · Revision 2026

Endbot is a complete audio-visual demo that fits in exactly 256 bytes. It runs under DOS (via DosBox-X) and renders in real-time: a robot sprite with progressive bullet damage, a growing explosion, a scrolling checkerboard landscape, and a MIDI soundtrack - all from a single tiny .com file.

You need FASM (Flat Assembler). One command produces a raw binary with no linker step:

fasm endbot.asm endbot.com

The intro writes to MIDI port 0x330 for music. Use DosBox-X (not plain DOSBox) for its proper MPU-401 emulation.

[dosbox] machine=vgaonly memsize=4 [cpu] cputype=386 cycles=auto [midi] mpu401=uart mididevice=fluidsynth # use win32 on Windows, fluidsynth on Linux/macOS fluid.soundfont= # path to a GM .sf2, e.g. /usr/share/sounds/sf2/FluidR3_GM.sf2 [sblaster] sbtype=none [mixer] rate=44100

dosbox-x -conf dosbox-x.conf endbot.com

0xFF ) before exit so no notes hang open.; "Endbot" - 256b intro for DosBox-X ; presented at Revision 2026 ; by HellMood/Desire %define initbp 0x91C ; BP=Timer, use constant to ease calculations org 100h push 0xa000-20*4 ; VGA Memory Adress, slightly offset to beautify pop es ; into ES mov al,0x13 ; 13h : 320 * 200 Pixels in 256 Colors int 0x10 ; Set! mov cl,Nasenatmungsgeraeusch ; Dump the whole Code to MIDI until this point mov di,si ; Align Music Pointer with Pixel Pointer for 1st check

int 10h / AL=13h sets VGA mode 13h: 320×200, 256 colors, flat 64 000-byte framebuffer at A000:0000 . CL is loaded with the byte length of the combined music+sprite block - used by rep outsb on the first frame boundary to stream it all to MIDI port 0x330 in one shot.StartFrame: mov dx,0x330 ; Set MIDI Port sub di,si ; Advance Pixel by 4*n ( +1 by stosb is a nice dither) jnz StartPixel ; If not at the end of a frame, skip per-frame-stuff mov ax,bp ; sub al,initbp&0xFF ; hit four times, at time = 0, 256, 512, 768 jnz NoSound ; Output exactly four MIDI notes, except at start rep outsb ; CX is 4 except the first time! NoSound: mov al,1193182/256/30 ; PIT frequency / High Byte / FPS out 40h,al ; Set Timer to ~ 30 FPS hlt ; Sync against the timer inc bp ; Next time step xor byte [si-Nasenatmungsgeraeusch+Colors+1-8],cl ; angry flicker! in al,0x60 ; Key Code in AL sub al,2 ; Will leave 0xFF in AL on Exit! jc Quit ; ESC -> Stop Sounds -> END

40h then hlt pauses the CPU until the next hardware interrupt, locking to ~30 FPS. rep outsb streams CX bytes from [SI] to the MIDI port whenever BP mod 256 == 0 - four beat events over the demo's runtime; CX is 4 on beats 2–4 and the full block length on beat 1. The keyboard check reads scancode port 60h ; ESC has scancode 1, subtracting 2 leaves 0xFF with carry set → exit branch.StartPixel: mov ax,0xcccd ; The Rrrola trick to get X,Y in DL,DH mul di ; there we go mov ax,bp ; get timer in AX sub ax,(768+initbp) ; check if it's explosion time mov cx,dx ; "DrawSprite" gets x,y in DX as CX jc NoExplosion ; No explosion yet! (CF != ZF) jz Flash ; The very moment of impact, flash orange once

0xCCCD and reading the high-word gives approximate X (DL) and Y (DH) without a division instruction - 5 bytes of machine code vs 8+ for a proper divide+modulo. AX = BP − (768 + initbp) gives time-since-explosion: negative (CF set) = not yet; zero (ZF set) = exact impact frame; positive = expanding circle.sub ch,al ; After impact, move Bot down xchg bx,ax ; Save "time since impact" (TSI) in BL mov al,dh ; Y in AL sub al,77 ; center Y imul al ; YY sub bl,ah ; TSI - YY mov al,dl ; X in AL add al,128 ; center X imul al ; XX cmp bl,ah ; TSI - YY - XX = TSI - RR = Circle Flash: mov al,0x2a ; A beautiful orange value jz PlotPixel ; ON the circle -> plot orange jnl BackGround ; INSIDE -> dissolve into background js NoExplosion ; not yet exploded, and before 128 time steps after TSI Quit: ; (RET = Quit, top Stack = 0, [0] = int 20h = quit) out dx,al ; Either has 0xFF (silence) from above ... ret ; ... or outputs one trash byte after silence xD

X² + Y² = TSI defines the ring edge, growing as time increases. Pixels 0x2A ); pixels sub ch,al ). Exit uses ret : the stack top holds 0, and address 0 in a .com segment contains int 20h - the DOS "program terminate" call - saves 1 byte.NoExplosion: mov ax,bp ; get timer in AX cmp ax, 256+initbp ; first 256 time steps = no Sprite jl BackGround test al,32 ; mirror jnz NoAniFlip ; on not al ; x-axis NoAniFlip: and al,63 ; filter to last 6 bits add al,148 ; adjust X position of Sprite add cl,al ; timebased X zig zag movement of Sprite js BackGround ; inside signed byte range = Sprite sub ch,36+8 ; adjust Y position of Sprite js BackGround ; inside signed byte range = Sprite DrawSprite: ; Draw the 128x128 Pixel Sprite mov bx,Sprite ; Sprite data adress mov ax,bp ; Get timer in AX sub ax,(512+initbp) ; Time for damage already? jc SkipDamage ; AL = Time since shooting xor al,1010101b ; Pseudo Random Impact Location btc word [bx],ax ; Directly flip sprite bits SkipDamage: shrd ax,cx,18 ; SCALE and transfer of local X,Y test al,16 ; need to mirror? jz NoFlip ; mirror on y-axis not al ; if needed NoFlip: and ax,00011110b*256 + 00011110b ; filter : range&even xchg cx,ax ; just to get AX to CX add bl,ch ; offset Sprite to correct line mov ax,[bx] ; get the line data shr ax,cl ; shift down by (mirrored) column mov bl,Colors-1 ; CLUT -> 0 = transparent and al,3 ; set zero flag if "transparent" == 0 xlat ; looks up 3 Colors, discarded if 4th jnz PlotPixel ; if not transparent, directly PlotPixel

Colors . The zigzag horizontal movement comes from toggling bit 5 of the timer with test al,32 / not al . btc (bit-test-and-complement) flips one sprite bit per frame from frame 512 onward, accumulating visible bullet holes over time. xlat performs a 1-byte palette lookup: AL = [BX+AL] .BackGround: mov al,0x4e+72 ; a bluetiful color =) test dh,dh ; are we over the horizon? jns PlotPixel ; if yes, just plot the Blue sub dh,-(128+13) ; are we wrapped around to sky again!? js PlotPixel ; if yes, just plot the Blue mov ax,bp ; timer as depth, DIV DANGER div dh ; Constant / Y as distance in AL xchg dx,ax ; DL=distance AL=X add al,128 ; center X imul dl ; X' in AH add dx,bp ; distance += time (plane movement) xchg dx,ax ; DH= X' AL=distance' xor dh,al ; checker pattern imul dh ; distortion texture aam 9 ; irregular filter & range add al,212 ; offset to "landscape" colors PlotPixel: stosb ; FINALLY, plot the damn pixel! mov cx,4 ; for sound routines above and bot flicker jmp StartFrame ; Rinse and Repeat

div dh for a perspective depth value (BP/Y), perspective-corrects the X coordinate, then XORs for a scrolling checker pattern. The aam 9 (ASCII Adjust after Multiply) is a 2-byte modulo-9, providing irregular color banding across the landscape palette entries. stosb writes the final pixel to ES:[DI] and auto-increments DI; CX is restored to 4 for the music/flicker logic on the next frame boundary.Sprite: dw 0000111101110000b ; Pixels by Steffest / Desire dw 0111110111110100b ; he was so nice to anticipate dw 1111011111111100b ; i need reusable Sprite Data dw 0101111101111100b ; so he left me the following dw 0111111010110000b ; two bytes of actual MIDI data dw 1111111111110000b ; inside the middle of the Bot dw 1111111100000000b ; ************************************** dw 0111111111000000b ; 0xC07F, MIDI, set gunshot on channel 0 dw 1011011111110000b ; ************************************** dw 1011101111110000b ; this (too) is dumped to MIDI at start dw 1011101101111100b ; or is it a coincidence? dw 1011101110111100b ; a 1 in 65536 coincidence? dw 1011101110011111b ; Who knows ;) dw 0111011101111111b dw 1111111111111111b ; this gets modified by the code so ;dw 1111111111111011b ; this patch has to be applied 11 -> 10 dw 1111111111111100b MusicData: db 0xc9,56 ; set drum channel to SFX db 0x99 ; play on drum channel : db 70,0x58 ; helicopter, moderate db 81,0x7F ; wind

© 2026 Now Let Us. All rights reserved.

Source: Hacker News

Advertisement
Ad slot ready: 5887729102

More in this category

NOW LET US Related – Leaving Mozilla

dev-tools

Leaving Mozilla

A poignant and candid reflection from a 15-year Mozilla veteran upon their departure. The author highlights the leadership's missteps in trying to emulate tech giants and urges Mozilla to return to its core values: community and uniqueness.

NOW LET US Related – Shepherd's Dog: A Game by the Most Dangerous AI Model

dev-tools

Shepherd's Dog: A Game by the Most Dangerous AI Model

A developer tested Anthropic's latest, supposedly 'too dangerous' AI model by asking it to build a long-held game idea in a single shot. The model succeeded, generating a complete 2,319-line game after a 45-minute reasoning session.

NOW LET US Related – Open source AI must win

dev-tools

Open source AI must win

If artificial intelligence becomes a utility rented only from a few closed institutions, humanity loses its operational freedom. Open-source AI is a vital infrastructure for the future of our digital society.

NOW LET US Related – Statement on US government directive to suspend access to Fable 5 and Mythos 5

dev-tools

Statement on US government directive to suspend access to Fable 5 and Mythos 5

The US government has issued an export control directive forcing Anthropic to suspend all access to its Fable 5 and Mythos 5 models due to national security concerns, a move the AI safety startup strongly disputes.

NOW LET US Related – Electric motors with no rare earths

dev-tools

Electric motors with no rare earths

Renault Group is pioneering the development of electrically excited synchronous motors (EESM) that eliminate the need for rare earth magnets, reducing dependency on global monopolies while driving efficiency and sustainability.

NOW LET US Related – Swift at Apple: Migrating the TrueType hinting interpreter

dev-tools

Swift at Apple: Migrating the TrueType hinting interpreter

Apple has rewritten its TrueType hinting interpreter from C to memory-safe Swift for its Fall 2025 OS releases, improving security and boosting performance by an average of 13%.

EXPLORE TOPICS

Discover All Categories

Deep dive into the specific technology sectors that matter most to you.