Category Archives: Display stuff

Step 3: Adding Assets (images, sound, etc)

Adding sound, video, fonts, etc. to your game

SkeletonGame provides an built-in asset manager that is driven by a simple YAML file format. On game launch, the asset manager will pre-load all the assets defined in config/asset_list.yaml. The asset_list.yaml, associates files (images, animations, sounds, music, fonts, and lampshows) with “friendly” names, and allows for custom settings for each of these items (e.g., change the default volume of a sound, change the x/y position of a sprite). Once these assets have been loaded, they can be used in code or in other locations by referring to their key (alias).

Looking at an example asset_list.yaml (this is the example that comes with SampleGame), we can disect the components expected to be present:

  1. Loader User Interface: The visual layout of the asset loading screen that will be shown while your assets are being pre-loaded (on game launch)
  2. LampShows: a mapping of lamp show file names and logical names (i.e., keys) by which they will be defined. Defining a lampshow in this file causes the lampshow to be parsed and validated during asset loading, so if there is in error in the lampshow you will find out immediately instead of when your code eventually goes to play the lampshow.
  3. Animations: a list of images and animations to be used in your game; minimally their file names and their logical names (i.e., keys). By including an entry the image or animation will be pre-loaded, ready for use in your game’s mode code. Supported formats include the ‘dmd’ format, many common single frame formats: jpg, gif, png (per pixel alpha supported), and some animation formats such as gif (for animated gifs) and single frame file sequences (e.g., a file range from my_image000.png through my_image029.png would be specified with the file name my_image0%3d.png and all 30 would be loaded as the frames of a single animation).
  4. HDFonts: Native system fonts (TTF) and aliases for specific sizes of those fonts
  5. Fonts: Bitmap fonts, based on the PyProcGame font format
  6. Audio, Music, Voice: Audio files named via key (wav or ogg format).

UserInterface — what the loading bar looks like

Settings in this section modify what the user sees when the game is pre-loading assets.

The splash_screen is an image file to be shown underneath the information displayed during pre-load. progress_bar defines the size and position of the progress_bar relative to the overall screen size. In the example above the full-width of the bar is 90% (width: 0.9) of the window, and 10% of the height of the window (height: 0.10). It is centered on the X-axis (0.5) and appears in the top 1/4 of the display. The border color of the bar is a bright magenta color (border: [255, 0, 255] –> means 255 of a possible 255 Red, 0 of a possible 255 Green, and 255 of a possible 255 Blue). The filled portion of the bar as loading progresses is shown as Red.

The text portion defines the color of the text used to indicate which file is being loaded, and the y_center defines the height at which the text will appear.

Those settings together produce the following loading interface for the user; while the text is clearly cut off, thankfully the user only sees this briefly. Note to self: add a font size option!!
preview of loading screen


lampshow files can be pre-loaded on asset load. The key is name by which you will refer to the lampshow files later when you attempt to play them, and the file is the filename, assumed to be located in the path ./assets/lampshows/

The above example loads two lampshow files, each of which has a key that is simply the name of the file without the .lampshow extension. You can find more information about the lampshow format, here

Animations (and Images)

Both single images and animations are defined in a section called Animations: The minimal information for an entry is typically a filename (file:) and an alias (key:). Code can then refer to the asset by the given alias.

file: can be a single .gif, .png, .jpg, or .dmd file, or can refer to a numeric range of files using the %d operator. Three simple examples are given below:

Notice on the third entry (robot) the file there is an additional parameter x_loc which will move the image over 50 ‘dots’ when it is displayed. (y_loc would move the image down, and negative values can be used to move objects in the opposite direction)

Animations as sequences of images:

For example, suppose there are 91 images called explosion1_0000.png through explosion1_0090.png and these images should be treated as consecutive frames of an animation. If all these files are placed in ./assets/dmd/explosion1_64x48/ (just to reduce clutter), specifying the file: 'explosion1_%04d.png' will load a file ./assets/dmd/explosion1_64x48/explosion1_0000.png as the first frame, ./assets/dmd/explosion1_64x48/explosion1_0001.png and so on until the first consecutive file number is not found. You can’t skip numbers in the middle, and you cannot skip the first (0) filename. The %04d means 4 digits, padded with zeros to the left (so 0000, 0001, …). %2d means numbers up to two digits, but without the zero padding, so 1, 2, 3, ..9, 10.

