A Tour of the Adobe Director File Format

nosamu
22 min readOct 25, 2019

--

A Macromedia Director 5 Movie, displayed in a hex editor.
A Macromedia Director 5 Movie, displayed in a hex editor. You’ll learn all about the chunks visible here!

Anthony Kleine, known online as Tomysshadow, has amassed expert-level knowledge of the Adobe/Macromedia Director Movie file format. In our recent text conversation, he gave me a great rundown of this knowledge. Because the details were so fascinating to me, I decided to condense and edit his messages into a set of “lecture notes.” And if you’d like to delve into more of the details, I’ve provided helpful links at the end of the article. The Director file format can feel dizzying in complexity, but this article is the best place to begin. So let’s get started!

Introduction

The first thing is to just ignore Shockwave Movies (.DCR files) for the time being and focus on Director Movies (.DIR) since you need to understand Director Movies before you can understand the Shockwave Movie format.
Director Movie Files use a RIFX container. This format has a long history, beginning as the default multimedia format of Windows 3.1. If you’ve looked at a lot of archive formats before this is likely par for the course for you. The file consists of Chunks, each beginning with a ChunkID (taking the form of a FourCC.) It’s similar to a RIFF container, like what WAV uses, except that RIFX containers can either be little or big endian. If the file is big-endian, it will begin with the ID RIFX. If it’s little-endian, it will begin with the ID XFIR. Whether the file is little or big endian depends on the processor of the computer that saved the file, but Director is always capable of opening files of either endianness. All Director versions before 11 were not designed for Intel Macs and that’s why they save big-endian files.

For the purposes of learning the format, it can be easier to inspect big-endian files since that way, not everything will be backwards and you can acquaint yourself with the format better. However, since Windows uses an Intel processor it will save little-endian files, so you may want to search around for a game made on the Mac for some files that will be easier on the eyes. Note that saving one of these files on Windows with a tool like dirOpener or Movie Restorer will swap the file’s endianness.

The Structure

Alright, so let’s actually talk about the format structure.
The first thing in the file is its ID (RIFX or XFIR) followed by the length of the container as an INT32. Then we have the codec (in the case of most Director movies, this is MV93, which is short for Movie 1993, the year of the specification.)

Director Movie Files can have a variety of Chunks, but the first one is always the Initial Map, with a ChunkID of imap. (note: Initial Map is just a guessed name, since we don’t know for sure.) The Initial Map has the absolute address of the Memory Map in the file. I’ll explain why the Initial Map needs to exist in a bit.

The most important value (for our purposes) in the Initial Map is the second INT32, which is the Memory Map’s Position. The Memory Map is a Chunk with a ChunkID of mmap. It is an array which lists all of the resources in the Movie in order. Its job is what it sounds like — if you’re familiar with the PE format, think of this kind of like the sections of an EXE. The purpose of the Memory Map is to say where resources are in the file and their size, so that they can be loaded into memory.

You might be wondering why the Memory Map needs to exist, when it’s easy to just loop over the sections yourself by using the RIFX format. Well, it’s actually to serve as a performance optimization. You see, when you delete a resource in Director, it does not actually get removed in the Director Movie File — because if it did, everything after that resource in the file would need to be moved to earlier in the file, which would make saving take longer. To get around this, when you delete a resource in Director, it does not get deleted from the Movie File — instead, the pointer to that resource is made null in the Memory Map. This is akin to “deleting” a chapter of a book by not mentioning it in the Table of Contents. It’s much faster to erase one line in the Table of Contents than it is to remove all of the actual pages.

This does pose a problem however. If you add a lot of resources, the Memory Map gets long enough that nothing can be fit onto the end without moving every other resource later in the file. So, this is the purpose of the Initial Map. If the Memory Map gets too long, a brand new, longer one is created at a different location, and the Initial Map now points to the new one. This effectively makes it so every time you delete something in Director, the only thing that actually has to be changed is the pointer to it, rather than deleting the actual resource itself. The upper limit on how big an mmap chunk can be is the maximum size of an INT32, which is pretty big.

