Behind The Scenes: Our The Unfinished Swan Review

Yesterday, at 10am, the embargo for The Unfinished Swan lifted. A little earlier than normal (apparently due to certain US sites going live early), perhaps, but due to a very late night the day before, we were more than ready. What we weren’t quite ready for was the almost universal praise that the layout and design of the piece attracted, something that we hadn’t actually thought that highly about until it landed.

I had the idea a couple of days before the review code landed a week or two back, but hadn’t started to figure out how I’d actually do it until about 9pm on Sunday night. As it happens, and something that seems to have bypassed a fair chunk of the people letting us know that they liked it, it was pretty easy. If anyone’s interested, I’d like to explain how it was done.


unfinished swan

Web development, at this level, is reasonably trivial. We use WordPress, so a massive portion of the hard work is already done in terms of delivering the content to the reader and tying everything together – you just need to coax what you want out of it. Coupled with jQuery, one of the best Javascript libraries, there wasn’t actually a huge amount to create from scratch.

The first thing I wanted was a brand new page template. Because of the modular way I’ve built this latest theme, the templates are actually driven by categories. That is, if we want to use a wide format page (for a big review or a video interview, perhaps) it’s just a case of picking the relevant category from WordPress’ back end. I created the category required, got its ID, and added it to our modified single.php, which just checks the ID of the category used in the post, and pulls the relevant page.

if (in_category(‘X’)) { include (TEMPLATEPATH . ‘/wide-templatesingle.php’); }
elseif (in_category(‘Y’)) { include (TEMPLATEPATH . ‘/tusreview-templatesingle.php’); }
else { include (TEMPLATEPATH . ‘/normal-templatesingle.php’); }

There’re three main page layouts for single posts – the wide one (ID ‘X’), the new one for the Unfinished Swan review (ID ‘Y’) and the regular one, used on most posts (including this one). Obviously I’ve replaced the actual IDs with X and Y. Those template pages actually replace the standard WordPress single.php, and pull in everything the page needs, from the header section, the background, the side bar, the comments and the story itself.

In this case, and it was a decision I made quite early, I didn’t want any comments. The idea was that people would read and like the review, and then share it over Twitter. One of the things I’ve found about TSA is that if our readers like a story they’ll comment (which is always lovely to see) but it rarely spreads much further unless we get lucky. In this case, sharing on social networks is something we pushed quite hard, and that seems to have worked.

Back to the code, then, and the PHP is remarkably simple. It does our basic user security stuff, loads the WordPress header, loads another page that contains the layout, and then renders the footer section, and the basic Javascript that the site normally loads. In hindsight this latter load wasn’t needed, but there’s little point changing it now. The actual page itself, the one that loads the story and displays it, is where the real stuff happens anyway.

It starts with the usual WordPress check:

if (have_posts()) : while (have_posts()) : the_post();

And then jumps straight into some hugely ugly and W3C invalid inline style sheets. These should have been loaded in the head section, but that would have meant further lower level changes and didn’t seem necessary for the scope of the project (and the limited development time we had) – remember, I still had to actually review the game after all this, at the moment the post in WordPress is (literally) just Lorem Ipsum.

The CSS consists of a few wrappers (to keep the text neat and centred) and a body class that adds a subtle inset shadow (to create a gentle vignette look). Some other basic styling set the font types, sizes and so on:

