Phil Hassey - game dev blog
Phil Hassey as Syndrome
"Look, stores don't sell
costumes like this to just anyone."

Archive for the 'python' Category

How I got Dynamite Jack from 62MB down to 46MB

Thursday, August 9th, 2012


So – I went Universal with Dynamite Jack just today! Yay! This involved a lot of “blah blah” messing with resizing all the menus for iPhone users, which wasn’t very interesting, though it came out really well. The interesting bit was when I realized that “going Universal” meant that my retina iPad assets were going to be put on everyone’s phones. And that meant that the 50 MB OTA limit was going to hit me. Quite a few devs advised me against going over the limit, so I took their warning.

I was at 62 MB. I had to take the size down AT LEAST 12 MB to hit the 50MB limit. However, I also know that when distributing your game iTunesConnect pads things a bit, so adding 2MB to that is a good idea. So my target is 48MB.

What was taking up all that room??

– Video (IVF): 10 MB
– Sound effects (WAV): 7 MB
– Music (AAC): 24 MB
– Images (PNG): 20 MB
– Maps, etc: 1 MB

Okay, so I’m at a good place, I know exactly who is eating my space. But now what to do? Let’s check it out!


So I decided not to do anything about the video. I include two IVF files, one for the retina iPad and one for everything else. They are as lossy as I want them to be, so further altering would start to eat up the quality. I could probably get away with re-encoding them a few % lighter and save 1 or 2 MB if I really had to.

Sound Effects

Stereo 16-bit WAV files sound great but they are huge. I took some advice and converted them to IMA4 files which are 25% as large as WAV files. This saved me about 5 MB. However, I found when testing the game out on my decent computer speakers that the IMA4 format really adds a lot of noise to the sound, this was not acceptable to me. I decided to re-encode them using the AAC encoder at 96k which resulted in perfect sounding sound effects and saved me 6MB!

iMac$ afconvert -d aac -f caff -b 98304 in.wav -o out.caf

I am using CocosDenshion for my audio engine, and it seems to handle this just fine.


My music was already encoded as AAC files at 128k. I tried a variety lower bit rates to see if I could save a few bytes. I found at 64k it was really obvious that I was cutting corners. I found at 80k I couldn’t tell any difference, so I decided to go with 96k since that would give me a bit of a margin above that just so I could be sure the music sounded perfect. I used the same command line as converting the sound effects. Going from 128k to 96k saved me 5MB!

So far I had saved 11MB, but I was 14MB over and I knew I needed to trim a bit more fat to make this work.


Previously I had tried a ton of variations on 16-bit “4444” dithered style images. These, unfortunately, looked horrible in Dynamite Jack. So I wasn’t able to use that trick.

I did find out about ImageOptim which takes forever to pack PNGs but it did manage to pull me back 2MB getting me down to 13MB total saved, which was really going to cut things close. I decided to investigate one other option.

I had heard that Amazing Breaker had used JPGs for the RGB component of images and a PNG file for the alpha component. I really require high-quality images in my game, so I found that at 98% quality and 1×1 sampling I was able to get really great looking images.

Ubuntu$ convert -quality 98 -sampling-factor 1x1 tmp-rgb.bmp tmp-rgb.jpg

I pre-blitted them (which gave me premultiplication) onto a black background to get the JPG. Then I made a grayscale PNG file of the alpha channel. I created my own mini format “.cuz” to combine these into single files and loaded them in my game. I found that the game looked perfect! This saved me 6MB!

Afterwards, I found that some of my pre-baked font images got larger using my format, so I left those as straight PNGs.

Finally …

So all said and done, I had saved 6 + 5 + 6 = 17MB! This got my IPA down to around 46MB, which is a nice distance below the 50MB limit 🙂 I’m quite pleased with the results. Some bonus tips:

– The AAC sound effect trick will only work iOS 3.0 and higher. Which shouldn’t be a problem now-a-days. I hear that this won’t work out-of-the-box with OpenAL, so maybe check out CocosDenshion.

– Definitely check your own music to find what bit rate starts to degrade the sounds. Playing on your iPhone or iPad speaker isn’t enough. Playing on earphones isn’t either (unless they are really nice). I recommend playing on your computer speakers so you can be sure the sound IS really good before deciding.

– The JPG+PNG image trick can get great results – but definitely keep the quality high. I found that I was able to go down to 98% and found no artifacts in my game. Be sure to experiment and find the sweet spot for your game images. Also be sure to test on all device resolutions you have to check for artifacts. I tested on all 4 iOS screen resolutions to be sure things were perfect.

Anyway, I hope you find this helpful in your quest for saving bytes! And don’t compromise on quality! Nobody wants to hear or see compression artifacts.


P.S. If you need to cut your App in half after that, here’s what you could do:

– Change all SFX+music from stereo to mono
– Set JPG quality to 95% or something even less

That would probably cut mine back another 15MB or so, and very few people would notice. I would notice a tiny bit, and in my case, I don’t need to compromise any more, since I’m already under 50MB.

Bonus: a bit more detail on my image file format

First, I used a python script to figure out which was the best way to compress the image. I do a variety of conversions and see which one is the smallest:

– Using JPG-RGB + PNG-A
– Using PNG premultiplied Alpha
– Using original PNG

So, for example, fonts ended up working best as “original PNGs” and most everything else ended up being JPG-RGB + PNG-A. There should be a 4th option of just JPG-RGB with no alpha, but I didn’t bother, since I don’t have any fully opaque textures.

# -*- coding: utf-8 -*-
import glob
import os
import pygame
from pygame.locals import *
from PIL import Image
import numpy

SRC = "../data-ios"
DST = "../data-ios"

def do_cmd(cmd):
    print cmd

def png_fix(fname):
    img = pygame.image.load(fname)
    img = img.convert_alpha(),fname)
def premult(finput, foutput):
    im =
    print "premultiplying matrix..."
    a = numpy.fromstring(im.tostring(), dtype=numpy.uint8)
    alphaLayer = a[3::4] / 255.0
    a[::4]  *= alphaLayer
    a[1::4] *= alphaLayer
    a[2::4] *= alphaLayer
    res = Image.fromstring("RGBA", im.size, a.tostring())

def main():
    s = pygame.display.set_mode((256,256),0,32)
    for fname in glob.glob(SRC+"/*.png"):
        print fname
        img = pygame.image.load(fname).convert_alpha()
        img2 = img.convert_alpha()
        cmd = "convert -quality 98 -sampling-factor 1x1 tmp-rgb.bmp tmp-rgb.jpg"
        img2 = img.convert_alpha()
        cmd = "convert tmp-a.bmp -define png:bit-depth=8 -define png:color-type=0 tmp-a.png"
        dst = fname 
        dst = dst.replace(".png",".cuz")
        f = open(dst,"wb")
        # 4 byte magic
        # 4 byte version / whatever
        s1 = open("tmp-rgb.jpg","rb").read()
        s2 = open("tmp-a.png","rb").read()
        t = 3 #JPG + PNG
        s3 = open(fname,"rb").read()
        # add a check for non-alpha images, store as JPGs.
        # wouldn't save much room since the full alpha PNG itself will only
        # be like 100 bytes.  not a high priority item!
        if (len(s3) < (len(s1)+len(s2))): 
            # we have failed, fall back to just wrapping a PNG
            # but first, premultiply it
            s4 = open("tmp-pre.png","rb").read()
            if len(s3) < len(s4):
                t = 1 # PNG - original
                s1 = s3
                s2 = ''
                t = 2 # PNG - premult
                s1 = s4
                s2 = ''
        s1 += "\x00"*(4-len(s1)%4)
        s2 += "\x00"*(4-len(s2)%4)
        # 24 byte info
        s = "%d %d %d"%(t,len(s1),len(s2))
        s += "\x00"*(24-len(s))
        # data
s = f = open("%s/data.json"%(SRC)).read()
s = s.replace(".png",".cuz")
f = open("%s/data.json"%(SRC),"wb")


In my game, I use stb_image to load my images. But I used a little bit of C code to read my header and decide how to decode them.

        unsigned char cuz_head[256];
        FILE *f = fopen(fname,"rb");
        int tp=0,s1=0,s2=0;
        sscanf((char*)cuz_head+8,"%d %d %d",&tp,&s1,&s2);
        fprintf(stderr,"is_cuz: %d %d %d\n",tp,s1,s2);
        // load our first image!
        data = stbi_load_from_file(f,&width,&height,&bpp,4);

        if (tp == 1) {
            // do nothing, it's like we loaded a normal image
        if (tp == 2) {
            // this image is premultiplied
            is_premult = 1;
        if (tp == 3) // separate ALPHA image
        if (data) {
            // this image is premultiplied
            is_premult = 1; 
            unsigned char *alpha;
            int _width,_height,_bpp;
            alpha = stbi_load_from_file(f,&_width,&_height,&_bpp,1);
            if (!alpha) {
                fprintf(stderr,"(cuzi:alpha) stbi_load failed %s - %s\n",fname,stbi_failure_reason());
            if (alpha) {
                fprintf(stderr,"(cuzi:alpha) OK\n");
                unsigned int *pix = (unsigned int *)data;
                unsigned char *pa = alpha;
                for (int i=0; i<width*height; i++) {
                    unsigned char *p = (unsigned char*)pix;
                    p[3] = *pa;
                    pa ++;
                    pix ++;

Dynamite Jack: The second prototype, post-post mortem

Monday, April 23rd, 2012

So about six months after I created “Escape from Anathema Mines” during the Ludum Dare game jam, I created a game called Dynamite in the PyWeek game jam.


So the theme of PyWeek #1 was “Power” .. I worked with my brother-in-law Tim on this game, and we spent a fair amount of time working with the idea of using a “mind control power” over the characters in game. So I wrote some A* code to navigate things around and whatnot. This was boring. So I made it so you could blow something up. This was exciting. We decided “the power of dynamite” was what the game was about, since the dictionary definition of dynamite said something about “a powerful explosive.” Not my best “theme compliance” for a game jam, I’ll admit.


The best way to see the gameplay is to PLAY THE GAME if you have Windows 🙂 (Download the post-compo version, it’s a little shinier.) But short of that, watch me play through one of the levels. There’s a ton of interesting differences between this and Dynamite Jack. The most significant one is that in Dynamite you can “fail” really easily. You can block yourself into a corner by destroying the floor, and you can run out of bombs. Those are both design decisions I changed for Dynamite Jack.

Fun facts

Tim created all the music for this game, one of the tracks is based on a fiddle tune as well. You may be able to tell that the character art in this game is the same character art I ended up using in Dynamite Jack. It’s all from Reiner’s Tilesets. It definitely helped a ton to have that art work. It ends up looking really sharp in Dynamite Jack because I scale things down so small.

I also brought the “dynamite drop” sound effect from this game into Dynamite Jack. It just sounds so cool.


I think one of the big gameplay mechanics I like in that game is that when you sneak along the walls you are invisible to the guards. It kinda leaves the “lighting effects” to your imagination. But one of the problems with that is that it’s not very obvious. I used the different colored cursor to help the player be able to know where the safe zones were.

This game introduced the fun of having guards running to check out whatever you just exploded. I did the voice acting in this prototype of the game.

The idea of this game really stuck with me for a long time, so for the next several years I always talked about going back and re-making it.


(Dynamite Jack is coming to PC / Mac in mid-May. Check out the trailer to see the difference from the original shown here.)

Dynamite Jack: Seven Years Ago Today – the prototype post-post-mortem

Monday, April 16th, 2012

The development of Dynamite Jack was a really involved and long-term project. The project started almost exactly SEVEN YEARS AGO. I’m going to do a series of blog posts over the next few weeks leading up to the release of Dynamite Jack highlighting both the features of the game, the development of the current version of the game, and the unique history that went into the development of this game.

Seven Years Ago Today …

The first prototype I created of this game idea was during the 6th Ludum Dare game jam. This was only my second game jam I ever participated in, and it was an amazing experience. I was learning how participating in game jams stretched me as a game designer, so instead of just saying to myself, “hey, I’ll make a Mario 3 clone today!” I was given a specific theme that I had to design a game around!

Light and Darkness

The theme was light and darkness, which today I still think was one of the greatest themes ever for a game jam. It brought a ton of unique concepts out of all the developers who participated in that jam. My game was called “Escape from Anathema Mines”:

The Gameplay

To give you an idea of the gameplay, well, you can play the game on Windows, maybe. Or using pygame, if you know how to get that working. Or, you can just watch this video of me attempting to play the game today 🙂

Some differences in the gameplay from Dynamite Jack are – in the original, the flashlight could run out of batteries. The guard could hear you when your flashlight was turned on. And if you took too long, you’d run out of time for no apparent reason.

Fun Facts

The name “Anathema Mines” was inspired by a greek word I heard in a sermon meaning totally accursed. This seemed to match my feelings for being forced to work in salt mines, so I went with it for the name of the game. The speaker who taught me that greek word, Lyn, posed for the totally awesome title screen art of the game.

Also, the music in the game is based on a fiddle tune that I knew called “Tennpenny Bit” .. You can hear a rustic recording of a band I was in playing it about 7 years ago here listed under “Two Dinners and Sunday Brunch”.

The Post-Post Mortem

After a game jam I often write up a post-mortem of what went right and wrong in the dev of the game. I’ve posted that in verbatim below. I’ve included my “hindsight” comments highlighted in yellow, so you can see what I think of my analysis of the game seven years later 🙂

This year I spent around 2 hours planning before I actually started writing my game. I also bounced ideas around with some friends to come up with a really good game concept. I believe spending this time planning before actually creating really helped out in the fun factor this year. Last year my fun score was fairly low. My first jam game was called “Cuzco’s Goat Bloat Game” and it featured my pet goat Cuzco .. but it was crazy hard to play

I used pygame again this year to great success. I love pygame, and I still use it for jams sometimes. Python is the best. It was easy to get my game up and running and working quite nicely by the time the contest came around. I also used my own level and tile editors, which helped save a good deal of time. I also was able to use my MR-8 for recording sound effects, ModPlug and n-track for creating the music. I was quite pleased with the quality of audio I was able to create in about 2 hours. I also utilized friends to do play testing. This also helped in the fun factor, as I was able to get some good feedback on what parts of the game were fun, what levels were too hard, etc. I’ve done a ton of this for Dynamite Jack. It really helps. My wife, Nan, is the primary tester of Dynamite Jack, and if she doesn’t like a level, she won’t play the game again until I remove it from the game. I was also pleased to have enough time to create 5 levels for the contest, giving my game a fairly complete feel.

For next time, I am interested in learning a 3-D kit so that I can do fancier graphics. My game would have still been a 2-D game, but with the added light effects, I think that would have helped my production. I did just that for Dynamite Jack. Jack is written using OpenGL, but I have the game in 2-D mode all the time, so I never use any 3-D effects. I also don’t actually use the OpenGL lighting features, I pre-calculate all the lighting in my code. But being able to have vertex colors makes the nice shading in Dynamite Jack. Escape From Anathema Mines was written in PyGame which is based on SDL, and I only had simple blitting of images. The effects that I managed in this early prototype are actually doing a cool job of pushing the boundaries of what pygame was able to do.

The Good

  • Prep: I made sure all my tools were installed and working before the contest
  • Planning: gave me considrable direction and a better starting idea
  • Tools: pygame, pgu (level and tile editors), ModPlug, n-track, Audacity
  • Windows: knowing how to use py2exe
  • Testing: Having lots of it. Game play came out good, and no critical bugs were in the contest edition.
  • Time: Managing time from most important features to least

The Bad

  • Tools: wish I had 3-D tool knowledge to do my lighting effects and hi-res graphics.
  • Testing and Time: wish I had more time to do more to weed out the last few non-critical bugs, but you can only do so much in 48 hours.

Glaring omission here: the horrible controls! You can see in that video how I’m barely able to control the main character. He moves like a go-cart or something. I have no idea why I designed it with “rotate left” / “rotate right” / “forward” / “reverse” controls instead of just using the arrow keys as ARROW KEYS.

Going Forward

Going forward, well, my game only placed about 8th place in the competition, and nobody was super into the game at that point, so I didn’t bother to do anything with it beyond doing a few post-competition tweaks to the game. Thus Anathema Mines was put aside for quite some time.


(Dynamite Jack is coming to PC / Mac in mid-May. Check out the trailer to see the difference from the original shown here.)

tinypy2 musings

Thursday, June 2nd, 2011

So, my mind has been poking away at the idea of making a “tinypy2” that would be a bit less like python, so probably even more confusing for end users. Being only one sentence into my proposal here, and it already sounds bad. Well, here goes:

-1 All objects would be assigned and passed by value instead of by reference
=0 There would be a dictionary of global variables
+1 The VM state could be saved to readable JSON
+1 The VM state could be loaded from JSON
=0 The VM would be written in C++
+1 The VM would have super-easy interoperability with C++ code
-1 The VM would be on the slow side

Tallying up the pros and cons, we get to a +1 for this idea. I don’t suppose there’s much way for anyone to comment on if this sounds like a good idea or not, but thos are some of the thoughts going around in my head right now. It seems like it would be an interesting rudimentary scripting language. The load / save of VM state and C++ interoperability are the key points.

#badideas ??


Google AI Challenge featuring Galcon!!

Friday, September 10th, 2010

Hey, it’s been a long time in coming, but finally we’re having a battle of programming prowess for Galcon!!


Go rev up your coding skills and let’s do this!

.. You might be interested to know that I ported the iPhone bot from C code over to python code for the contest. It is currently hanging out in the upper portion of the ranks as “galcon”. Making a bot is a ton of fun! And I’m highly pleased that they have a kit available for python devs :) So get started and have fun!


Ludum Dare 2010 Keynote (starring Cuzco the Goat!!!)

Friday, April 23rd, 2010

See the Ludum Dare 2010 Keynote:

Inviting all python game-devs! Even if this notice is coming too late, we’ve got a compo coming in August, December, and mini-compos every month! Just check out the website and join the fun!


Galcon Fusion for the iPad

Saturday, April 3rd, 2010

galcon-ipad-rainbowSo Galcon Fusion is available for the iPad.

Here’s a bit of tech stuff for ya! The port itself took about 3 days. If you check out the screenshots, you can see I letterboxed the desktop version of Galcon Fusion, and used that extra area to put the iPad specific controls (the pause button, the chat activation button, and the ships % “mouse wheel”)

I don’t have an iPad yet, but I think it’s going to work pretty well. The multi-touch interface design was all done ages ago for the iPhone, so I just used that code for this. It should work great!

The biggest challenge in porting was dealing with OpenGL stack limits on the iPad which appear to be 16 levels. My GUI used quite a few Push/Pop’s to achieve various theme effects and whatnot, but that was blowing the stack. It took me a bit, but I was able to find a number of places where I was able to remove those uses of the stack and things seemed to work fine. (There are some edge cases where my changes wouldn’t be safe, but none of my code uses those, so no harm!)

Anyway, I’m really looking forward to getting an iPad and seeing how the iPad users stack up against the mouse users. This will really pit two different interfaces against each other, which should be really neat. Both interfaces have their own advantages!

As always, python proved useful in this project as I had to update all my graphical assets for the game to work with the iPad. Since my asset pipeline was written in python and pygame, it only took a couple minutes to add in the code I needed to fix a few issues. And thankfully these fixes will go forward and improve my desktop version as well, so all and all, a good deal.


P.S. In other news, I’ve been playing with django lately for my non-games business. It’s slick!

Update: Since I was unable to test Galcon Fusion on a REAL iPad it has bugs 🙁 Apparently the multi-player game crashes and the framerate is low. I’ll be getting my iPad on Monday and fixing those issues ASAP! There’s probably some kind of “testing on real hardware is smart” kind of lesson in this somewhere …

Rebuilding my GDC talk …

Monday, February 22nd, 2010
Me speaking two sentences at some political thingie.

Me making a 15 second speech at some crazy political thing.

So, wow .. I’m going to be speaking during the iPhone summit at GDC in two weeks. The last few months have been a whirlwind of activity for me as I’ve been churning out Galcon Fusion. So now it’s time to get to business getting my talk ready.

Part of the GDC talk process is sending them a title and a draft version of your talk a month or so in advance. I did this with my talk, which was titled, “Nuts & Bolts of Internet Multiplayer iPhone Game Testing” .. The feedback I got from the iPhone summit advisors was (to summarize): “This talk looks short, and maybe a bit boring.”

After a week of soul searching and considering my options, I had to agree. I wouldn’t want to go to my talk, it didn’t sound that great. Having nowhere else to turn to, I turned to PyCon. I knew that at PyCon people gave talks about how to give talks almost every year. I’ve missed the last two PyCons, so thankfully they’ve been posting them online!

I watched Andrew Kuchling’s How to Give a Python Talk which gave me some insight. The three points he made that really struck me were:

  • Think About Your Audience

    This means I need to give my audience a reason to be at my talk.  What are they interested in?  What do they want to accomplish?  What can I give them so they are empowered to accomplish this goal?

  • Too Short > Too Long

    Andrew related that it’s better to cover too much material in too little time, then to cover too little material in too much time.  If I can cover a blazing amount of information, but at least hit some key points with a strong note, the audience will come away with something.  If I drone away about nothing for 30 minutes, they’ll come away bored.

  • Rehearse your talk!

    I knew this one.  But, it’s good to be reminded.  To those who are coming to GDC and plan on seeing my talk, fear not.  I’ve got this week and next week with NOTHING planned, so I’ll be rehearsing my talk MANY times.  I plan on delivering this one with a bit more style than last time.  Last time was at 360iDev, my first “long” talk at a conference.  I  rehearsed my talk about 1.5 times, and I think it showed.

I think for me the first two points answer my question really quickly.  Why does a dev want to hear me talk?  They want to learn how to make a multi-player game.  As for length, I can cover a bunch of keys to creating a multi-player game and maybe people will latch onto a few key points.  If I only cover testing (as was my original plan) the people at my talk would walk away completely unable to use that information if they don’t have any idea where to start.  Instead, if I give the whole picture, and include testing as part of it, they’ll have enough to go on to get started creating iPhone multi-player games.


P.S. Yeah, if anyone wants to give me tips on talking, feel free.  Oh, and I think my talk is going to be re-titled to: “How GALCON Conquered the Universe of Online Multiplayer Games”

The Galcon Fusion beta testers rocked

Thursday, February 11th, 2010

Galcon Fusion has arrived.“Yay, it’s finally here! Check out Galcon Fusion today! We’ve got a free demo and it works on Windows, Mac OS X, Linux, and Steam! It features some crazy nice hi-res graphics and soundtrack. And epic multi-player battles like you’ve never seen ‘em before! Have fun!” <– marketing blurb 😉

Okay, for some dev thoughts. Man, it was a long week! Adding the “demo” feature to the build was a ton of work. And then doing all that other ‘stuff’ that sort of comes up. I think the one serious lesson I’ve learned in this whole process is that beta-testers are awesome.

Really awesome. I had about 50 people who I passed out 10 builds of the game to over the past 3 months. Some of these people put in several dozen hours of play time. All this was a huge help for me, as this was my first desktop ‘3D’ game, so I had a lot of learning to do in terms of graphics capabilities. As in, I was able to get the game to run on my computer which is a pretty nice MacBook Pro .. but not everyone else’s.

The beta tester feedback was huge, I was able to get the game running on old PPC macs, various linux netbooks, and who knows what else .. as long as it had a somewhat reasonable 3D card. I changed the memory requirement for graphics from about 200 MB down to < 64MB. Without any noticeable reduction in graphics quality even in HD video modes. In fact, that reduction changed the loading time on my computer from 5-8 seconds down to about 1 second 🙂 Anyway, I think I'm going to take a nap. It's been a long week, and I really appreciate everyone who helped me get this game put together. Give it a whirl, and thank the beta testers!

5 awkward and 5 awesome things about lua …

Friday, January 29th, 2010


I’ve been spending some time checking out lua, because I’m thinking about using it for scripting in games.  I’m looking at it instead of tinypy because tinypy is slow and really needs some more TLC to be totally useful to me.  However, after looking at lua for a while, I’m finding the things that make it feel awkward to me.

  1. List indexes starting at 1.
  2. For loops use [a,b] intervals
  3. No += operator.
  4. do / end keywords instead of { }
  5. List and Dict types combined into one

At the same time, I’ve found that lua is totally awesome.  I mean, wow.  Really slick stuff!  Here’s 5 awesome things:

  1. Small codebase
  2. Faster than other dynamic languages
  3. Easy API integration
  4. Coroutines <- these are neat!
  5. State is serializable

So here are my thoughts:

  • The first 4 awkward things are superficial, I could probably hack those into shape in a day or two.  The 5th item (List + Dict) as one item is probably not something I can fix, but I could probably live with it.
  • If I changed the language like that, and provided it for users to create mods for my games I would not be able to give them a link to the lua documentation, since it would not be accurate anymore.

Not quite sure what to do here.  Lua seems great, though a few language design decisions seem awkward to me.  I could change the language easily enough, but then I would be breaking all the lua documentation for my users.

Anyone got some language-design thoughts on this one?