Before we go any further, we need to talk about ResourceIDs. A ResourceID is the index of a resource in the Memory Map. (Remember that The Memory Map is an array.) So for example, the first resource in the Memory Map is the RIFX Container, so it has a ResourceID of 0. The second is the Initial Map so it has a ResourceID of 1. This goes up to the last element of the Memory Map, whose index will never be greater than the maximum INT32. This upper limit allows Director to store ResourceIDs as INT32s.

But remember, INT32s are signed! So what does Director do with all those negative numbers? They don’t go unused — Director uses negative ResourceIDs to refer to resources that it has built in. For example, let’s say you have a palette resource. If the ResourceID is 57, 103, 472, or any other positive number, that refers to a resource in the Memory Map, since it’s an array indexed from 0 upwards. Meanwhile, a ResourceID of -100 might refer to the Windows system palette, -101 the Mac palette, and so on. Director can use those numbers because they aren’t positive, and they can’t possibly be in the Memory Map, because that array starts at 0 and goes up.

Another thing I should mention briefly before we continue is that Director never truly “reads” Chunks. The Chunks are actually just dumps of the state of Director’s memory in various places at the time of saving. When opening the file, the Chunk’s data is simply copied back into memory without being read/parsed.

So to be clear, all chunks are actually memory dumps. Which is why finding out how they are read is so difficult. It’s not like they are all read in nicely with something like readInt32 for example. Instead, it’s more like they are a bunch of C++ structs and Director simply creates one of these structs and points it to the Chunk. That makes it so only when the properties are actually used can you find out what they do.

So if chunks are just loaded directly into memory, you might think you could you use a tool to watch how Director’s memory changes. But surprise! Director uses a custom heap manager (specifically, SmartHeap). Windbg is totally useless! You’re better off opening a file, changing something, then saving the file and seeing what changed in a particular Chunk, which you can of course do anyway. The problem being, a bunch of other irrelevant values will also change because that is the nature of just dumping sections of memory.

Key Mapping Pointers

Anyway, so far, here is what the format looks like:
RIFX Container -> Initial Map -> Memory Map
It’s also worth noting that the resources in the Memory Map are not necessarily in order by address. In fact, most of them are not in any particular order at all. However, the first four resources of the Memory Map must always be the same. The first, second and third are the aforementioned RIFX Container, Initial Map and Memory Map (yes, the Memory Map does reference itself.) The fourth is the Key Mapping Pointers (an inferred name), which has a ChunkID of KEY*.

Okay, so we have the RIFX Container, which has the Initial Map, which we can use to find the Memory Map. The next thing we need to do is find the Key Mapping Pointers with a ChunkID of KEY*. This is always the fourth resource in the Memory Map, which is how we find it. The Key Mapping Pointers Chunk is probably the most difficult Chunk for beginners to understand. It allows an “owned by” relationship to exist between resources. For example, Sound Headers and Sound Samples can be “owned by” a Cast Member. The Key Mapping Pointers chunk has an array, each element of which consists of two ResourceIDs and one ChunkID. A ResourceID is the index of the resource in the Memory Map. (Remember that The Memory Map is an array.) So for example, the first resource in the Memory Map is the RIFX Container, so it has a ResourceID of 0. The second is the Initial Map so it has a ResourceID of 1, and so on. The first INT32 is the ResourceID of the owned Resource. The second INT32 is the ResourceID of the owner Resource. And then there is the ChunkID of the owned Resource.

Now, here’s how this actually works. Let’s say that Director encounters a Cast Member, and it is a sound. So Director knows that this Cast Member owns Sound Headers and Sound Samples. So it will search every Key Mapping Pointer, until it finds one with both the ChunkID it is looking for, and the ResourceID of the owner Chunk (since it already has the owner chunk, and is looking for the owned one.) Sound Headers have a ChunkID of sndH, so it’ll stop when it finds one that has a ChunkID of sndH and is owned by the Cast Member it knows is a sound. From there, it will get the ResourceID of the Sound Headers, which it can then use to find those Sound Headers by using the Memory Map.

