Technical notes
How vrChristmas worked
The source code for VRMan's vrChristmas is gone. To rebuild it faithfully we took the finished screensaver apart and watched it run. This page records what we found.
Each finding is tagged measured when we read it from the program or from recordings of it running, or inferred when it is our best explanation of what the evidence shows. The browser version is built from these notes.
- We unpacked
vrxmas30.scr(version 3.0, 2002) and read its embedded resources. - We decompiled the program with the NSA's Ghidra to read the logic and the constants it uses.
- We ran it beside a small stand-in for
d3drm.dllthat logged every Direct3D Retained Mode call: about a million calls in a three-minute run, including every position, orientation and camera move. - We recorded video of its window, with that log timestamped to match, to compare frame by frame.
Everything here comes from the program VRMan published. Nothing was taken from other sources.
What is inside the file
| 38 models | DirectX .x files in binary format: cabin, sleigh, snowman, train engine and boxcar, gingerbread man, candy cane, wreath, stars, fish, stocking, light-string pieces and more. |
|---|---|
| 42 textures | Bitmaps for the ground, tree, cards, train, flakes, glows and 16 frames of smoke. |
| 20 songs | MIDI files. See the music page. |
| 1 video | A 151×111, 6.7-second animation. We have not yet seen where the program uses it. |
The clock: one step per eight frames
measuredThe scene does not move every frame. The program draws eight frames, then runs one step of the simulation, then draws eight more. In a recording, exactly 8 frames fall between steps in 506 of 508 steps, and the picture does not change at all in between. Each step also spins everything that has a rotation set by moving the scene forward 7.5 units of time.
measuredDistances are per step, not per second: the train covers about 8 units every step whether the computer is fast or slow. So the screensaver ran faster on a faster graphics card. In our recording (software rendering, about 40 frames a second) that was about 5 steps a second; on a modern PC drawing 300 frames a second it would be about 37.
The opening camera move
measuredThe first 120 steps are a fly-in. The program builds two Direct3D animations, each with four position keys at times 0, 2, 4 and 12, and picks one at random. Each step it moves the animation clock forward 0.1 and the camera follows the curve until time 12, ending in front of the greeting card.
| Path A | (−2593, 371, 333) → (1200, 800, −1500) → (200, 150, −200) → (−70, 50, 0) |
|---|---|
| Path B | (−461, 344, −1672) → (1200, 800, −1500) → (−100, 125, −500) → (−400, 50, −300) |
inferredThe curve between keys is a cubic Hermite spline whose tangents are the chord slope between neighbouring keys, halved at the two ends. It matches the recorded camera positions to within about 40 units on average.
measuredThe ground texture is also chosen at random each run: snow 9 times in 11; otherwise the web-page picture or the greeting-card picture.
The flying ornaments
measuredTwenty objects are in the scene: the train, and nineteen flyers. The flyers are a candy cane that leaves a smoke trail, two gingerbread men that each drag a string of ten lights, and sixteen random ornaments (stars, sleighs, snowmen, stockings, wreaths, a fish and others). The flyers' rules, read from the program:
| Steering | Every step the heading is nudged one-fifteenth of the way toward the current target, so the sharpest possible turn is about 3.8° a step. We measured the same maximum in the recordings. |
|---|---|
| Speed | Each step, 35 times in 100 the speed is multiplied by 0.988; otherwise 0.17 is added. Speeds drift upward, settling near 26 units a step. |
| Targets | A random point 14,000 units wide, 1,400 high. When an ornament gets within 150 units it picks another. |
| Flocking | About one step in four, an ornament adopts another ornament's target, so the crowd drifts together. |
| Collisions | Two ornaments closer than 25 units both tumble, lose a quarter of their speed and throw sparks. |
| Special moves | Now and then an ornament spins on a random axis for 20 to 170 steps. |
inferredThe decoration of the tree comes from one more rule: an ornament that dips below the ground is moved onto the tree, where it hangs still (speed 0) at a random height on the cone. Hanging ornaments take off again at random, about once every 430 steps. The gingerbread men first circle the tree through a ring of waypoints. That is why the tree is bare at first and fills up over the first minutes.
The camera
measuredAfter the fly-in the camera tracks the candy cane. Once in a while (about once in 1,024 steps) it chooses a new mode from a weighted list. The modes are named inside the program.
| Tracking | 6 in 25. Glides toward the target, closing 1/128 of the gap each step, and holds about 150 units away. |
|---|---|
| Stationary | 7 in 25. Stays put and turns to look at the target. |
| Still | 4 in 25. Parks at (1000, 200, 200) and looks at the target. |
| Trailing | 3 in 25. Rides behind the target. |
| SlowTrack | 3 in 25. Like Tracking but closes only 1/256 of the gap each step. |
| Closeup | 2 in 25. Closes 1/15 of the gap each step and holds 60 units away. |
The program also has Chase, Target and Cockpit views; we have not seen them chosen in our recordings.
The train
measuredA toy train (an engine and four boxcars) rolls on the ground at exactly 8 units a step. It always starts at the same place, (2500, 4, 2600), and in two separate recordings the first 500 steps were the same, so the opening of its route is fixed. It sweeps in toward the tree and then wanders around it. We recorded 2,176 steps of it.
inferredAfter the recorded stretch, the browser version steers the train toward random points near the tree, which is how its route looks in the recording.
Snow, smoke and lights
| Snow | measuredUp to 150 flakes (300 in heavy snow) are created about 3,000 units in front of the camera and fall; wind changes about once in a hundred steps. Four flake pictures are used. |
|---|---|
| Smoke | measuredA pool of 50 puffs, each shown as 16 pictures one after another. The candy cane drops a puff every step, the train's chimney now and then, and collisions throw several at once. |
| Lights | measuredEach light string is ten wire pieces, 76 units apart, trailing behind a gingerbread man; every piece has a glow picture in red, yellow, blue or pink. |
| Colored light | inferredThe pink and blue wash on the snow near the tree in later minutes comes from real colored Direct3D lights following the light strings. The browser version does not reproduce this yet. |
The music
measuredThe program picks a song with rand() % 20, asks Windows to play that MIDI resource, and when it ends picks again. Music can be turned off in Settings. See the music page.
- Where the program uses its short video.
- The exact blinking pattern of the lights, and how the colored lights are placed.
- The details of several ornament states (following, chasing, the ring around the tree).
- How the sky's stars are drawn.
- What the Chase, Target and Cockpit camera views look like in action.
If you worked on the original or have a copy of the source, please get in touch.