Analysis model: gpt-5.5 xhigh

Heaven by Barti!/NoooN - Technical Dissection

Scope

This is a binary-level pass over Heaven by Barti!/NoooN, an MS-DOS 4 KB intro released at Assembly 1995. The Assembly 1995 results list it as the second-place entry in the PC 4K intro competition, between Animate by Schwartz and Crashtest by J-P/Rebels.

Useful public references:

The shipped text identifies the intro as a one-night 4K, coded by Barti, and says the code is optimized for size rather than speed. It also names the visible parts:

That text is accurate. The executable is a packed 4095-byte COM that expands itself in memory, allocates a large conventional-memory work area, builds sine, height, texture, palette, and object tables at runtime, then runs a frame-counter timeline.

Archive And Variants

The examined party archive:

e1cf4d4d65fceebeb2082830a4ff4ee9f8590fa59601b26c2f123eb059f02e8e  nooon_he.zip

Extracted files:

5df1b8015d3dc40a3f438882717c6397e724b38672468be9f8afb6e6d30bcdd4  HEAVEN.COM
137821af5bb349b9afc45a540b728fc02181f10ee47554bb912d77cafc699011  NONAME.COM
3d34925b9d27b9fc837dc2c6cdf45cdcecb2c6c076052e96a332cd888ae64214  FILE_ID.DIZ
5ebc5dfb24d2908814116c99164b91a252cc57c1d414115cdf116314054b18f5  HEAVEN.TXT

Both COM files are exactly 4095 bytes. HEAVEN.COM is the named version used for this pass. NONAME.COM is very close but changes the visible credit area and packed bytes near the tail. Because the archive text describes Heaven by Barti/NoooN, the named executable is the useful one to dissect.

The external text says the intro needs roughly 450 KB of low memory. The code matches that claim: after unpacking it requests 0x6000 paragraphs, i.e. 393,216 bytes, and then divides that allocation into several 64 KB-ish work segments.

Runtime Capture

The visual pass used the same HEAVEN.COM hash listed above in DOSBox-X 2026.01.02. Timing zero is the start of dx-capture /v HEAVEN.COM.

Machine:        svga_s3
Memory:         32 MB
CPU:            normal core, fixed 50000 cycles
DOS memory:     XMS on, EMS off
Audio:          disabled; this intro has no music path
Capture:        DOSBox-X MPEG-TS/H.264
Frame size:     640x400 host capture of 320x200 VGA
Duration:       108.032 s

Heaven runtime contact sheet

The contact sheet follows the frame-counter timeline recovered from the code: cloud landscape, first torus/rays object, tunnel, second torus object, landscape/tunnel composite, and triple-donut object scene. The on-screen HEAVEN tag is produced by the intro itself and remains visible through most sections, which is useful when checking that these are not unrelated captured frames.

Heaven cloud still

Heaven tunnel still

Heaven torus still

Heaven triple-donut still

Packing And Recovered Image

HEAVEN.COM does not start as ordinary code. The first live instructions are a short high-memory relocator:

mov  cx, 07dch
mov  si, 10deh
mov  di, ff7fh
mov  bp, 0100h
push bp
pusha
std
push di
rep  movsw          ; copy most of the packed COM upward, backwards
lea  si, [di+3]
cld
mov  di, bp
ret                 ; return into the relocated tail at ff7f

The relocated tail expands the real program over the original COM area. Stopping at the first DOS interrupt after unpack gives a normal-looking COM image with the entry at 0x0100:

eaa0a3141697bdcf1d8f0f261d3066bc022138bc635546e5f48be62a65299b32  recovered COM area
a6daf18a6f29ab996d9ba9e30df4f6f4f113e18377a784f3db8ef89ec772f547  recovered full segment

All offsets below are offsets in that recovered COM image, using normal COM addresses where the file is loaded at CS:0100.

Top-Level Runtime

The unpacked entry begins with DOS memory resizing, stack setup, and runtime table generation:

0x0100  DOS AH=4A, shrink/resize current block to 0x0e6d paragraphs
0x0107  SP = 0xe6c2
0x010a  DS = ES = CS
0x010e  call 0x06ec        allocate work memory and build sine table
0x0111  int 10h mode 13h
0x0116  clear 768-byte RAM palette at 0xb430
0x0120  upload palette
0x0123  wait retrace
0x0126  DOS print title string
0x012d  copy the visible text-mode/VGA area into a work buffer
0x013e  build several palettes
0x016b  build perspective curve
0x016e  build fractal/height material
0x01b6  save old timer vector
0x01bf  install timer ISR
0x01c2  enter frame-counter timeline

The timeline is driven by word [0xd730], incremented from the timer interrupt. The main branch compares it against these cut points:

0x0320   800 frames
0x0640   1600 frames
0x0a8c   2700 frames
0x0dac   3500 frames
0x1388   5000 frames
0x1c66   7270 frames

The code does not use a general script format. It has explicit branches for the six sections, and each branch calls the small renderer components in a different combination.

The rough timeline is:

0x0000..0x031f   fractal cloud landscape
0x0320..0x063f   first torus/rays object
0x0640..0x0a8b   tunnel
0x0a8c..0x0dab   second torus object
0x0dac..0x1387   landscape plus tunnel composite
0x1388..0x1c65   triple donut / space-cut object scene

Escape is polled directly from keyboard port 0x60. Scan code 1 exits.

Heaven cloud landscape motion

The runtime pacing is exactly as compact as the branch table suggests. There are no loader menus or hidden interaction states: the intro enters graphics, runs the six timed sections, restores text mode, prints the credit line, and exits.

Memory Layout

Routine 0x06ec requests 0x6000 paragraphs with DOS AH=48h. The returned segment is stored at 0xa81a, and then several derived segment bases are built:

[0xa826] = allocation_base
[0xd742] = allocation_base + 0x2000
[0xa82a] = allocation_base + 0x3000
[0xd740] = allocation_base + 0x4000
[0xd744] = allocation_base + 0x5000

The intro treats these as scratch pages:

[0xd744]  main 64 KB-ish work framebuffer copied to A000
[0xa82a]  generated height / tunnel / cloud data source
[0xd740]  lookup or texture work segment
[0xd742]  second lookup/height segment
[0xa826]  depth/space-cut buffer pair

The same allocation also holds a sine table. 0x06ec seeds a 32-bit recurrence, then writes a 4096-entry word table at 0xb730:

; after building 4096 32-bit recurrence values
si = 0
cx = 0x1000
di = 0xb730
loop:
    eax = [ds:si]
    eax >>= 14
    stosw
    si += 4

This table is used everywhere: camera motion, object rotation, projection offsets, tunnel addressing, and the landscape camera vector.

Timer And Palette

The timer code is minimal. 0x060f saves interrupt vector 8 from physical 0000:0020. 0x05f6 installs CS:0594, then programs PIT channel 0:

cli
write interrupt vector 8 = CS:0594
out 43h, 36h
out 40h, low(04a9h)
out 40h, high(04a9h)
sti

The interrupt handler at 0x0594 accumulates 0x11eb into [0x05cc]. On carry it advances the frame counter and several phase variables:

[0xd730] += 1      global timeline frame
[0xa816] += [0x137e]
[0xa818] += 2
[0xd73e] += 15
[0xd738] += 5
[0xd73a] += 10
[0xd73c] += 3

Then it far-jumps to the old timer vector. This keeps DOS/BIOS timing alive while giving Heaven its own faster phase counters.

Palette upload is at 0x0626:

si = 0xb430
dx = 03c8h
al = 0
out dx, al         ; DAC index 0
inc dl             ; 03c9h
cx = 0300h
rep outsb

Routine 0x04b4 is the palette fade/scaler. If BP is between 1 and 128, it multiplies every channel from the source palette by BP, shifts right by 7, writes the scaled palette to 0xb430, waits retrace, and uploads it. If the fade value is outside the range, it simply uploads the current palette.

The palette tables themselves are generated by 0x0649. The routine takes small control tables at 0x12df, 0x12eb, and 0x1333, and interpolates RGB triples into the live palette buffer. For 4K, this is more efficient than storing full 768-byte palettes.