This sounds really complicated, but it’s simple in reality. It’s just a table where you plug in two things you do know (the owner, and what you’re looking for) in order to find one thing you don’t know (the owned chunk). This is important to understand, because after you’ve found the Initial Map, and then the Memory Map, the Key Mapping Pointers is what we will use to find everything from here on out. This is because there are some chunks which are owned by the Movie itself, which always has a ResourceID of 1024.
I don’t know why they chose 1024. I just know that looking at Director in IDA, it is a constant and that constant is 1024.

Now, there is one other very important aspect of ResourceIDs, which is that they are not exclusive! You see, the Movie always has a ResourceID of 1024 — but there can be more than 1024 Resources in the Memory Map. So what happens if you have 1024 Resources in the Memory Map? Does the 1024th one become blank, as to not be confused with the Movie? Well, no — if you have 1024 sound Cast Members, for example, in the Memory Map, the 1024th one will in fact be a sound Cast Member. But, here’s the thing — when it looks in the Key Mapping Pointers for a resource that is owned by another one, it is looking for a particular resource. For example, with sound Cast Members, Director will only look for Sound Headers and Sound Samples. So it’ll only consider the resource owned by the other one if it both has the ResourceID of the owned chunk AND also the ChunkID of what it is looking for (sndH or sndS). Both the Movie and the sound Cast Member can have the same ResourceID, because when Director looks for resources owned by the sound Cast Member, it’ll only look for sound-related stuff, and ignore the movie-related stuff. As a result, certain Resources can only own certain other types of Resources, otherwise there would be a conflict. This is because a ResourceID is not like a primary key — it’s not exclusive to one resource alone.

What Belongs to the Movie?

So, let’s talk again about opening our movie. The first thing we do is open the RIFX Container, the Initial Map leads us to the Memory Map, which leads us to the Key Mapping Pointers. Now, Director is going to find a few things that the Movie owns, and it can do this because the Movie always has a ResourceID of 1024.

The first thing it needs to find is the Config. Depending on the Director version, the Config will either have a ChunkID of VWCF or DRCF (which is short for VideoWorks Config and Director Config respectively.) Director Configs are exactly the same as VideoWorks Configs though, only the ChunkID is changed and Director will always search for either. They didn’t change it from VWCF to DRCF until around Director 6, though even Director 12 checks for both of them. If a Movie has more than one Config it causes undefined behaviour. (This was actually a CVE at one point because having more than one Config could cause heap corruption.)

The Config, as you might imagine, has some basic properties about the movie itself. This includes the version number, stage size, background colour and etc. In older Director versions where only one Cast was allowed, Cast Properties were also stored here, but now they are stored somewhere else. Also, it’s worth mentioning that Config is not actually a guessed name, as it is one of the clipboard types registered by Director, so we know this is its official name.

The next thing that is owned by the Movie itself is the Cast Properties, which has a ChunkID of MCsL (which is short for Movie Cast Libraries.) This Chunk was introduced in Director 5 to allow Movies to have multiple Casts. The Cast Properties, which used to be a part of the Config, were moved here. This is a list which has the names, filenames (if external), minimum and maximum member number (will touch again on this in a moment), number of members, and most importantly, ResourceIDs of the Casts. That’s right — Casts have ResourceIDs too! And again — they’re not exclusive, so it can be the same ResourceID as anything else.

Another resource owned by the Movie is the Sort Order chunk. This is an array of INT32s, each of which form the number property of a Cast Member. Each INT32 is really made up of two INT16s: the two most significant bytes of each INT32 represent the Cast’s index, and the two least significant represent the Cast Member’s index. The number property allows Director to match Cast Members to slots in the Cast window, regardless of where the Cast Member resources actually are in memory.

