Adventures in Motion Capture: Using Kinect Data (Part 3)
July 15, 2016
Having already covered the basics of recording joint information with the Kinect v2 sensor and applying that data to a custom 3D character model for animation, this week I’m going to wrap things up with a few last tweaks. In particular, I’ll go through using the Kinect’s floor data to ensure characters are standing straight and the Kinect’s positional data to allow for animations that involve vertical movement, such as jumping.
Tilted Skeletons
When the Kinect sensor records its surroundings it uses itself to define the origin of the three dimensional space being recorded. Within this space we have our standard X, Y, and Z axes. To best understand these, imagine you are a Kinect sensor looking into the world.
![[Camera space with the Kinect parallel to the floor.]](images/skeleton11.gif)
Camera space with the Kinect parallel to the floor.
- The X axis (not shown above) increases to your left and decreases to right.
- The Y axis increases going up and decreases going down.
- The Z axis increases in front of you and decreases behind you.
All well and good, but as I mentioned, these axes are defined with the Kinect as the origin. Now imagine what happens if you raise and lower your head.
![[Camera space with the Kinect pointing downwards. Note how the model head is closer on the Z axis than the feet.]](images/skeleton12.gif)
Camera space with the Kinect pointing downwards. Note how the model head is closer on the Z axis than the feet.
Here we have the Kinect sensor tilted so that it’s pointing slightly downwards. The sensor doesn’t account for that though. It still considers going straight away from it to be the Z axis and going up from its top to be the Y axis. As shown, these directions no longer match with the true Y and Z. The result of this is that if we apply the raw Kinect orientation information to our model then the model will be leaning forwards if the sensor is pointed down and backwards if the sensor is pointed up.
The easy way to correct for this tilt is to simply ensure that the Kinect sensor is adjusted so as to be level with the surface the person being recorded is standing on. However, the Kinect also provides us with data that we can use to programmatically account for this tilt.
From the Kinect 2.0 SDK we previously used the Body Basics sample application to record orientation data from the sensor. This was done using the BodyFrame class, which provides access to both the position and orientation data of joints. It also provides information about the floor a person is standing on if the floor is in the field of view of the camera.
Each frame that data for a body is retrieved from the sensor, the BodyFrame method get_FloorClipPlane can be used to retrieve a Vector4 that defines the plane the bodies are standing on. The general equation of the plane is defined as:
Ax + By + Cz + D = 0
In our case, the Kinect sensor returns the values for A, B, C, and D in that Vector4. These values are returned in “Hessian normal form” which is a fancy way to say that the values have been scaled such that A, B, and C define a unit length vector that is the plane’s normal. It’s this unit vector that we’re most interested in.
![[From the point of view of the camera the floor normal is pointing uppish and back instead of just up.]](images/skeleton13.gif)
From the point of view of the camera the floor normal is pointing uppish and back instead of just up.
If we consider that the subject being recorded by the sensor is standing on the floor (and the floor is more or less level), then the person will be standing up and down and the normal to the floor will also be up and down. If we then introduce the sensor into the equation, we can see that both the normal and person will be pointed towards or away from the camera by the same amount. From the point of view of our camera there is some angle between where the floor normal is and where a true straight up Y vector is. We therefore need to rotate each of the orientations we receive from the Kinect by that angle to bring them into true.
To do this we need to define two vectors in our code. The first vector is just a basic “up” vector defined as (0, 1, 0). The second is the floorNormal vector which is of unit length and is obtained by taking the first three components from the Vector4 returned by get_FloorClipPlane.
Important: The Kinect sensor can only return the floor plane if it can actually see the floor in its field of view. If the sensor is tilted up, or used in a really confined space, it may not be able to perceive the floor. In this case, the values of the Vector4 are all returned as 0. Just something to test for to ensure things don’t go sproing.
Frist we calculate both the cross product and the dot product of these two vectors. The cross product gives us the axis that we need to rotate about to bring the floorNormal vector to be pointing straight up like the up vector and the dot product gives us the amount of rotation that we need.
axis = up X floorNormal
dot = up . floorNormal
To get the angle of rotation, we take the arc cosine of the dot. From that angle and the axis we already calculated, we can define a quaternion that we can use to rotate the Kinect orientations to eliminate model tilt.
angle = RadToDeg(ArcCos(dot)) Note that we convert from radians to degrees here for the angle.
floorQuat = Quaternion(axis, angle)
By applying this rotation to all of the Kinect orientations we receive we rotate the skeleton information such that it’s now standing up and down from the point of view of the sensor. This gives us the effect were after; namely, it removes the tilt from the skeleton.
One final note: You may recall from last time that in my particular case, because I was using MilkShape 3D to create my test model, I had to rotate the Kinect orientations such that the Y axis was mapped onto the Z axis. When applying correction for the floor tilt, that correction should be applied after the YZ swap.
Jumping
Up to this point we’ve only concerned ourselves with the orientation data from the Kinect as that’s what we need to pose the skeleton of our 3D model correctly. Given differences in size and shape, we can’t really use the joint position data the Kinect provides, except for one in one instance: the SpineBase
![[The Kinect v2 joint hierarchy.]](images/skeleton05.gif)
The Kinect v2 joint hierarchy.
The SpineBase joint is the ultimate ancestor of every other joint in the skeleton. By moving this one point about we automatically move all the other points in the skeleton by the same amount. This is especially useful for allowing us to do animations where the body travels vertically, such as when the person we’re recording jumps.
Right now, we’re not doing anything with the position of SpineBase in our test model. Spine base is our starting point and all we do is apply its rotation to any vertices related to it. This allows those vertices to twist and turn in space but doesn’t otherwise allow for them to move up and down. If we were to apply a jumping animation at this point, we’d see the body move as if it was jumping but it wouldn’t actually change height. Let’s address that, shall we?
First, revisiting our SDK sample application, we’ve already used the GetJointOrientations method of the Body class (which we in turn get from the BodyFrame class) to retrieve the orientations of the joints. Now we’re also going to use the GetJoints method to get the positions of the joints themselves. The joints are returned to us in a list of Joint objects, one for each joint the Kinect tracks, the same as for the orientations. For each joint we can access the Position property and get its X, Y, and Z sub properties.
Even though we get the positions for all of the joints, we’re really only interested in the SpineBase position. From that we can tell how much the skeleton as a whole is moving up and down. What we need to do is apply that movement to our test model skeleton in a reasonable way. We can’t just apply it directly. For example, suppose we record a really tall person but we apply the animation to a really short model. If we used the change in position directly it would look like our short model had a super jump. What we want to do is apply the change in position of the recorded subject proportional to the height of our actual test model.
There are a number of ways to do this. For my playing around, I went the simple route. I assume that the person being recorded starts in a more or less neutral standing position. A position where their SpineBase point is the regular distance from the floor the person is standing on.
The first goal is to determine how far away from the floor plane the initial SpineBase is. Yep, the same floor plane we used above to straighten out the tilt in the model from tilt in the camera.
By taking the position of the SpineBase and substituting it into the floor plane equation we get how far away from the plane the SpineBase position is.
distance = Ax + By + Cz + D
Here, A, B, C, and D come from our floor plane and x, y, and z are from the SpineBase position. We hold onto this distance and, because we’re assuming the person we’re recording is starting standing in a neutral pose, we say that this distance is equivalent to the distance from the origin to SpineBase in our 3D test model.
![[Applying a proportional difference in the SpineBase move allows the model to jump.]](images/skeleton14.gif)
Applying a proportional difference in the SpineBase move allows the model to jump.
On subsequent frames in our recorded animation we run the SpineBase position through the plane equation to figure out how far away from the floor plane the skeleton currently is in Kinect space. When the person jumps up, the distance will increase from the initial distance we stored. When the person ducks, the distance will decrease. In either case, we can calculate the percentage of their initial height like so:
percentHeight = currentHeight / initialHeight
Suppose the initial SpineBase height is 1 meter. On a later frame, the person then ducks so their SpineBase is at 50 centimeters (half a meter). Our calculation above will give us a percentHeight of 50 / 100 = 0.5. All we have to do is multiply the initial SpineBase position of our 3D test model by 0.5 and our model will move down by half of its SpineBase height regardless of the height of the actual person we’re recording.
And that’s it. By applying proportional changes in the height of the SpineBase joint instead of raw changes in height, our test model will move vertically in the same way as the person being recorded but at a scale appropriate for the test model. If we wanted to, we could apply a similar technique to the X and Z movements of our test model. This could be useful for having the model move along at an appropriate rate where the person we’re recording is walking or running, for example.
Limb Rotations
One last topic I wanted to briefly touch on is that of limb rotations. I’ve left it for the end because it’s something I haven’t dealt with yet in my own experiments with the Kinect data. However, if you’re playing with Kinect data you’ve probably already encountered the issue of bad limb rotations.
The Kinect sensor works quite well for recording body information, but it’s not perfect. Arms and legs can cause the Kinect sensor some problems. Especially the forearms.
If you stick your arms straight out in front of you, palms pointed in, and then rotate them so they’re still straight out but your palms are pointed outwards, you’ll see that there’s really very little physical difference in how your arms (ignoring your hands) appear. These type of bone aligned rotations can cause the Kinect issues where from one frame to the next the Kinect may decide that a person’s arm has suddenly rotated 180 degrees and then on a subsequent frame it may rotate back again.
I haven’t done anything yet to try to filter out these bad rotations so I have no real recommendations on how to handle this problem. Just be aware that if you’re seeing this happen with your Kinect data that it is more than likely coming from the data from the Kinect itself and is not a mistake in any code you may have written.
Summary
It took a while to get through all the issues – three blog posts to be exact – but we now have motion capture data recorded from real people using the Kinect that we can reasonably apply to our virtual 3D models. A few issues remain (mostly just the bad limb rotations) and doubtless many improvements could be made but hopefully this miniseries will allow you to have some fun with your Kinect. Good luck!
Previous: Adventures in Motion Capture: Using Kinect Data (Part 2) | Next: Does an Idea Have Legs?
Blog Posts
2025
April
04: Rolling Some Animations
March
07: Speaking and Moving
February
07: The Voices in Their Heads are Talking
January
03: Reputable Script Organization
2024
December
06: A Grab Bag of Stuff
November
08: The Recording Booth is Finished and then Some
September
06: The Recording Booth is Started
August
09: It’s All About the Dialog (Now)
July
05: Talking About Statistics
June
07: Broken Dialog Record
May
03: Finally Photos
April
05: Hint System 2.0
March
08: Flashing Back in Time
February
09: Inventory, Inventory Everywhere
January
05: Sleuthhounds Year Seven, Will it be the Last?
2023
December
01: Climbing the Rungs
November
03: Walking Through the Evolution of the Walkthrough
October
06: Look to Look
September
01: Sneaking at Sunset
August
04: Every Game Needs a Loot Box
July
07: Hamsterdam Exchange: Revisited
June
02: Dressings All Dressed Up
May
05: Ducts? Why Did it Have to be Ducts?
April
07: End of the Road
March
03: Daughter of the Boss
February
03: Den of the Boss
January
06: Where are We At? Where are We Going?
2022
December
02: Cutting the Way to Success
November
04: Maintaining the Ship
October
07: Once More Around the Promenade
September
02: Toilet Tank Humour
August
05: Uplifting: Combining 2D and 3D
July
01: A Moodier Room
June
01: Try Your Luck...Or Not
May
06: The Sky Deck: Almost but Not Quite There
April
01: A Clean Desk is a Sign of Dirty Drawers
March
04: Cable Management
February
04: The Doctor Will See You Now
January
07: The New Year is No Time for Lounging About
2021
December
03: Bridging the Gap
November
05: Captain's Log, Or Cabin
October
01: One Man's Treasure...
September
03: Rudder Way to Go
August
06: The Illusion of Depth
July
02: Streamlining Stairways for Players
June
04: Room with a View
May
07: States, Saves, and Simplifying Testing
April
02: Safety Features
March
05: When You Gotta Go
February
05: The Dining Room: Last of the Big Three
January
01: Boxing Day Sale at Sea
2020
December
04: You Gotta Have a Library
November
06: Pipes and Problems
October
02: A Sleuthhounds Message
September
25: It's a Room Sandwich
18: Writer's Room
11: Souvenirs at Sea
04: Cruise Cartography
August
28: Chocolate Shop, Er, Passenger Cabin
21: Place Your Wagers at the Pirate’s Chest Casino
14: Sometimes You Just Gotta Stop and Admire a Sunset
07: The Cruise Casino for Fun and Profit
July
31: Keep Fit and Have Fun
24: Even More Doors
17: Doors, Doors, and More Doors
10: Art Walk
03: Captain Windwhistler, to the Bridge
June
26: Doctor Seymour, to the Infirmary
19: Bilge is a Funny Word
12: There's No Money Laundering Here
05: A Pirate I was Meant To Be
May
29: You Gotta Have a Brig
22: Boring Backgrounds for the Staff
15: Theatre from on High
08: Theatre Crowding
01: In the Pool Any Time of the Day
April
24: The Crew Have to Sleep Too
17: Spring Time, Flowers Time
10: Cleaning Staff
03: Two Worlds
March
27: Kitchens, Spared No Expense
20: Cabins Day and Night
13: An Art Tour at Sea
06: The Pirate's Chest
February
28: Room with a View
21: Lock Picking Refined
07: The Gigantic Joanna
January
31: Updating the Safe
24: Interview Screenies
17: Burning Down Assets
10: Full Speed Ahead on Asset Creation
2019
December
20: Christmas Sale and Mini Mysteries
06: Generic Character Interactions
November
29: Locking the Gates - Preventing Characters from Wandering Amok
22: Side Quests Complete
15: Achievements to Prompt Replays
08: Interviews and Interludes
October
25: Halloween Sale and Mini Mysteries 2019
18: Fountains and Fortunes
11: Shifting the Blame Game
04: Streamlining the Audio Workflow
September
27: Hamsterdam Exchange
20: Streamline the Interface, Lower Production Time
13: Linking Ideas like a Golden Necklace
06: Beware of Geeks Bearing Gifts
August
16: Extra, Extra! Read All About the Extras!
09: Dressings of Fruits and Veggies
02: Sidling into Side Quests
July
26: Working on Workouts
19: How to Draw Cartoon Marble
12: AppCredits() = The End
05: Getting the Ending Right
June
28: The Problem with Balconies
21: Return of the Summer Sale and Mini Mysteries
14: The First Ending
07: Rewrites and Recodes
May
31: Choice and Consequence
24: Doctor Seymour Colourization
17: Sneaky, Sneaky
10: Play Time
03: Things to Do in Acts 1 to 3
April
26: The Changing Nature of Estimates
19: Escaping the Balcony (A Goldilocks Puzzle)
12: Facts more Fun than Fiction
05: Ramping Up Difficulty in an Adventure
March
29: Evolution of a Scene
22: Characters: Sources of Problems and Solutions
15: The Act 3 Countdown
08: Ducts, Why Did it Have to be Ducts?
01: Cheating in the Name of Narrative
February
22: Meet the Suspects - Edward Noble
15: Meet the Suspects - Doctor Michelle Seymour
08: Flashback Investigation
01: Milestone: Act 2 Done-ish
January
25: Letting the Player Fail
18: Meet the Suspects - Tobias Rotterdam
11: Adding another Layer to Note Reassembly
04: Meet the Suspects - Craig Holdfast
2018
December
28: New Free Games Section
21: Meet the Suspects - Carlotta Travail
19: Christmas Sale and Mini Mysteries
14: From Body Language to Sleuthhounds
07: Ludum Dare 43 - Body Language
November
30: Meet the Suspects - Carmichael Portly
23: Meet the Suspects - Marion Wood
16: Finding Focus
09: Safe Cracking
02: Meet the Suspects - Captain Warwick Windwhistler
October
25: Halloween Sale and Mini Mysteries
19: Meet the Suspects - Sir Reginald Price
12: Meet the Suspects - Joanna Price
05: Revising Rough Drafts
September
28: Light in the Dark
21: Animation Improvements - Realized
14: Animation Improvements - Design
07: Fainter and Fainter
August
31: A Splash of Colour
24: Paging Doctor Homes
17: Talking of Alternatives
10: Costume Party
03: Lock Picking
July
27: Act 2 from On High
20: Disruptive Director
13: Rolling, Rolling, Rolling
06: NPC Biographies
June
29: Design - Stepping Sideways to Move Forward
19: Summer Sale and Mini Mysteries
15: Mini Mysteries on the Way
01: Walk the Walk
May
25: Windows 10 Pen Woes, Part 2
18: Windows 10 Pen Woes, Part 1
11: SeaLeft FAQ
04: Milestone: Act I Done-ish
April
27: Saves, the Bookmarks of Games
20: NPCs Doing Their Own Thing
13: Homes and Ampson Together and Apart
06: Dialog as Interesting Gameplay, Take 3
March
30: Dialog as Interesting Gameplay, Take 2
23: Dialog as Interesting Gameplay, Take 1
16: Dialog: The Problem
09: Iterating on the Dining Room
02: Refining with Index Cards
February
23: Refining with Puzzle Dependency Charts
16: Refining Practically
09: Sleuthhounds Valentine's Sale
02: Refining Geographically
January
26: Feature Length Design Challenge
12: The New Sleuthhounds Cast
05: New Year, New Direction
2017
December
29: Distorting Voices - Muffled Neighbours
22: Merry Christmas, 2017
18: Announcing: Sleuthhounds - The Yuletide Tail
15: Sleuthhounds Holiday Sale
08: Distorting Voices - Old Time Phonograph
01: The Yuletide Tail Trailer
November
24: Yuletide comes Early
17: Christmas Countdown
10: Short Story Published: Rites and Responsibilities
03: The Halloween Deception - Post Mortem, Part 2
October
27: The Halloween Deception - Post Mortem, Part 1
20: On Sale: The Halloween Deception
13: Adding Depth to Drawers
06: Through the Doorway
September
29: Teamwork
22: Animating in the Rain
15: Let is Snow! Let it Snow!
08: NaNoWriMoPla 2017
01: Record Your Own Line
August
25: Sleuthhounds History
18: Sleuthhounds Series Summer Sale
11: Time for a Timeline
04: Save and Load: A Developer Tool
July
28: The Cast of Robyn HUD: The Guard(s)
21: HUD Hacking v2.0
14: Intro Revisions
07: Sounds Like Wood
June
30: Blending up a Table Saw
23: Moving Ideas Forward
16: Windows Were Meant to be Resized
09: Blueprints from Buildings
02: Expanded Scenes
May
26: Artifical Intelligence: Robyn
19: HUD Hacking
12: Robyn's Wheels
05: Deleted Scenes
April
28: The Cast of Robyn HUD: Robyn
21: Lights, Camera, Action: The Intro Scene
14: The Cast of Robyn HUD: Arthur
07: Adventures in Facial Capture: Using Kinect Data (Part 1)
March
31: Stairway to Gaming
24: The Sleuthhounds Effect
17: Cops Have Vans
10: Mini Models for Detail
03: Storylines in Twine
February
24: Planning a Game Narrative
17: Evolution of a Level: Texture
10: The Valentine's Vendetta Trailer
03: Robyn HUD: The Face
January
27: Robyn HUD: The Body
20: Robyn HUD: Start of Production
13: Evolution of a Level: Form
06: Countdown to Christmas Sleuthhounds has Begun
2016
December
23: Sleuthhounds of Christmas Yet to Come
16: Accessibility for Younger Audiences
09: Reality's Not All It's Cracked Up to Be
02: A Good Heist Requires a Good Plan
November
25: Artifical Intelligence: Guards
18: Artifical Intelligence: Bystanders
11: Unconventional Design Tools for Robyn HUD
04: Brainstorming
October
31: Announcing: Sleuthhounds - The Halloween Deception
28: Coming Soon: Sleuthhounds - The Halloween Deception
21: Nice to Haves, the Final Polish
14: The Halloween Deadline
07: Halloween Countdown
September
30: Cutting through Cutscenes
23: Life of the Party
16: What's in a Name?
09: Halloween End to End
02: Ludum Dare 36: Amelia Deerhart and the Elemental Temple
August
26: Crowd Considerations
19: Interaction Density
12: Puzzle Wrangling
05: Sleuthhounds, Top Priority
July
29: Adding 3D to a 2D Game
22: Does an Idea Have Legs?
15: Adventures in Motion Capture: Using Kinect Data (Part 3)
08: Adventures in Motion Capture: Using Kinect Data (Part 2)
01: Adventures in Motion Capture: Using Kinect Data (Part 1)
June
24: Sleuthhounds Animations? Check, Check, Not Check
17: Retro Tech: Quake 3 Light Volumes
10: Adventures in Motion Capture: The Hardware
03: Interactive Cutscenes: Adding Depth and Responsiveness
May
27: From Stealth to Robyn HUD
20: Sneaking into Stealth
13: Storytelling in Computer Games (Part 2 - Looking Forward)
06: Storytelling in Computer Games (Part 1 - Looking Back)
April
29: Walking Away from Windows 10
22: Code Name: Stealth
15: Using Game Tech Creatively
08: Game Accessibility: Visual Sound
01: Walking for Ideas and Creativity
March
25: Game Dev: Unintended Sophistication
18: A Sleuthhounds Trick or Treat in March?
11: Game Design: Success through Failure
04: Critical Equipment in Critical Condition
February
26: Semispheres - Support Your Local Game Dev
19: Post Project Completion Syndrome
14: Announcing: Sleuthhounds - The Valentine's Vendetta
12: Coming Soon: Sleuthhounds - The Valentine's Vendetta
05: Sleuthhounds Production Update - Implementing Two Characters
January
29: Sleuthhounds Production Update - Designing for Two Characters
22: So You Want to Make a Computer Game: The Path Leads On
15: How to Animate When You Don't Know How to Animate
08: So You Want to Make a Computer Game: Deploying
01: State of the Union, 2016
2015
December
25: So You Want to Make a Computer Game: Sound and Music
18: Ludum Dare 34: Rise of the Weeds
11: So You Want to Make a Computer Game: The Critical Path
04: An Hour of Code for Ludum Dare
November
27: So You Want to Make a Computer Game: Custom Artwork
20: Obfuscating NaNoWriMo Manuscripts
13: So You Want to Make a Computer Game: Inventory Items
06: Satin and Sutherland Return for NaNoWriMo
04: Announcing: Sleuthhounds - The Cursed Cannon
October
30: So You Want to Make a Computer Game: Interactivity
23: Coming Soon: Sleuthhounds - The Cursed Cannon
16: So You Want to Make a Computer Game: The Virtual World
09: NaNoWriMo Prelude: Be Creative
02: So You Want to Make a Computer Game: The Artwork
September
25: More Evolving: Tweaking the Sleuthhounds Timeline
18: So You Want to Make a Computer Game: The First Step
11: Sleuthhounds: The Cursed Cannon - It's the Final Countdown
04: Vampire Bites (Ludum Dare 33 Redux)
August
28: Ludum Dare 33: You are the Monster
21: Game Performance: It's the Software's Fault
14: Short Story Published: Where There's Thunder
07: Game Performance: It's the Hardware's Fault
July
31: CMYW - Support Your Local Game Dev
24: Is it Still Scope Creep if you Plan for It?
17: After a Game Engine, You Can Program Anything
10: An Avalanche of Done-ness
03: Sleuthhounds with Style
June
26: Sources of Gameplay - Assets Versus Emergent Behavior
19: Benefit of Writing Comics: Humour or Humor
12: Evolving: Reimagining the Sleuthhounds Story Board as a Timeline
05: Evaluating: Play Testing the Sleuthhounds Story Board
May
29: Magic and Public Speaking
22: Implementation: Realizing the Sleuthhounds Story Board
15: Benefit of Writing Comics: Pacey Dialog
08: eBook Publishers: Final Comparison
01: Design: Brainstorming the Sleuthhounds Story Board
April
24: Analysis: Dialog Trees in Adventure Games
17: Benefit of Writing Comics: Writing Tight
10: eBook Publishers: Apple
03: Sleuthhounds Production Update - The Critical Path, Designing from the End
March
27: Sleuthhounds Production Update - Games Have Rough Drafts Too
20: Benefit of Writing Comics: Long-term Story Planning
13: eBook Publishers: Google
06: Announcing: Sleuthhounds - The Unlocked Room
February
27: Coming Soon: Sleuthhounds - The Unlocked Room (The First Game Demo)
20: Benefit of Writing Comics: Character Growth
13: eBook Publishers: Kobo
06: From Case Files to Sleuthhounds: Evolution of a Computer Game
January
30: Deadlines and the Estimates that Make Them (OR Why the Sleuthhounds Demo isn't Ready)
23: Adventures in Canadian ISBNs
16: Benefits of Writing Comics: Releasing Material
09: eBook Publishers: Amazon
02: New Year's Resolutions: Making Time
2014
December
26: Quack V – The Unwrapped Present
19: Benefit of Writing Comics: Constant, Regular Practice
12: What’s next? Elementary, my dear Ampson. Sleuthhounds!
05: Announcing: Satin & Sutherland – The Golden Curse
November
28: Coming Soon: Satin & Sutherland – The Golden Curse
21: Enter the Cubes
14: Covers, Judging By
07: Hello, World!