Frame Present And Work Buffer Clear

Routine 0x052b copies the work framebuffer to mode 13h A000 and then prepares the work buffer for the next frame.

The first half is a fast copy:

push ds
push es
cx = 0x3e30
si = 0x0140
di = 0
es = A000h
ds = [0xd744]
rep movsd          ; copy 63,680 bytes to visible screen

The source begins at 0x0140, so it skips one 320-byte line. That lets some renderers write with y clipping and still present a clean 320x199-ish page.

After the copy, it either clears the beginning of the work buffer or reloads it from another generated segment:

if [0x1351] == 0:
    clear BP words at work_buffer:0000
else:
    copy 0x3e80 dwords from [0xa82a] into work_buffer

That is a size-coded way to share one present routine between the landscape, tunnel, and object sections. Some parts want a blank work page. Some parts want the generated background restored each frame before objects are drawn.

Fractal Cloud Landscape

The landscape is built from two pieces:

Fractal Generator

Routine 0x0b46 initializes a 64K buffer to 0xffff, seeds one corner with 100, calls a recursive subdivision routine at 0x0aa8, then converts the high nibble of each generated value into a byte height map.

The recursive kernel at 0x0aa8 is a diamond/subdivision style function. It looks at four neighboring samples, averages them, perturbs the result through the pseudo-random helper at 0x0a7c, then recurses into four smaller squares.

The helper 0x0a7c is the random perturbation:

si = (0x00ab * si + 0x2bcd) mod [0x134b]
dx = si - 0xeaa9
ax = signed(dx * cl) >> 5
ax += current_average
clamp to 0xfe
store byte

The recursion stops when the square size reaches one. That gives the intro a cloud/terrain texture without storing one in the 4095-byte file.

Landscape Column Renderer

Routine 0x08b9 is the landscape draw path. It sets FS and GS to generated lookup/height segments, interpolates camera endpoints into a small local table at 0xa80c, and then draws vertical screen columns from back to front.

The hot loop is in 0x0988..0x09e5. Rewritten:

for sample along ray:
    advance fixed-point source coordinates
    height = -terrain[source] + 15
    screen_y = projected_height_lookup[source_phase]

    if screen_y < current_horizon:
        if screen_y < 9:
            screen_y = 9
            source_phase = 0xfa00

        count = current_horizon - screen_y
        current_horizon = screen_y

        color = height - (source_phase >> 11)
        if color < 0:
            color = 0
        color <<= 4

        repeat count rows:
            work_buffer[y][x] = color | color
            y -= 1

The actual store is word-sized:

shl  al, 4
mov  ah, al
mov  es:[di], ax
sub  di, 0140h
loop row_fill

That means it writes two adjacent pixels at a time while walking upward through the 320-byte screen. This is exactly the classic height-field/voxel-column optimization: one ray gives a stack of filled pixels, and already-covered screen rows are skipped by the moving horizon variable.

The part text's "32000 pixels" claim lines up with the code style. The renderer draws a half-resolution set of vertical columns and uses word stores to cover two pixels per step.

The cloud clip above makes the recovered landscape model visible. It does not scroll a finished picture; the same generated height/material data is sampled from a moving camera path and repainted into vertical exposure spans.

Tunnel

The tunnel uses precomputed lookup buffers, not per-pixel polar math in the frame loop.

Routine 0x0813 clears a 64K buffer, then repeatedly calls 0x0764 while incrementing a scale value from 1 up to 0x176. The generator uses the 4096 sine table and writes a pair of map buffers through FS and GS.

The visible tunnel renderer is 0x0853, with its core pixel loop at 0x0893:

mov  ebx, gs:[si]      ; packed lookup pair
add  ebx, ebp          ; animated phase
mov  al, [bx]          ; sample one texture component
shr  ebx, 16
mov  ah, [bx]          ; sample another component
add  bx, dx            ; scroll/phase offset
shl  ax, 4
and  bl, 0feh
add  ax, [bx]          ; color/lighting contribution
add  es:[di], ax       ; write two pixels additively
si += 4
di += 2