This is where the minimum and maximum member number come in! Remember how the Cast’s index is represented by an INT16? This explains why the maximum number of Cast Members per Cast is 32000 — I’m certain it’s just 32768 rounded down. The minimum member number (minMember property) also shows something interesting about Director. For example, if the first ten members of a Cast are blank, Director can avoid having 10 null slots in the Cast Mapping Pointers where the empty Cast Members would be. Instead, Director actually treats the 11th member as the first one internally, and adds the minMember to it to pose the illusion to the author that it is the 11th.

Another thing that belongs to the Movie is the Score. The Score has a ChunkID of VWSC (which stands for VideoWorks Score). Note that this Chunk abbreviation was never changed from VW to DR (in fact, Config is the only chunk that did change in this way).

The format of the Score is probably the most varied thing between Director versions. Unlike the Cast, which consists of many different Chunks, the Score is entirely one chunk. It is also easily the most ridiculously complex, so much so that I’m not going to explain it in too much detail. One thing to note however is that the first five channels are always dedicated to timing, transitions, sound 1 & 2, and scripts.

The thing is, what you see in a Director Movie File is actually lightly compressed (at least in Director 8.5 which is the primary version I inspected). The Score actually pads all the channels to a certain length in memory, but if they were saved in the file that way it’d be mostly blank, so it is actually modified to have a pretty stupid RLE implementation before saving.
It’s sort of like MIDI — it says which sprites are on which frame. Having more channels requires more memory, because like I said, in memory they have a fixed width. This means that the majority of the memory describing the Score is likely to be blank, but it comes with the performance optimization of always being able to know exactly where a particular sprite is in memory. This can be quite inefficient for movies that skip a lot of channels. If Director didn’t implement RLE compression, Director Movie Files would probably be much larger because of the Score alone. Or at least, it does use more memory. But for the CPU, of course, it will very much improve performance.

Note that what I am saying here does not apply to all Director versions. Like I said, it changed a lot, especially from Director 4–7. What I am explaining mostly applies to Director 8.5 and onwards, and I haven’t really looked into Director 7 and below. ScummVM does support some of those versions if you want a reference.

Anyway those are the main things the Movie owns. It does also own some other uneventful Resources. For example, your Favorite Colors (FCOL), FileInfo (VWFI), Guides and Grid (GRID), some of which are only accessed during authoring. For example, Favorite Colors allow you to choose some colours that will always appear in a colour picker.

Where are the Cast Members?

Alright, back to the Cast. Here is an updated summary of the file structure so far:
RIFX Container -> Initial Map -> Memory Map -> Key Mapping Pointers -> Cast Properties

Now, the ResourceID of the Cast is important. This is going to allow us to find Resources owned by the Cast.
And those Resources are the Cast Mapping Pointers, Lingo Context, CastInfo, and Score References.

One of the craziest things is when you have a Director movie as a cast member. I’ll have to talk about that, but not yet.

The Cast Mapping Pointers chunk has — guess what — more ResourceIDs! These are actually the ResourceIDs of the Cast Members in order, with any blank spaces being null. Finally!

So we open the RIFX Container, use the Initial Map to find the Memory Map, which we use to find the Key Mapping Pointers, which we can use the ResourceIDs from in conjunction with the Memory Map to find the Cast Properties, which gives us the ResourceID of the Cast, which we then use with the Memory Map again to find the Cast Mapping Pointers, which gives us the ResourceIDs of the Cast Members, which we use with the Memory Map to find the Cast Member’s chunks. You got all that?

This is years. This is years of research here. I don’t expect anyone to understand it in a day, to be honest.

But anyway, that’s how you get at the Cast Members. What about Lingo?

Getting the Lingo

