Winamp Skins Development Tutorial

by Kevin Farnham
December 7, 2007

My recent article "Winamp Sings a Brand New Song" introduced the Tenth Anniversary Edition of Winamp, version 5.5. In this article, I talk about the components that make up a modern freeform Winamp skin, and demonstrate the step-by-step development of a skin.

Winamp Skins

A Winamp skin is a graphical user interface that permits a Winamp user to control the operation of the program. Winamp reads a set of files that define the skin, creates the specified graphical images, configures mouse events for the regions defined as buttons, and responds with the actions that are identified for each control image.

Clearly, the Winamp skins API permits an unlimited number of skin designs. As you'd expect, when you go to the Winamp skins page, you find that thousands of Winamp skins have already been created.

Examples: Some Popular Skins

On the left menu bar of the Winamp skins page, there are options for browsing skins by category. You can browse skins with themes such as Computer/OS, Games, Movies/TV, Nature, Sports, and Transportation. Sixteen different categories are defined. In addition, the Skin Snapshots sections lets you look at:

  • Featured skins
  • Just added skins
  • Top rated skins
  • Most downloaded skins
  • Recently modified skins

Clicking on Most Downloaded Skins, you see that the three most downloaded skins have been downloaded a total of more than 32 million times!

Skin Name Image Downloads
MMD3 MMD3 19,714,988
Nucleo_NLog_v2G Nucleo_NLog_v102 8,530,329
ZDL GOLD STACK ZDL_GOLD_STACK 4,653,372

Winamp Modern/Freeform Skins Development

What does it take to create your own Winamp skin?

A look at the Winamp Create a Winamp Skin page shows you the basic requirements for creating a Winamp skin. In this tutorial, I'll focus on modern, freeform skins, which are the skins that work with current versions of Winamp. Freeform skins are developed on the Wasabi platform.

The Winamp modern skins tutorial page explain why, if you create a Winamp skin today, you should create a freeform skin:

Modern (aka freeform) skins offer authors a tremendous amount of flexibility by allowing authors to change the player's shape, size, layout, and function.

What do you need, in terms of skills and software, to create a freeform Winamp skin? The primary skills are some graphic design ability and knowledge of HTML and XML, plus the software tools that enable you to work with these technologies. In my case, for my graphics work I used an old version of Paint Shop Pro that I've been using since the 1990s; and for my programming I used a plain, vanilla text editor.

Winamp Freeform Skin Components

A Winamp freeform skin consists of, at minimum, a set of XML files and image files, stored within a directory structure. At the top level in the directory, there is a skin.xml file, which defines a set of XML resources. These resources will typically include custom files (stored in a subdirectory named xml), and may also include resources that are made available to skin developers through the Winamp download; for example, the Equalizer resource (eq.xml).

XML

Hence, understanding a bit about XML is critical if you're going to create your own Winamp freeform skin. There are many good XML tutorials available, so I won't go into a detailed description of XML here. For developing a Winamp skin, you don't have to know anything about the more complex aspects of XML, like XML stylesheets or parsers. For a basic introduction that will give you everything you need to know to use XML in creating a Winamp skin, take a look at the W3 Schools XML Tutorial. Going as far as the XML Elements and XML Attributes sections should give you a basic understanding of the aspects of XML that are important for developing a Winamp skin.

Graphics

Every Winamp player must have buttons to control player actions. Typically, the following actions are defined:

  • PREV: Go to previous song.
  • PLAY: Play or resume playing the current song.
  • PAUSE: Pause the current song.
  • STOP: Stop playing.
  • NEXT: Go to the next song.
  • EJECT: Exit this playlist.

For each of these, you'll need an appropriate graphic that will serve as a button the user clicks in order to make that action happen. Typically, developers apply images that are similar to the buttons on standard physical music devices (CD players, etc.).

In addition, you may want an image to use as the background for portions of your player. This background image can give your skin its own unique look and feel.

Positioning

Images, for example those that represent buttons, are positioned on the background player canvas using x and y locations relative to upper left corner of the background canvas. Hence, a position of x="20" and y="10" positions the upper left corner of the image 20 units to the right and 10 units below the top left corner of the canvas container.

Relative positioning is also possible, but for beginners it's probably simplest to stick with absolute positioning.

Groups

Defining groups provides a convenient means for moving a group of user interface items as a unit. For example, you could define a "control buttons" group, and place all of your buttons into that group, with their positions defined with respect to the upper left corner of the group's canvas. Then, you can position that group anywhere on your player background canvas, in effect moving your entire set of preconfigured buttons as though they were rigidly linked together.

I'll talk more about positioning and groups below, when I demonstrate how I created my own first Winamp skin.

Advanced Features Overview

The potential for creating very elaborate Winamp skins exists, and many developers have taken advantage of these capabilities in producing some of the most popular skins. For example, you can make non-rectangular players, work with layers of images, apply animations, and much more. The sky really is the limit.