You can also use .mp4 files that contain animations. More documentation about their use is forthcoming.

frame_time: indicates how many times the frame will be shown before it advances to the next frame (note the default system framerate is 30 frames per second, and this can be changed in your config.yaml file). By default, the frame_time is 1.

repeatAnim: indicates whether or not the animation should loop, playing over and over again. If omitted, the default is False. (Notice that True and False are indicated with a leading capital letters, as in Python itself).

compositeOp: 'blacksrc' can be indicated to cause the framework to treat black (0,0,0) pixels as transparent. There is also a 'magentasrc' (255,0,255) and 'greensrc' (0,255,0). For PNG files, per-pixel alpha transparency and whole image alpha transparency is supported, so saving images as PNG files with per-pixel alpha (RGBA/32bpp) eliminates the need for using compositeOp.


The Audio: category allows the definition of music and sounds. Use .wav or .ogg (Ogg Vorbis) file formats. MP3 is not recommended at this time.

The following example should be straight forward.

  • Music files are expected to be found in ./assets/sound/music
  • Effects (sound effects) are expected in ./assets/sound/sfx
  • Voice (call-outs) are expected in ./assets/sound/voice


True Type and Open Type Fonts (ttf and otf) can be used in the framework. The list of the entries of “HD” fonts should occur under the Font category

The key defines an alias for the specific type face and the size of the font when rendered. The font may be specified as a filename or a system name, however using systemName will require a user to install a font onto his/her machine before use, which is far more intrusive. If using filename, the path is assumed to be ./assets/fonts/

Font “Styles”

Font styles may be defined within the font category as well, and should appear at the same depth as the HDFonts category

In the example above there are two styles defined: weird will fill the text rendered in a medium blue ([0,0,128] as R,G,B), has a line_width (aka border) of 1 and the line_color is a reddish purple ([255,0,128]).

SkeletonGame Requirements:

SkeletonGame requires a few conventions in your asset_list, that allow you to tweak/customize certain properties. You must be sure you define a few things:

  • A Font or HDFont named: tilt-font-big, tilt-font-small, settings-font-small, high_score_entry_inits, high_score_entry_msg high_score_entry_letters
  • TODO: Flesh out the complete list, for here!
  • something else that’s vital…

Displays and Layers: basic concepts

PyProcGame display basics

The Mode architecture of PyProcGame allows every mode to provide a display ‘Layer’ to be shown on the DMD. The Layer should be thought of exactly as the Layer metaphor in Photoshop or other image editing software. The Layer family of classes in PyProcGame represent the various container classes for types of content to be displayed on the DMD, and The ordering of the Layers is dictated by the priority of the Modes, with the highest priority mode (largest number) being the top-most layer and the lowest priority mode would be the bottom-most layer (assuming all layers are opaque).

Modes do not always have a visible component, and do not by default. A mode that does have something to show would create a layer by assigning it’s layer attribute (i.e., self.layer) to some specific instance of a Layer object. The type of layer object you create depends on the type of data you want to place in the Layer.

What’s different in the display framework between PyProcGame and PyProGameHD ??

In PyProcGameHD, traditional DMD support has been removed. If you are running a P3-ROC, you didn’t have it anyway, but if you are a P-ROC user, this means you cannot output to traditional 128×32 DMD displays. That said, you can now very easily output full color graphics to a regular video display device (a 1080p monitor, for example).

SkeletonGame specific conveniences (like using YAML to describe fancy layers with minimal code) is described [on this page].