The Cast also owns the Lingo Context, which has a ChunkID of Lctx. Each Cast has its own Lingo Context. The Lingo Context has the ResourceID of the Lingo Names, and the ResourceIDs of the Lingo Scripts. Those have the ChunkIDs of Lnam and Lscr, respectively. The Lingo Names have strings which can be turned into symbols, such as “go” or “alert”. These strings are used across the multiple Lingo Scripts owned by the Lingo Context. The format of the Lingo Names is simply a bunch of C Strings back to back.

Now, this is why you can’t have a Lingo decompiler without being able to read the rest of the format. You can’t even get here without finding the Casts, which you can’t get to without finding the Key Mapping Pointers and everything else before it. You also can’t use the ResourceIDs in the Lingo Context to find the other Lingo-related Chunks without having the Key Mapping Pointers and Memory Map at the ready.

So the chunks are dependent on one another. Without the Lingo Context, what you effectively have is the scripts without symbols, but the symbols are very important to the decompilation! You can’t properly read the Lscr chunks without knowing which Lingo Names belong to which Scripts.

Now, remember how I said that these chunks are all just dumps of Director’s memory? If you look at a Lingo Script chunk, it might seem a bit perplexing, because there seems to be quite a few values that are repeated or unused
This is because the Lingo Script chunk has a buffer that is normally empty, but this buffer is used as the stack during playback. Once loaded into memory, the Lingo Script chunk is used to track the state of all aspects of the Lingo Script. If you’re thinking of it like a struct — you could have a Lingo Script, with a <std::vector> stack, as an example.

The Lingo Script chunk has quite a few numbers in it. Importantly, the Lingo Script has the ResourceID of the Cast Member it’s for. The Lingo Scripts are not actually owned by their Cast Members — they don’t appear in the Key Mapping Pointers. Instead, the Lingo Context belongs to the Cast, and the Lingo Scripts state which Cast Member they are for. This means that you cannot find out which Lingo Script “belongs” to a Cast Member. You can only do the reverse — find out what Cast Member a Lingo Script is for.

Also, the scriptText is NOT stored in the Lingo Script chunk. Everything in the Lingo Context and below is bytecode related. The scriptText is a property of the Cast Member. That said — I’m not sure how something like Parent Scripts work. That is still an unknown to me.

Anyway, so that’s where you find Lingo — it belongs to the Cast, for which the ResourceID is found in the Cast Properties, which belongs to the Movie.

Cast Member Types

But! I still haven’t talked about all the Cast Member types! There are a ton of them, but Director supports 15 major ones.

They are:
1. Bitmaps
2. Film Loops
3. Text
4. Palettes
5. Pictures
6. Sounds
7. Buttons
8. Shapes
9. Movies
10. Digital Videos
11. Scripts
12. Rich Text
13. OLE
14. Transitions
15. Xtras

Let’s explain them all one by one. The important thing to understand is that Cast Members can own media as separate resources. The Cast Member itself is, again, like a struct — it has a bunch of properties describing what the Cast Member is. But the media is a different Resource — which is found by plugging in the ResourceID of the Cast Member into the Key Mapping Pointers.
Cast Members have a ChunkID of CASt.

The Bitmap is the first type of Cast Member on the menu. They can own Bitmap Data (BITD,) Editable Media (ediM,) and an Alpha Channel (ALFA) in the event the bitmap is compressed as JPEG in a Shockwave Movie. (This will only actually appear in a Director Movie File when using dirOpener on a Shockwave Movie since it’s not compressed to JPEG until after exporting.)
The Bitmap Data (BITD) is what Director treats like a BMP file. It is losslessly RLE compressed, which Director refers to as Standard compression. They can have a variety of bit depths, and may or may not rely on a palette. Bitmap Data is just the raw colour data. All of the other properties like width, height, bit depth and palette to use are part of the Cast Member which owns the media. This is another case where one Resource depends on another. You cannot render Bitmap Data without having the Cast Member that owns it first. This is because the width and height of the Cast Member doubles as the width and height to use when reading the Bitmap Data.