MAKI Scripting Overview

To help you really appreciate what I mean, let's take a brief look at Winamp MAKI scripting. "MAKI" stands for "Make A Killer Interface." Here's how Ken Chen describes MAKI scripting in his "Winamp 3: Skinning Tutorial Webpage" PDF document:

  • MAKI is a scripting engine for creating custom behavior from a Wasabi skin and set of components.
  • MAKI scripts are precompiled into cross-platform bytecode. This means that the set of skin XML, elements, and compiled scripts are completely cross-platform.
  • Scripts can attach to any event of any object in the UI. Scripts can be loaded and unloaded in any order.

In other words, Winamp is actually a user interface development platform. You can apply the MAKI scripting language to do almost anything you could possibly want to put into a music player's GUI.

Clearly, we can't go deeply into MAKI scripting in an introductory Winamp skin development article, but it's important to recognize that the capability for significant highly creative UI development is there.

Demonstration: Coding a New Skin

Now, let's roll up our sleeves and develop an actual Winamp freeform skin.

As I was scrolling through some of my digital pictures, I found this cute picture of our cat, Merlin, acting crazy (as is normal for him):

MerlinSkinBkgd

So, I figured, why not give Merlin the "fame" he deserves, by making him into a Winamp skin?

To get started, I created a directory named MerlinSkin. Inside that directory, two subdirectories are created: player and xml. The background image (MerlinSkinBkgd.jpg) goes in the player subdirectory.

Next, we'll need some images to use as buttons for controlling the player. These could be custom-made, but for this application I'll just use the button images that come with the Simple Tutorial skin. I place these six images:

  • blue-eject - blue-eject.png
  • blue-stop - blue-stop.png
  • blue-play - blue-play.png
  • blue-pause - blue-pause.png
  • blue-previous - blue-previous.png
  • blue-next - blue-next.png

into the player subdirectory beneath my MerlinSkin main directory.

Identifying and Configuring the Images

Now I've got seven images (the six control buttons plus my Merlin background image) in my player subdirectory. How do I tell Winamp that those images exist and specify how they should be applied?

Here's where we get into some XML. In the xml subdirectory, we create a file named player.xml. The structure of this file typically includes an <elements> section, one or more <groupdef> sections, and a <container> section.

First, all of the images must be identified, using the <elements> section. Here's my player.xml code for that section:

<!-- Element definition -->
<elements>
  <bitmap id="player.background" file="player/MerlinSkinBkgd.jpg" 
      gammagroup="Backgrounds"/>
  <bitmap id="player.button.previous" file="player/blue-previous.png" 
      gammagroup="Buttons"/>
  <bitmap id="player.button.play" file="player/blue-play.png" 
      gammagroup="Buttons"/>
  <bitmap id="player.button.pause" file="player/blue-pause.png" 
      gammagroup="Buttons"/>
  <bitmap id="player.button.stop" file="player/blue-stop.png" 
      gammagroup="Buttons"/>
  <bitmap id="player.button.next" file="player/blue-next.png" 
      gammagroup="Buttons"/>
  <bitmap id="player.button.eject" file="player/blue-eject.png" 
      gammagroup="Buttons"/>
</elements>

Notice that the file names are relative to the top-level directory, which is MerlinSkin in my case. Also, note that I've divided the images into two gammagroups: Backgrounds and Buttons. Designating all the buttons as belonging to a specific group will give me the flexibility to change the (x,y) coordinates of all of the buttons by simply changing the (x,y) position of the Buttons group in my player.xml file.

Now that the image files are identified as being part of the player, I need to specify the purpose of each image. Since the buttons belong to the Buttons group, I specify their locations and purposes within a <groupdef> element:

<!-- Playback Buttons Group Definition -->
<groupdef id="player.normal.playbuttons" name="Player buttons">
  <button
	id="Eject"
	action="EJECT"
	x="0" y="0"
	image="player.button.eject"
	tooltip="Eject"
  />
  <button 
    id="Previous"
	action="PREV" 
	x="25" y="0" 
	image="player.button.previous" 
	tooltip="Previous"
  />
  <button
	id="Next"
	action="NEXT"
	x="50" y="0"
	image="player.button.next"
	tooltip="Next"
  />
  <button
    id="Play"
	action="PLAY"
	x="0" y="25"
	image="player.button.play"
	tooltip="Play"
  />
  <button
	id="Pause"
	action="PAUSE"
	x="25" y="25"
	image="player.button.pause"
	tooltip="Pause"
  />
  <button
	id="Stop"
	action="STOP"
	x="50" y="25"
	image="player.button.stop"
	tooltip="Stop"
  />
</groupdef>