The caller runs this loop twice with CX=0x3e80:

first  0x3e80 words = 32,000 pixels
second 0x3e80 words = 32,000 pixels
total               = 64,000 pixels

That is the "64000 pixels" tunnel from HEAVEN.TXT. It is not doing expensive division or trigonometry in the hot loop. All geometry is in the lookup maps; the frame loop is lookup, combine, word add, advance.

The use of add es:[di], ax rather than mov is intentional. The tunnel can be composited over other generated material, and the two bytes in AX carry two neighboring pixels.

Heaven tunnel/vortex motion

The tunnel clip is the best example of the 64,000-pixel path. Most of the visible motion comes from phase movement through generated lookup and texture tables; the renderer itself stays small enough for a 4K budget.

Object Generator And Torus Scenes

The torus/donut sections are built by routine 0x0b88. It takes a compact source shape at 0x13db, writes an expanded object table at 0x14b6 or 0x4abe, and varies the construction according to a mode byte at 0x80c6.

The setup values in the main timeline show the intended variants:

mode 1   first torus/rays object
mode 4   second torus object
mode 3   first object in triple scene
mode 2   second object in triple scene

0x0b88 is compact but dense. It loops over twelve source slices and repeatedly builds pairs of transformed records. The rotation helpers at 0x0cd9 and 0x0d20 use sine-table values and scale constants at 0x147f and 0x1481. The result is a list of vertices/edges/faces suitable for the triangle renderer.

The triple section starting at 0x035f expands two objects:

object A at 0x14b6, center-ish values 0xb4 and 0x37
object B at 0x4abe, center-ish values 0x91 and 0x55

Then routine 0x0422 draws three passes per frame by changing position, depth, and rotation phase variables before calling the object renderer.

Triangle Setup

Routine 0x0d57 is the object draw entry. It reads object records, transforms and projects vertices with 0x0e58, then builds triangle/edge data and calls the rasterizer 0x0ee2.

The projection step is straightforward:

z = vertex_z + current_z_offset
if z is behind the near plane:
    screen_x = 160 + (x * scale) / z
    screen_y = 100 + (y * scale) / z
else:
    keep unprojected or clipped coordinate

The screen-space setup also writes small per-vertex intensity/depth helpers at 0xa008. Those are later used to shade spans and decide which parts of an object should be visible.

0x0ee2 sorts or classifies the three vertices by y, rejects triangles outside the 200-line screen, then calls:

This is where the text file's "spacecut" remark shows up in code: the renderer maintains depth/coverage buffers and tests spans at pixel level rather than just overpainting triangles in submission order.

Depth-Tested Span Inner Loop

The core span loop is at 0x1284..0x12a9, inside 0x116b.

Before it reaches the loop, 0x116b has:

DI = x position inside current row
DX = span length
SI = interpolated depth value
CX = color/intensity accumulator
BP = per-pixel depth increment
ES = work framebuffer segment
FS = depth/space-cut buffer segment

If DI crosses the half-buffer boundary at 0x7d00, the code switches FS and ES upward to the second buffer half:

cmp  di, 7d00h
jb   same_half
sub  di, 7d00h
fs += 0x0fa0
es += 0x07d0

Then the pixel loop:

cmp  fs:[edi*2], si
jbe  skip_pixel
mov  fs:[edi*2], si

xor  al, al
add  bl, cl
adc  al, ch
mov  es:[di], al

skip_pixel:
inc  di
add  si, 1111h
add  cx, bp
dec  dx
jne  pixel_loop

The depth buffer is word-sized, indexed as edi * 2. A pixel is drawn only if the new depth is closer than the stored depth. On success, the color is derived from a compact fixed-point accumulator: the carry from adding CL into BL becomes part of the final color, while CH carries the coarse shade.

This is the most important 4K trick in Heaven. The object renderer is not a simple painter's algorithm. It pays the cost of a per-pixel depth test, which lets the torus/donut scenes self-occlude correctly. The code is size-oriented, so the depth step is crude (SI += 0x1111 in the inner loop), but it is enough to make overlapping rings read as solid shapes.