The Editable Media (ediM) Chunk is created if you choose from the Media dropdown to keep an editable version of the file on import. This just copies the contents of the original imported file literally. This means that when you choose to export the bitmap into an external editor, if you choose this option it will actually export the original file. Director will also reflect this in the external editor window, which will say JPG or PNG etc. in place of BMP, which is the Bitmap Data’s equivalent. When publishing as a Shockwave Movie, if you choose to compress to JPEG, the Bitmap Data is replaced by an Editable Media chunk with a JPEG image, and an Alpha Channel chunk (ALFA) to preserve alpha transparency despite being in JPEG, which is simply a map of the alpha channel.

Film Loops are the next type of Cast Members. They can own Film Loops, which have a ChunkID of VWCS. You will notice that this is just the ChunkID for the Score with the S and C flipped. Film Loops use the same format as the Score, and are actually just a Score which is owned by a Cast Member. That’s why during Director authoring, you can paste a film loop into the score as its original score data.

However, If they are the same format as the Score — why is the ChunkID different? Well, remember, ResourceIDs aren’t exclusive! If the ChunkID for a Film Loop was the same as the Score, then if a Cast Member were the 1024th Resource, there would be a conflict because that ResourceID would have two Scores associated with it! So they are the exact same, but they have a different ChunkID to avoid conflicting with the Movie Resource.

Next we have Text members. These are the basic Fields/Styled Text introduced in older Director versions. There are a variety of differences between this type and Rich Text. Rich Text is more similar to, well, RTF. This is a simple text member that isn’t as customizable. The main big difference between Text and Rich Text is that Text is rendered on the fly, while Rich Text is rendered to a bitmap. This means that Text can be edited during playback, but if the user doesn’t have the correct font installed it’ll fall back on something like Arial. Rich Text is rendered to a bitmap during authoring so it’ll display correctly no matter what, but can’t ever be changed during playback. The difference between Text and Rich Text during authoring is a lot like the difference between TXT and RTF. Text Cast Members own Styled Text media (STXT).

Next we have Palette Cast Members. These are fairly self explanatory. They can own Photoshop CLUT media (CLUT). These are Color Lookup Tables for a palette. If a Bitmap Cast Member depends on a custom palette, it will have the ResourceID of one of these Palette Cast Members. Otherwise, the Bitmap will use a negative number to refer to one of Director’s built-in palettes. Remember that this is possible because a ResourceID is an INT32, and a positive value refers to a resource defined in the movie, while a negative value refers to a built-in resource.

Then there are Picture Cast Members. This is a Macintosh PICT copied into the Movie file, just look up Macintosh PICT.

Then there’s Sound Cast Members. They can own Sound Headers (sndH) and Sound Samples (sndS.) They are exactly what they… sound like. Lossless, uncompressed PCM samples. They can also own Macintosh Sound Resources (snd) if importing a Macintosh Sound file. Sound Headers and Sound Samples (sndH/sndS) are Director’s WAV equivalent.

Note that in early Director versions, AIFF was the only cross platform external sound file format. External sound files were generally used when internal sound cast members would take up too much memory. As such, authors would often opt to play an AIFF file. External WAV files could only be played on Windows and external Macintosh Sound files could only be played on Mac.

What we have next are Button Cast Members. These actually also own Styled Text (STXT) media. The only difference between these and Text cast members is that they have a button look. In fact in the Director API both Text and Buttons use the exact same rendering subroutine.

Next there are Shape Cast Members which, in older versions of Director, owned Vector Shapes. In newer Director versions the rendering of these is just relegated to the Flash Xtra. As such, they own Xtra Media (XMED)

Then we have Movie Cast Members. A movie Cast Member is a Cast Member which can own… well… anything a Director Movie can own. When importing a Director Movie as a Cast Member, everything that Movie owned now belongs to the movie Cast Member. The Score of said Movie is changed to a Film Loop, again to avoid conflicts with the actual Movie. Everything the Movie owned is then added to the current Movie’s Memory Map and Key Mapping Pointers appropriately.