Here I am defining that the buttons will be positioned into two rows with three buttons in each row. The top row (located at position y="0") will include the eject, previous song, and next song buttons. The bottom row (located at position y="25" within the Buttons group) will have the play, pause, and stop buttons. For each button, the following data is specified:

  • id: Button identification string.
  • action: Keyword mapping the button to a Winamp action.
  • x: The x position (pixels from the left of the container).
  • y: The y position (pixels beneath the top of the container).
  • image: The image identifier specified as the bitmap id in the <elements> definition section.
  • tooltip: The string displayed when the mouse hovers over the button<./li>

For the player background image, the relevant section is the <container> section. I'll identify that MerlinSkinBkgd.jpg, which will be the background for my player, with the following code:

<!-- Main Window: Container and Layout -->
<container id="main" name="Main Window" default_x="0" default_y="0" default_visible="1">
  <layout id="normal" background="player.background" droptarget="pldr">
	<group id="player.normal.playbuttons" x="12" y="12" />
  </layout>
</container>

Note that I define the buttons group as being located at x=12, y=12; that is, 12 pixels to the right of and 12 pixels beneath the top left corner of the background image.

The skin.xml File

Now we have images and we have a player.xml file that identifies what to do with the images. The final piece for creating a basic Winamp skin is the skin.xml file. This file resides in the top-level skin directory (MerlinSkin in my case).

The skin.xml file contains basic identification information about the skin, along with a set of <include> elements that define the XML files that make up the skin. Here's the minimal skin.xml file I created to get my Merlin skin up and running:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<WinampAbstractionLayer version="0.8">
  <skininfo>
    <version>1.0</version>
    <name>Merlin skin</name>
    <comment>a skin in honor of a crazy cat</comment>
    <author>Kevin Farnham</author>
    <email></email>
    <homepage></homepage>
    <screenshot>MerlinSkin.png</screenshot>
  </skininfo>
  <include file="xml/player.xml"/>
</WinampAbstractionLayer>

The key element is the <include>, where I identify the xml/player.xml file that we created above.

Using this set of images and the two XML files is enough to produce a working Winamp skin that looks like this:

Merlin simple Winamp skin

This skin works, but it's kind of dull: you can't see what song is playing or anything else. All you can do is stare at Merlin and click the six buttons. To do anything else, you right-click the skin, and navigate the Winamp pop-up menu system.

Adding Some Basic Extras

Winamp provides a number of tools--kind of like widgets--that can be easily deployed once you have your basic skin developed. To apply the tools, you add and position them in your player.xml file using a <groupdef> element.

Here's how I extended player.xml to add a song timer, song artist and title, and equalizer to my simple Merlin skin.

<!-- Song File Information and Visualization Group Definition -->
<groupdef id="player.normal" name="Winamp">
  <text
	id="timer"
	display="time"
	x="120" y="50"
	w="30" h="20"
	font="wasabi.font.default" fontsize="12"
	timecolonwidth="7"
  />
  
  <!-- Song File Information-->
  <text
	id="infoline" ticker="1"
	display="songinfo" default=""
	x="160" y="50"
	w="200" h="20"
	font="wasabi.font.default" fontsize="12" ghost="1"
  />
  <!-- Visualization -->

  <vis
	id="vis"
	x="160" y="12"
	w="100" h="35"
  />
  
</groupdef>

<!-- Main Window: Container and Layout -->
<container id="main" name="Main Window" default_x="0" default_y="0" default_visible="1">
  <layout id="normal" background="player.background">
	<group id="player.normal" />
	<group id="player.normal.playbuttons" x="12" y="12" />
  </layout>
</container>

And here's how the extended skin looks, as it plays "Beat" by Kala Farnham.

Merlin Skin with Extras

Installing the Skin for Access by Winamp

Once you have your skin developed, you can install it into Winamp by copying your skin directory into the Winamp/Skins directory. Alternatively, you can zip up your directory, change the extension of the zipped file to .wal, and put the .wal file into the Winamp/Skins directory.

Advanced Winamp Skin Development

The Merlin skin is of course quite basic. There's a lot more you can do with Winamp skin development. The "Winamp 3: Skinning Tutorial Webpage" document (PDF), written by Ken Chen, is a solid 81-page reference that provides details on all aspects of Winamp freeform skins. The tutorial walks you through the steps for creating a simple skin, and then goes into detail on the more complex aspects of freeform skin development such as containers, groups, positioning, layer composition, alpha channels, animated layers, snap points, drawers, and skin scripting.

Conclusion

You can get started creating your first Winamp skin with under 100 lines of XML code and some images. But Winamp provides an enormous amount of flexibility for developing complex, dynamic skins.

Winamp's 10th Anniversary Edition (version 5.5) is the ideal starting point for your Winamp skin development project. It's a powerful player, with more than 60 million very pleased users. If you think you'd enjoy customizing a powerful media player, please download my simple Merlin skin below and use it as a template to help get you started. I had a lot of fun programming it myself!

Resources

References

awesome

great post, I'll make the mine!