Heaven first torus motion

The first torus clip shows the renderer using the same depth-tested span core for a large close object. The shading bands are coarse, but the occlusion reads correctly because pixels only win when their word depth beats the stored value.

Heaven triple-donut motion

The final triple-donut section is the most convincing runtime proof of the object pipeline. Multiple interlocking rings overlap and rotate without collapsing into painter-order artifacts, which matches the per-pixel depth buffer described above.

Texture And Background Generator

Routine 0x1396 sits directly after the visible credit string and is called before torus sections. It clears a generated segment to zero, then runs a long byte-generation loop from about 0x13a4:

es = [0xa82a]
clear 0x8000 words
di = 0xef98
ecx = 0x10e50
loop:
    transform neighbor bytes around di
    build small bias from high bits of the loop counter
    add/average previous pixels
    stosb
    ecx--

The exact byte recipe is packed hard for size, but the structure is clear: it uses previous pixels and nearby rows (di-0x280, di-0x140, di-0x141) to grow a soft texture/background. The shipped text thanks earlier fire-background work; this is the runtime generator that replaces a stored bitmap.

Runtime-To-Code Concordance

The four GIF clips now have an explicit code map. This is mostly a cross-index, because the article already has the relevant inner loops.

The cloud-landscape GIF maps to the first timeline window, [0xd730] < 0x0320. The code-side anchors are the midpoint/fractal generator at 0x0b46, the recursive subdivision kernel at 0x0aa8, the pseudo-random perturbation helper at 0x0a7c, and the vertical-column renderer at 0x08b9. The clip proves moving camera resampling of generated terrain/cloud material, not a stored background pan.

The tunnel/vortex GIF maps to the 0x0640..0x0a8b timeline window and the 64,000-pixel tunnel path. The lookup generator at 0x0813 and helper 0x0764 build the tunnel maps; the hot loop at 0x0893 samples packed lookup pairs, adds phase offsets, combines two texture bytes and a lighting contribution, and adds two pixels at a time into the work buffer. The GIF is the temporal proof that this is phase motion through generated maps, not per-frame polar math.

The first-torus GIF maps to the object generator/rasterizer chain: 0x0b88 expands the compact source shape, 0x0d57 transforms and projects object records, and 0x0ee2/0x116b set up and draw triangle spans. The important visible property is self-occlusion, which matches the word depth buffer test in the span loop at 0x1284..0x12a9.

The triple-donut GIF maps to the final timeline window, 0x1388..0x1c65. That section reuses the same object generator and depth-tested span core but draws multiple passes from 0x0422 with different position, depth, and rotation phase values. The clip is the strongest visual proof that Heaven spends bytes on a real space-cut/depth path rather than a painter-order object hack.

All four clips share the same infrastructure: the self-relocating COM unpacker, the 0x6000-paragraph allocation, generated sine/palette/texture tables, the timer ISR at 0x0594 that advances [0xd730] and phase variables, and the present routine at 0x052b that copies the work framebuffer to A000h. That is the 4K design pattern: generators and shared kernels, not stored visual assets.

Exit Path

When the frame counter reaches the end threshold or Escape is pressed, the code runs:

0x05ce   restore old timer vector and reset PIT divisor
unmask IRQ2 path through port 0x21
int 10h mode 3
DOS free allocated block
DOS print the title and credit strings
DOS AH=4C exit

The final DOS print strings are small title and credit lines. The recovered image stores them with marker bytes around the title, so the useful point is only that the exit path restores text mode, frees the allocated block, prints the Heaven credit, and returns to DOS.

What The Code Is Doing

Heaven is impressive because the visible variety is not stored as assets. In 4095 bytes it contains:

The inner loops are deliberately simple once the generated tables exist. The landscape loop fills vertical runs and skips already-covered rows. The tunnel loop is two table reads plus a two-pixel additive write. The torus loop is a classic y-sorted triangle span routine with a word depth buffer. That is the right 4K design: spend bytes on generators and shared render kernels, then reuse them with different constants and palettes to make several distinct scenes.