# Amiga Juggler: veertig jaar later, elke frame live berekend

> Canonieke pagina: https://www.mahieu.nl/toepassingen/amiga-juggler/

- Demo: https://www.mahieu.nl/amiga-juggler/ (publiek, Nederlands en Engels; vereist WebGL2, geluid via Web Audio).
- Kern: analytische raytracer in een WebGL2-fragmentshader, vanilla JavaScript, zonder frameworks of buildstap.
- Gemaakt door [Michel Mahieu](https://www.mahieu.nl/) als hommage aan de Juggler van Eric Graham uit 1986.

Een persoonlijk maakproject, ontwikkeld in eigen tijd en met eigen middelen.

## Wat het is

In november 1986 liet Eric Graham een Amiga een jongleur raytracen: 24 frames van 320 bij 200 pixels, elk ongeveer een uur rekenwerk. Deze hommage berekent dezelfde scène opnieuw, maar dan elke frame live op de grafische kaart van de bezoeker: 70 bollen, harde schaduwen en twee spiegelreflecties per lichtstraal. Met een 1986-modus met dikke pixels, een vrije camera en het originele ‘ding’.

De demo start in de 1986-modus: 320 × 200 pixels in een 4:3-kader, 4 bits per kleurkanaal zoals HAM, en 24 stappen per lus van 0,8 seconde. Modern geeft de vloeiende weergave op volle resolutie. Slepen draait de camera, het wiel of een knijpbeweging zoomt, de pijltjestoetsen werken als alternatief. Drone shot laat de camera doorlopend rond de jongleur cirkelen; Herstel camera zet de originele kadrering terug. De snelheid loopt van 0,01× tot 2×; het geluid verandert mee in toonhoogte, zoals een bandje. Met de toetsen , en . stapt u beeld voor beeld door de 24 poses; de spatiebalk pauzeert. De demo is er in het Nederlands en Engels.

Op de showcasepagina laadt de demo zodra hij in beeld komt en start hij na een klik. In kijkmodus blijft de pagina gewoon scrollen; met Zelf besturen neemt u de camera over. Buiten beeld pauzeert de demo vanzelf, ook het geluid.

## Het origineel: een uur per frame, op een Amiga met 512 kB

Eric Graham kocht medio 1986 een Amiga 1000 en schreef in november van dat jaar in één dag een raytracer. Daarmee berekende hij 24 beelden van een jongleur met drie spiegelende ballen: 320 bij 200 pixels, 64.000 lichtstralen per beeld, ongeveer een uur rekenwerk per frame. De beelden werden gecodeerd in de HAM-modus van de Amiga, die 4096 kleuren tegelijk op het scherm toont, verliesvrij gecomprimeerd tot zo’n 10 kB per frame en afgespeeld als lus van 0,8 seconde op 30 beelden per seconde, met één ‘ding’ per vangst.

Commodore bracht de animatie in november 1986 uit als demonstratie van wat de Amiga kon. Bij Commodore geloofde men eerst niet dat het van een Amiga kwam; Graham stuurde zijn renderer op, zodat ze de frames zelf konden berekenen. Uit die raytracer groeide Sculpt 3D, dat in het najaar van 1987 uitkwam.

De camera- en bewegingsdata van toen zijn verloren. Wat er wél is: de 24 frames, de teruggevonden broncode van Raytracer 1.0 (1987) met het scènebestand robot.dat, en een opname van het geluid van een echte Amiga. Daaruit is deze versie teruggemeten.

## In cijfers

- 70 bollen, elke frame analytisch geraytracet, plus een oneindige dambordvloer.
- 24 frames uit 1986, opnieuw gemeten: balcentra, hoofd, handen, voeten en gewrichten.
- 0,8 seconde per lus (24 frames op 30 fps), één ‘ding’ per vangst.
- 102 geautomatiseerde tests: 82 unittests en 20 browsertests in Chromium.

## Dezelfde lichtstralen, twee weergaven

De 1986-modus raytracet op exact 320 × 200, kwantiseert elke kleur naar 4 bits per kanaal (⌊16·kleur + 0,5⌋, zoals rt2.c) en toont het beeld met nearest-neighbour in een 4:3-kader, met de pixelverhouding 5:6 van een monitor van toen. De beweging stapt in de 24 discrete poses van het origineel. Het per-scanlijn-foutgedrag van de HAM-encoder (kleurfringing) wordt bewust niet geëmuleerd.

De moderne modus rendert op de eigen resolutie van het scherm (inclusief device-pixel-ratio), met FXAA als lichte tweede beeldpass. De 24 poses worden geïnterpoleerd als gesloten kromme. De verticale beeldhoek blijft die van het origineel (≈ 50°); brede schermen tonen meer opzij.

## Teruggemeten uit 24 frames

- **De camera staat waar hij in 1986 stond.** Gefit op de framedata: oog op (−6, 3,32, −6), blik 45° over de diagonaal van het dambord, vrijwel waterpas (horizon op rij 97 van 200), brandpunt 215 pixels met vierkante beeldpixels. De figuur staat op de wereldoorsprong.
- **De beweging komt uit de pixels.** Balcentra, hoofd, handen, voeten en de buigrichting van de gewrichten zijn uit alle 24 frames gemeten. De balbaan is een Fourier-fit met drie harmonischen per coördinaat (herprojectiefout ≈ 2 pixels), gelegd op een licht gekanteld 3D-jongleervlak; de handen bewegen op een vlak er vlak achter, zodat ze de ballen ook vanuit een vrije camera echt raken. Eén bal doorloopt het circuit in drie lussen; de drie ballen liggen een derde uit fase.
- **Materialen en shading uit de broncode van 1987.** 70 bollen met de materialen en kleurwaarden uit robot.dat; het lichtmodel van rt1.c: wrap-ambient (n·ẑ + 1,5) · 0,4 × 0,25, één verre lamp met cos/r², binaire witte glimpunten boven cos² > 0,95, spiegels als recursieve reflectie × 0,9, harde schaduwen en géén gammacorrectie. De vloer is een exacte port van gingham(): tegels van 3 eenheden, gespiegeld om beide assen, inclusief de dubbele band bij de oorsprong die in het origineel zichtbaar is.
- **Een figuur die ook van opzij klopt.** De lichaamsbouw volgt de slankere, camera-onafhankelijke 3D-pose van Ben Hanke (romp 0,69 → 0,55, hoofd r 0,46, vaste arm- en beenlengtes). Two-bone IK houdt handen en voeten op hun gemeten doelen, zodat de ballen bij een vrije camera niet door hoofd of romp gaan.
- **Het ‘ding’ is nagemeten aan een echte Amiga.** Eén ding per lus op het vangmoment: een vrijwel zuivere sinus van 1 kHz met een trapsgewijze envelope in stappen van 50 ms (≈ 0,5 s), gemeten aan Ernie Wrights opname van de audio-uitgang van een Amiga. Web Audio speelt de sample als band af: bij snelheid r wordt de toon r× hoger en 1/r× korter, ook bij een wijziging tijdens de demo.

## Zo rekent de GPU

1. Scène in JavaScript: per frame de 70 bollen (positie, straal, materiaal) en vijf omhullende bollen, als uniforms naar de GPU. Geen meshes, geen texturen.
2. Eén straal per pixel: een fragmentshader (GLSL ES 3.0) schiet vanuit het gefitte cameraoog door elke pixel één straal; het hele scherm is één driehoek.
3. Snijpunten: analytische straal-bolsnijding; ledematen in vijf groepen met een omhullende bol, zodat de meeste stralen maar een paar bollen testen. De vloer is een oneindig vlak.
4. Licht en schaduw: per raakpunt een schaduwstraal naar de lamp; harde schaduw, wrap-ambient en glimpunt volgens rt1.c.
5. Spiegels: de drie ballen weerkaatsen tot twee keer (reflectie × 0,9), daarna de lucht. Bij aanhoudend trage frames schakelt het framebudget trapsgewijs terug: één reflectie en daarna, in de moderne modus, een lagere renderschaal.
6. Presentatie: 1986 als 320 × 200 naar een 4:3-kader met nearest-neighbour en 4 bits per kanaal; modern met FXAA op volle resolutie.

Verder: geen dependencies en geen buildstap (JavaScript-modules, drie GLSL-shaders, Web Audio) onder de strikte Content-Security-Policy van mahieu.nl; een eigen animatieklok waardoor pauzeren en hervatten niet verspringen en de snelheid voor beeld én geluid geldt; herstel na een verloren WebGL-context; 82 unittests voor scène, camera, klok, audio, framebudget en de contracten van bediening en renderer, plus 20 Playwright-tests in Chromium voor bediening, focus, pauze, audio, fullscreen, contextverlies en de gouden beelden van de 24 poses. Een verificatiemodus rendert elk van de 24 poses 1:1 op 320 × 200, zodat ze naast de originele frames gelegd kunnen worden.

## Bronnen en credits

- Eric Graham, Raytracer 1.0 (1987): de teruggevonden broncode (rt1.c–rt3.c) en het scènebestand robot.dat, door AlphaPixel van de originele diskette gehaald en gepubliceerd op https://github.com/AlphaPixel/Eric-Graham-1987-Juggler-Raytracer-1.0. Eric Graham gaf in februari 2026 toestemming: iedereen mag de code gebruiken, zolang hij genoemd wordt.
- Ernie Wright, technische analyse: de 24 originele frames als PNG, de opname juggler.wav van een echte Amiga en de geschiedenis van de demo, inclusief Grahams eigen herinneringen: http://www.etwright.org/cghist/juggler.html. Het kalibratie- en verificatiemateriaal van deze reconstructie.
- Meatfighter, wiskundige reconstructie: een stapsgewijze herbouw met de afleiding van camera, balbanen en het shower-jongleerpatroon (hoge boog van links naar rechts, lage boog terug): https://meatfighter.com/juggler/.
- Ben Hanke, realtime WebGL-versie: een eerdere realtime versie, gebruikt als vergelijking voor een camera-onafhankelijke 3D-pose: http://13h.org/juggler/.
- AmigaWorld, mei/juni 1987: Grahams eigen artikel over het maken van de Juggler; het programma dat het artikel aankondigde werd Sculpt 3D. De demo verscheen als versie 1.2 op Fish Disk 97.

## Waarom dit telt

Een raytracer heeft geen renderfarm meer nodig: wat in 1986 een uur per beeld kostte, doet een grafische kaart nu tientallen keren per seconde, in een browser, zonder plug-in. En uit 24 plaatjes en een stuk C-code is een werkende, geteste en toegankelijke toepassing te bouwen, als je bereid bent te meten in plaats van te gokken. Dat is dezelfde manier van werken als bij opdrachten: beginnen bij wat er is, de kleinste werkende versie bouwen, meten, testen en pas dan uitbreiden. Zie https://www.mahieu.nl/werkend-bewijs/

## Controleerbaar bewijs

- **Probleem:** de originele Juggler bestaat alleen nog als 24 HAM-frames; camera- en bewegingsdata zijn verloren en de demo is gebonden aan het Amiga-scherm van 1986.
- **Aanpak:** scène, camera, licht, beweging en geluid teruggemeten uit de frames, de teruggevonden broncode van 1987 en een audio-opname; opnieuw gebouwd als analytische raytracer in een WebGL2-fragmentshader, met een 1986-modus en een vrije camera.
- **Status:** live en publiek op https://www.mahieu.nl/amiga-juggler/, in het Nederlands en Engels. Een persoonlijk maakproject, niet in opdracht gemaakt.
- **Aantoonbaar resultaat:** 70 bollen, harde schaduwen en twee spiegelreflecties per frame live berekend; de 24 originele poses en het ‘ding’ gereproduceerd; 82 unittests en 20 browsertests slagen.
- **Beperkingen:** WebGL2 is vereist en zonder Web Audio speelt de demo zonder geluid; op zwakke grafische kaarten schakelt de demo terug naar één reflectie en een lagere renderresolutie. HAM-kleurfringing wordt niet geëmuleerd. Geluid vereist een klik of tik.
- **Stand van zaken:** oktober 2026.

## Veelgestelde vragen

**Wat is de Amiga Juggler?**
Een animatie van Eric Graham uit 1986: een jongleur met drie spiegelende ballen, geraytracet op een Amiga 1000 en door Commodore uitgebracht als demonstratie. 24 frames in HAM-modus, 320 bij 200 pixels, een lus van 0,8 seconde met één ‘ding’.

**Is dit het originele filmpje?**
Nee. Er wordt geen enkel origineel beeld afgespeeld: elke frame wordt live berekend in uw browser, op uw grafische kaart. Scène, camera en beweging zijn teruggemeten uit de 24 frames en de broncode van 1987.

**Waarom ziet de 1986-modus er zo blokkerig uit?**
Omdat dat de echte resolutie is: 320 bij 200 pixels, uitgerekt tot 4:3 zoals op een monitor van toen, met 4 bits per kleurkanaal en 24 stappen per lus. Kies Modern voor de vloeiende weergave op volle resolutie.

**Werkt het op een telefoon?**
Ja, in een moderne browser met WebGL2. Slepen draait de camera, knijpen zoomt en twee vingers verschuiven het beeld. Blijven frames traag, dan schakelt de demo zelf een trap terug: eerst naar één spiegelreflectie, daarna naar een lagere renderresolutie.

**Mag dit zomaar?**
Het is een hommage, geen kopie: er worden geen originele beelden gebruikt. Eric Graham heeft in 2026 laten weten dat iedereen zijn code mag gebruiken zolang hij genoemd wordt; de demo en deze pagina noemen hem en de andere bronnen.

**Wat heeft dit met uw werk te maken?**
Alles: beginnen bij wat er is, meten in plaats van gokken, de kleinste werkende versie bouwen en die testen. Zo werk ik ook bij opdrachten, van idee naar werkend bewijs.

## Contact

- Contactpagina: https://www.mahieu.nl/contact/
- E-mail: mwd@mahieu.nl
- Demo: https://www.mahieu.nl/amiga-juggler/ (Markdown: https://www.mahieu.nl/amiga-juggler.md)
- Alle eigen toepassingen: https://www.mahieu.nl/toepassingen/

Laatst bijgewerkt: 13 oktober 2026.