body {margin:0;padding:0;
-webkit-box-shadow: inset 0px 0px 80px rgba(0,0,0,0.1);
-moz-box-shadow: inset 0px 0px 80px rgba(0,0,0,0.1);
box-shadow: inset 0px 0px 80px rgba(0,0,0,0.1);}
.wrapper {width:960px;margin:auto;height:auto;overflow:hidden;}
.tus {width:560px;margin:auto;color:#000;padding-top:80px;height:auto;overflow:hidden;font-family: ‘Rosarivo’, serif;position:relative;z-index:5;}
.tus p {clear:both;margin-bottom:20px;cursor:default;text-align:justify;text-justify:inter-word;font-family: ‘Rosarivo’, serif;line-height:1.8;opacity:0;}
.tus h1 {width:560px;float:right;margin-bottom:20px;font-size:36px;letter-spacing:-1px;font-weight:700;font-family: ‘Rosarivo’, serif;}

The font, Rosarivo, is a Google Web Font and is loaded just above the CSS – I wanted the page to have a very distinct, un-TSA look about it, and a fresh, serif typeface seemed to do just that (and fit with the game’s storybook look and feel). I then needed CSS to control the positioning of the images and the header tags:

.tusleft {float:left;padding-right:10px;padding-bottom:10px;margin-right:10px;border-right:1px solid #aaa;}
.tusright {float:right;padding-left:10px;padding-bottom:10px;margin-left:10px;border-left:1px solid #aaa;}
.tusmid {margin:10px 40px 10px;border-top:1px solid #aaa;border-bottom:1px solid #aaa;padding:10px 0;}
.tusfooter {margin:20px auto 0px;padding-bottom:80px;border-top:1px solid #000;font-size:12px;color:#444;width:560px;padding-top:20px;font-style:italic;font-family: ‘Rosarivo’, serif;}
.tusfooter h2 {color:#888;margin-bottom:20px;font-size:12px;font-style:italic;font-family: ‘Rosarivo’, serif;}
.tusfooter h2 a {color:#444;font-size:12px;font-style:italic;font-family: ‘Rosarivo’, serif;text-decoration:none;}
.tusfooter h2 a:hover {color:#888;font-size:12px;font-style:italic;font-family: ‘Rosarivo’, serif;text-decoration:underline;}

There’ll be people looking at this and weeping. But time was short, and it seemed to do the job across every device I could test it on, and the browser support should be fine on anything above (and including) IE9. The PHP then renders the content, which again, is standard WordPress stuff.


Read the rest of this entry »


At this point, the page was working. It was obviously dummy text, but it was displaying as I wanted it to. Obviously, mind, it was invisible, due to the opacity:0 in the CSS for the paragraph tags. Then I rendered the footer, which was a few Twitter links (that had to be inserted after the post went live so we could grab the Twitter IDs) and a simple credit link. Twitter’s ‘web intent‘ links are quite nice – if you’re logged in they automatically do the hard work for the end user.

So, now, the jQuery that would let the page come alive.

Bear in mind that I’m absolutely not a JavaScript expert by any stretch, but hopefully this is all easy to follow. I started with the usual: a ‘script’ tag and this:

jQuery(document).ready(function ($) {

That tells the browser to do the following once the page is ready. Immediately after that, I added a ‘notclicked’ class to everything (which was defined in the CSS as ‘opacity:0;’), thus:

$(“.tus img”).addClass(‘notclicked’);

Then it was a case of asking jQuery to wait for a click on any of the paragraph or image tags, and change the opacity of that particular tag to 1.

$(“p”).click(function () {
opacity: 1
}, 250, function() {

$(“img”).click(function () {
opacity: 1,
}, 250, function() {

The change from transparent to solid takes 250 milliseconds, and the jQuery also removes the ‘notclicked’ CSS class. A couple of other things I wanted to happen was a cue that the page wasn’t dead (although at least one high profile game developer immediately thought it was) by slowly revealing the Unfinished Swan logo, and then the footer in case the reader quickly scrolled down. Again, fairly trivial:

$(“h1 img”).delay(5000).animate({
opacity: 1
}, 3000, function() {

opacity: 1
}, 3000, function() {

The logo appears after 5 seconds, the footer after 10. This probably needed a bit more balancing, but I thought the payoff for those that stuck with the page was probably greater this way than if we’d have given too much signposting. The only other thing to happen was the paint splat, something that really brought the page to life. I tried for a while to recreate the ball of paint flying to the cursor, but it wasn’t getting anywhere. Instead, we just used some Photoshop brushes to make a transparent .png and loaded that at the top of the page, albeit transparent, with an ID and a class we could manipulate later.

The jQuery for this took the longest, although that’s mainly because I’d messed up with the making of the img tags transparent earlier, meaning you had to double click first to make the paint appear, a bug that took about 90 minutes to figure out.

$(“.wrapper”).live(“click”, function(e){

var rNum = (Math.random()*360)-2;
‘-webkit-transform’: ‘rotate(‘+rNum+’deg)’,
‘-moz-transform’: ‘rotate(‘+rNum+’deg)’
} );

top: (e.pageY -150) + “px”,
left: (e.pageX -150) + “px”



This just looks for a click on the main wrapper div, picks a random number (which translates to a degree of rotation) and then rotates the div accordingly. It then places it at the co-ords of the mouse (offset by half the .png’s size, so it’s centred) and then quickly fades it in, waits 250 milliseconds, then fades it out again. The code to reveal the text is already underway, so the two just work nicely together, after a little bit of tweaking.

That’s literally all there is to it. It’s hugely simple, really, but seemed to have a fairly wideranging appeal. We’ve seen tweets from developers, publishers, journalists and – thankfully – our readers, and for the first time (to my knowledge) we got a nod from the main @playstationeu account. That wasn’t really the aim – and nor was it anything to do with Sony as one site suggested – it was just a fun experiment for a game I really liked and wanted to present a little bit differently.

Oh, and the review. I had to write the actual review, too.

Was it a success? Depends on how you measure success, I guess. It was interesting to see how a fairly standard bit of writing was so widely distributed solely because of the way it was delivered. It just goes to show that with a little bit of effort you can completely transform an article, something that we’d expect the bigger outlets to be doing on a much more regular basis.



  1. I keep clicking on this page but much of the text still remains gibberish to me…

    Loved the review yesterday, a nice surprise after I figured out why it was blank…

  2. The review was fantastic. A realy great way to present something different.

    I just wish I could understand what you’ve written above ;-)

  3. I really liked the presentation of the review. Great job, indeed. I get why you didn’t want the comments section beneath it. At least we can praise your review here. :P

    • Even aside from the social network benefits I felt it was quite refreshing not to have comments.

  4. I thought my VPN had cocked up again as it so regular does. A really nice idea and great review.

  5. Very stylish review, though I must admit I did think my browser wasn’t rendering the page correctly at first until I randomly clicked the white space :P

  6. I thought it was excellent. All that code made me temporarily dyslexic though. (I joke I joke)

  7. I was sat pressing F5 and wondering why i couldn’t read it!

    If only i had engaged my brain….. Now i can read it, Top Review.

  8. It was a cool and imaginitive way to present the review. Hope to see more in the future. Nice to see the behind the scenes of it as well and how a bit of CSS and JQuery can transform a feature.

  9. I unfortunately had to use the iPhone ‘Reader’ as it wouldn’t load on my iPhone 5 or ps3. That may be down to my slow Internet though…

  10. Amazing job!!

Comments are now closed for this post.