Digital Video Cast Members can only link to external video files, so they can’t own any media within the Movie. There are lots of digital video types, which all use different Xtras. Despite being considered a “native” type, even QuickTime cast members use an Xtra. In fact, there are quite a few “native” types that actually use an Xtra. Even bitmaps rely on JPEG Agent when publishing to a Shockwave Movie, for example, and sounds rely on Shockwave Audio in the same situation. And text relies on the TextXtra. But around Director 4–5 that was much less the case. Director 4 didn’t even have Xtras yet, only XObjects. I think that if they designed Director today they just would’ve used Xtras for everything from the ground up.

Lingo Script Cast Members, as discussed earlier, don’t own any resources either. This is because Lingo Scripts are not media. They belong to the Lingo Context, which belongs to the Cast, not individual Cast Members. Lingo Script Cast Members don’t have anything distinct about them aside from that you can select what types of scripts they are.

The scriptText is a little bit different. This is the code typed in the Script window, not the compiled bytecode. When a movie is protected, all of the scriptText is completely removed, and this is why we use decompilers! Anyway, the scriptText is a property of the Script Cast Member. Like other Cast Member properties, it is ingrained into the Cast Member itself. It is not a separate resource owned by the Cast Member.

Rich Text Cast Members are basically Cast Members which can have many more text styles, and notably are rendered as bitmaps during authoring. They own three Resources, with ChunkIDs of RTE0, RTE1 and RTE2 respectively. These represent the same thing but in different forms (which is really true of all Cast Member media — same thing in different formats applicable to different situations). The first is the actual style runs, the second is a plaintext version to be used by thumbnails and scripts, and the third is a bitmap render. I’ve talked about this before so I’m not going to reiterate in too much detail.

Next we have OLE Cast Members. I’m going to admit I don’t know what these can all own. I think they can own Bitmap Data as a render of themselves, but honestly I’m not sure. They can however own OLE Data (OLED). OLE cast members are often used to display documents such as excel spreadsheets. OLE is actually a Windows thing — it’s commonly used in other applications like MS Word. It is built on top of COM and allows importing a variety of objects that support it. Both Rich Text and OLE were introduced in Director 5.

The final type is Xtra. Which can be, well, anything! The Xtra itself defines what the Cast Member type is called in this case. Any other type Director supports is going to be via an Xtra.

Phew… and there you have it! I probably didn’t even cover half the chunks to be honest, it’s a tonne. Like, I didn’t mention Score References, which are owned by Casts. They ensure that an error occurs if External Casts are modified from what the movie expects. There’s a lot of unremarkable or only barely important chunks that are easy to forget exist, but this is the basic format rundown.

I didn’t even cover Shockwave Movies. We’d be here for another four hours probably.

I hope you found this information as interesting and valuable as I did! If you’d like to learn even more, here are a number of additional resources:

  1. Kleine, Anthony. More Director Movie File Unofficial Documentation.
    https://docs.google.com/document/d/1jDBXE4Wv1AEga-o1Wi8xtlNZY4K2fHxW2Xs8RgARrqk/edit
  2. Team Earthquake Guide: Shockwave Unofficial Documentation and XDK Director Properties.
    https://docs.google.com/document/d/18FMRZ0EvR2uF9rKTtvt-TXyIMFIBVg13bUhmV3_iHD0/edit
  3. Archive Team contributors. Lingo bytecode.
    http://fileformats.archiveteam.org/wiki/Lingo_bytecode
  4. ProjectorRays Shockwave Decompiler.
    https://github.com/ProjectorRays/ProjectorRays

--

--

nosamu

Former administrator at BlueMaxima’s Flashpoint, Discord community manager at Ruffle. I enjoy writing about technology and its history.