You can use this document to learn the display in “vanilla” PyProcGame –PyProcGameHD “exclusive” layers are indicated where appropriate. Similarly changes to the functionality of some layers was introduced and those are also indicated here. The biggest changes (i.e., things that might cause existing code to not work or behave differently than expected under the new framework) are:

  1. Alpha support: composite_op='blacksrc' is deprecated at best. Instead, every new layer created (Grouped, Frame, etc) is filled with a transparent color –i.e., (0,0,0,0) of the form (R,G,B,Alpha) where Alpha ranges from 0 (invisible) to 255 (opaque). Before, if you created a layer and did not indicate the blacksrc composite_op you would have expected it to be visibly opaque (though not the same as the flag opaque=True which carries a very different meaning for layers). If you’re wondering why you can now see through your GroupedLayer, that’s why. It also means you should probably set that GroupedLayer to have it’s .opaque property set to True which will both stop the lower layers from being visible by preventing them from even being rendered (saving CPU cycles).

  2. Graphical (animations, frames, fonts) assets must be loaded after the display framework has been initialized. What this means, is that any code that initializes a font at ‘global scope’ (i.e., outside a class body) will cause the code to “blow up” –instead, we provide an assetmanager class (defined in and all you have to do is provide a list of assets in the file config/asset_list.yaml and they will be pre-loaded for you when the game is loaded (a graphical progress bar is shown).

  3. Using the assetmanager means that you can refer to an animation (or single frame) by its key via game’s animation dictionary.

Look at the sample asset_list.yaml in the SampleGame/config/ folder. The assetmanager should hopefully make things easier.

Types of Layers and examples of their use:


The simplest of Layers (aside from ‘Layer’ itself) is the Frame layer. This layer is used when you want a mode to show a single image on the dmd. Assuming you already have the image in the correct .dmd format (which can be done using the procgame command-line tools to convert an image to a .dmd, or can be converted from other image formats at runtime). You will need three lines:

Of course, you can consolidate into a single line, if you are so inclined:

In PyProcGameHD you would define the file in the asset_list.yaml and simply refer to the file’s key.
Also, in PyProcGameHD, there is no need to convert animations to DMD format.

The asset_list.yaml might include a few entries. In the following example, an chrome.png is a single image and could be used as the source frame in a frame layer:

The corresponding ‘mode code’ to use chrome as a Frame Layer is:

This is far more complicated than just using the AnimatedLayer object that the assetmanager creates when it pre-loads the content.


The text layer will be used a lot in your games and is the same in any DMD based PyProcGame game. The PyProcGameHD version adds HDTextLayer, and it isn’t drastically different, so we will start with this one.

Typically you will create a textLayer

Many layers support a ‘fill_color’ argument which specifies the background fill to be placed within the
larger layer that contains the desired content. In the regular DMD framework those colors are 0..15,
in the PyProcGameHD framework they are (RED,GREEN,BLUE) tuples with values ranging from 0..255 for each RED,GREEN, and BLUE

There is also a width and height argument that lets you specify the width and height of the layer to be
created. The following example uses width, height and fill_color

Panning Layer (HDVGA Extensions)

Animated Layers

Again, PyProcGameHD and it’s assetmanager should make life easier. It will load the animated gifs indicated in the following examples as animations.

The corresponding ‘mode code’ to use a pre-loaded animation as such, is:

Grouped Layers

Real-world grouped layer

Scripted Layer

Layer from Text

Note: this is NOT supported in the PyProcGameHD Framework!!


Advanced Layers for PyProcGameHD

The following are Layers that are only present in the PyProcGameHD Framework only:

Particle Layer

Rotation Layer

HD Text Layer

Adds borders and interior fill colors

Animated HD Text Layer

Transition Layer

Script-less Layer

Assorted Changes in PyProcGameHD

  1. Added some fixes for when frame_sequences are used. My frame_listeners were not firing when I used frame_sequences, so I added a fix for that.
  2. Added a helper called play_sequence that would play a specific frame_sequence and then revert back to the prior sequence when complete. It makes it more like a traditional animation interface. I also added the ability to send an arg to the listener because I needed that for resuming sequences

  3. Fixed the movie (mp4) layer to work with the new framework. It does now; I’ve tested it.

  4. Added a callback for scripted_layers, so a specified method will be called when that script section is encountered. Example:

  5. Scriptless layer supports callbacks, too

  6. GroupedLayers support a fill_color so that if you want to explicitly black_fill (or something else) you can just specify it here. You can also omit it for the default which is a transparent fill.

  7. PanningLayer supports setting the ‘frame’ content to be any type of layer, so anything can be panned. If you specify a regular frame, well, that still works too. I also fixed some implementation bugs that I encountered with bounce. A ton of testing went on there, so I’d be surprised if any part of that didn’t work.

  8. RotationLayer: a cute toy. Lets you rotate any type of layer. It’s cute.. not very useful but I thought, why not?

  9. I fixed some major placement bugs in AnimatedHDTextLayer that caused them to be positioned incorrectly.

SG: Display Markup Language

SkeletonGame’s display markup language:

SkeletonGame exists to make it easier for you to get your game going. The YAML based display layer markup syntax was intended to make it “easier” to describe complex layer compositions for display on the PyProcGameHD framework, without requiring the programmer to generate code to do so. It was intended just to provide a short hand for a few Layer types. I use it in the attract mode, and it obviously has uses elsewhere too.

It was never intended to become an interface to the entirety of the display power of the framework … but there has been feature creep.

Can I use this in mode code??

Absolutely. Your mode has a layer. That layer is accessible via self.layer –the yaml parser is in the game’s dmdHelper so code such as:

will work, provided yaml_struct contains a valid format, as described below.

The YAML format

Let’s start by taking the canonical example of where this is used and likely to be first encountered, the attract.yaml file. This file starts with a Sequence tag that indicates what follows is a list of layer types that are to be played in, get this: a sequence!

What makes the sequence type “special” is that it augments each of the layer that it contains with three additional tags:
* [Required] duration: –a number of seconds that this layer should be shown.
* [Optional]lampshow: –the name of a lampshow to be played when this part of the sequence is shown on the display.
* [Optional] sound: –the name of a sound to be played when this part of the sequence is shown on the display.

The values for lampshow and sound (if present) should correspond to keys that can be found in the asset_list.yaml file if you expect it to work. Again, every list entry in the Sequence should define a duration

The Sequence contains a list of layers. The following documents the syntax for the layers:

Types of Layers:

Combo: a combination of simple text, shown in front of an image or animation

The Combo layer is the simplest way to get text on the screen The line (or lines) given
to the combo layer will be centered on the display. If multiple lines are specified,
then they will be centered vertically.


In the example above, this entry will show three lines of text (the middle line being blank) drawn
in a Font named med (as defined in the asset_list.yaml). No FontStyle has been specified
(notice the line starts with a # which comments out the line). This text will be shown on top
of some image or animation named dark_chrome which is presumably defined in the asset_list.yaml.

A FontStyle can be defined in two different ways: one, as a string that maps to a key in the
asset_list.yaml –very useful if you plan to use the same style over and over again. The other
way is with an in-line definition. That looks something like this:


Super simple. Show a single frame or animation with a key found in the asset_list. Example:

So we expect to find an entry keyed t800-war in the asset_list.

If you want more control/power, see the #animation# object, later in this document.


An idea from scottdanesi, this is a Combo layer that allows you to specify multiple options
for the text and, at playback, one will be selected at random each time the layer is shown.

Like Combo, it shares Font, FontStyle and Animation tags. What is different is the
Header tag which, if present, will add a line of text at the top of each of the options when
displayed. The list of options are tagged TextOptions which is a list of Text entries,
each of which is a list, of multiple lines of text which might be shown (as in the Combo layer)

This layer has three different options that will be chosen at random, but all
would be rendered in front of the dark_chrome asset, in the small Font, in the
weird FontStyle.


Multiple frames will be generated (a sequence of frames) for each of the system’s recorded
high scores. You can control the Font, FontStyle, a background Image/Animation, and the
order in which the stats appear on the display. Of note, the duration tag here is required
and each of the frames will be shown for the given duration

For example, if there are four high scores and a duration of 4.0, then the entire high score sequence will take 16 seconds.


Multiple frames will be generated (a sequence of frames), one for each of the player’s score from the last game played. You can control the Font, FontStyle, a background Image/Animation. The duration tag again is used to indicate how long each frame is shown. If this is the first launch of the game and there was no immediate prior play, then this frame will not be generated.

“power” layers

The following layers are actually quite powerful and flexible. They are indicated by lower case layer names and the _layer suffix naming convention.

All of the _layers that follow provide the user with the optional ability to specify the x and y location (relative to the top left corner of the display and the image) as well as a width and height.

These values are specified in a fairly flexible format:

  • if a positive int is specified, the value is taken as-is
  • if a negative int is specified, the value is taken as offset from the relative value (e.g., for x or width, this is the width of the DMD display)
  • if a float is specified the value is taken as a percentage of the relative value (e.g., 0.25
    is 25% of the display width, in the case of width or x)
  • if a string value matching the key is specified, the relative value is returned
    (so specifying width: width has the same effect as specifying 1.0 as 100%)

When width and height are omitted, the framework will try to compute the values on its own. This may be incorrect in certain pathological cases. When something seems amiss and you cannot see the entirety of your layer content, you may wish to set these values as width:width and height:height just to check.


The Name: tag remains from the Animation layer, however the animation_layer provides quite a bit more control over the animation playback.

The following tags are supported to adjust the specific settings for this play-through of the animation:

  • [Optional] hold_last_frame: If True, the last frame will be held if the animation is shown for longer than the time it takes to play all of the frames. The alternative (i.e., False) is that a blank frame is shown. If unspecified, the default value is the opacity set in the asset_list

  • [Optional] opaque: When True the player can see through this frame (not terribly useful unless the animation has transparent pixels and is part of a group). If unspecified, the default value is the opacity set in the asset_list

  • [Optional] frame_list: A list of frame indices to be shown. For example a value of [0,1,2] would only show the first three frames of the named animation. A value of [0] would only show the first frame. A value of [-1] would only show the last frame.

The following example shows only the final frame of the animation found in the asset_list with key intro:


This layer exposes the ‘MarkupLayer’ provided in PyProcGame, however this has been updated
for HD functionality. This layer is commonly used as a “Special Thanks To:” layer, or to provide a large amount of text, as it supports multi-line text and some basic formatting (two different font styles, left justify, right justify, and centered text, all on the same layer). This does
not support an animation tag for a background. If you want one, you’ll have to provide your own
through a group_layer. Similarly, it does not scroll/pan. If you want panning, you will need to enclose this layer in a panning_layer

In the example above, notice that two Fonts are defined: Bold and Normal
Lines with a [ are rendered in Normal Font & FontStyle, and those with a # are considered Bold. Lines that have style indicators at the start and end of the line of text are
centered. An indicator only on the left indicates the line is left justified. An indicator
only on the right means the line will be right justified. width can be used to control
the width of the rendered frame.

The final entry in the list, is surrounded with curly-braces. The markup layer will replace that element with an inline drawing of the first frame of the animation/image with key matching some-logo in the asset_list.


This layer exposes the PanningLayer provided in PyProcGame/HD. It provides the ability to
scroll/pan the layer that it contains.

The origin_x and origin_y represent where the layer will start on
the display. This allows the layer to “scroll into view” starting from off screen. Similarly scroll_x or scroll_y can be specified as zero to not move or negative to scroll left or up. frames_per_movement is how many frames need to pass (w.r.t. frames per second) before the next scroll_x and scroll_y are added to the layer’s current location. If True, bounce indicates that the layer will start moving in the opposite direction if it hits the edge of the display.


This layer allows you to group multiple layers just as the PyProcGame GroupLayer does in code.
The contents are a list of other layers (potentially including other group_layers if you really want to)

Items in the content list are added “bottom up” so the first item will appear beneath the next item, which appears beneath the next and so on…


About as fine-grained as you can get, the text_layer is the mechanism to describe a single
line of text for the display. Sure, it supports Font and FontStyle, and there is a slight
change in the use of Text to describe a single lines worth of text, however you can also
specify relative x, y, v_justify (vertical justification, either top, bottom, or center), h_justify (horizontal justification, either: left, right, or center), width.

In addition, a blink_frames tag can be added to specify a periodicity at which the text will appear/disappear. For example, blink_frames:15 would cause the text to appear for 15 frames then disappear for 15 frames (and that cycle would repeat). At 30fps (depending on your config.yaml) this is half a second on, half a second off.

Examples go a long way: