A helper class to show video "safe areas"

In this brave new world of XNA, we need to think about how our programs will look when displayed on televisions, as well as on computer monitors.  One new issue to be aware of is the concept of the safe area.  When your game runs on a console, the user's television may not show every pixel you render to the viewport -- some bits around the edges may get cropped.  The amount that will be visible will vary, based on the model of television.  Both standard-definition and high-definition TVs do this cropping, to about the same extent.  The consensus rule that broadcasters and console programmers tend to follow is:

  • Don't show any essential "action" outside of the center 90% of the viewport (the "action safe area")
  • Don't show any symbolic information such as text outside of the center 80% of the viewport (the "title safe area")

Note that you should still render your scene to the full viewport -- you just need to be aware that some users won't see those pixels near the edge, so don't rely on everyone being able to see what's out there.  As a game programmer, the main takeaway is that you should layout your UI elements to be within the title safe area.

Video editing tools generally have a way to visualize the safe areas.  I wrote up a quick helper class to do this in XNA.  Not rocket science, I know, but you can grab this code and use it to check your game before releasing it to the teeming masses.

Here's the code:

/// <summary>
/// A helper class to indicate the "safe area" for rendering to a
/// television. The inner 90% of the viewport is the "action safe" area,
/// meaning all important "action" should be shown within this area. The
/// inner 80% of the viewport is the "title safe area", meaning all text
/// and other key information should be shown within in this area. This
/// class shows the area that is not "title safe" in yellow, and the area
/// that is not "action safe" in red.
/// </summary>
public class SafeArea
{
    GraphicsDevice graphicsDevice;
    SpriteBatch spriteBatch;
    Texture2D tex; // Holds a 1x1 texture containing a single white texel
    int width; // Viewport width
    int height; // Viewport height
    int dx; // 5% of width
    int dy; // 5% of height
    Color notActionSafeColor = new Color(255, 0, 0, 127); // Red, 50% opacity
    Color notTitleSafeColor = new Color(255, 255, 0, 127); // Yellow, 50% opacity

    public void LoadGraphicsContent(GraphicsDevice graphicsDevice)
{
        this.graphicsDevice = graphicsDevice;
spriteBatch = new SpriteBatch(graphicsDevice);
tex = new Texture2D(graphicsDevice, 1, 1, 1, ResourceUsage.None, SurfaceFormat.Color);
        Color[] texData = new Color[1];
texData[0] = Color.White;
tex.SetData<Color>(texData);
width = graphicsDevice.Viewport.Width;
height = graphicsDevice.Viewport.Height;
dx = (int)(width * 0.05);
dy = (int)(height * 0.05);
}

    public void Draw()
{
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

        // Tint the non-action-safe area red
        spriteBatch.Draw(tex, new Rectangle(0, 0, width, dy), notActionSafeColor);
spriteBatch.Draw(tex, new Rectangle(0, height - dy, width, dy), notActionSafeColor);
spriteBatch.Draw(tex, new Rectangle(0, dy, dx, height - 2 * dy), notActionSafeColor);
spriteBatch.Draw(tex, new Rectangle(width - dx, dy, dx, height - 2 * dy), notActionSafeColor);

        // Tint the non-title-safe area yellow
        spriteBatch.Draw(tex, new Rectangle(dx, dy, width - 2 * dx, dy), notTitleSafeColor);
spriteBatch.Draw(tex, new Rectangle(dx, height - 2 * dy, width - 2 * dx, dy), notTitleSafeColor);
spriteBatch.Draw(tex, new Rectangle(dx, 2 * dy, dx, height - 4 * dy), notTitleSafeColor);
spriteBatch.Draw(tex, new Rectangle(width - 2 * dx, 2 * dy, dx, height - 4 * dy), notTitleSafeColor);
spriteBatch.End();
}
}

Let's see how it works on Wendybrot...

Safe Area Example

Uh oh, call the TV police! I'm definitely drawing some text and UI elements too close to the edge of the viewport. If I were to ship this app as a real console title, I'd definitely want to move the text and the progress indicator wheel inward so they're in neither the red nor yellow zones.

-Mike