What if you could use APNs (Apple Push Notification Service) to send push notifications for your website users right on their desktop? Since OS X Mavericks it has been possible to dispatch push notifications from your web server directly to users.

In this article, I’ll provide step-by-step instructions of implementing Safari Push Notifications directly in your website.

Table of Contents

Prerequisites

In order to get everything up and running, you need at least:

In this example, I’m using Heroku and node.js (+ Express) for serving both the website content and push package.

Registering a Website Push ID

First step is to register a Website Push ID. This is done at “Certificates, Identifiers & Profiles” section of the Member Center.

Under “Identifiers”, you’ll find a sub-section titled Website Push IDs.

Insert description and identifier, which is recommended to be in reverse-domain name format, starting with “web”. In my case I’m using web.com.herokuapp.hakonieminotification as an identifier.

After you’ve registered your Website Push ID, you’re ready to generate a certificate.

Generating a Certificate

This can be considered as the hardest part of the tutorial. It requires multiple steps and all of these needs to be completed.

We start our journey by logging into Developer Overview. Under there you should see a folder link titled Certificates. Navigate there and you go into a same view where we’ve created Push ID. This time we select Certificates and create a new certificate.

Now you should see a list of Development and Production certificate types. Under Production there is a checkbox for Website Push ID Certificate. After selecting that you’ll get a prompt about which Website Push ID we are going to use. This should be obvious.

Now we’re going to create a CSR by using Keychain Access. Launch it and select Keychain Access » Certificate Assistant » Request a Certificate from Certificate Authority.

Fill in your details (leave empty if unsure). Request is Saved to disk. Now you should be able to save [filename].certSigningRequest file to the Desktop.

Now that we’re done with the CSR file we can continue our process on Development Portal and generate our certificate. After that we’re able to download our .cer file. After downloading it, double-click the .cer file.

You should end up in the Keychain Access, under login section, where you should see your certificate. Right-click it and select “Export Website Push ID [web.your.reversed.domain.name]“. This should open up a dialog where you can save [filename].p12. Then you’ll be prompted with the password which will be used to protect the exported item. In our case this can be left empty.

Now that we’ve created .p12 file, we can proceed on creating the actual package.

Contents of the Push Package

When website asks user for permission to send push notifications, Safari will ask your server for a push package. This package is a normal zip file containing following files (all files are required, and no other files can be included):

MyPushPackage.pushpackage
  icon.iconset
    icon_128x128@2x.png
    icon_128x128.png
    icon_32x32@2x.png
    icon_32x32.png
    icon_16x16@2x.png
    icon_16x16.png
  manifest.json
  signature
  website.json

Every icon file and website.json are created by you, while manifest.json and signature files are generated by a script.

Website.json

Website.json contains following information (mine as an example):

{
    "websiteName": "Heroku Push Notification Test",
    "websitePushID": "web.com.herokuapp.hakonieminotification",
    "allowedDomains": ["http://hakonieminotification.herokuapp.com"],
    "urlFormatString": "http://hakonieminotification.herokuapp.com/%@/",
    "authenticationToken": "19f8d7a6e9fb8a7f6d9330dabe",
    "webServiceURL": "https://hakonieminotification.herokuapp.com"
}

This is described in the Apple Documentation as:

  • websiteName – The website name. This is the heading used in Notification Center.
  • websitePushID – The Website Push ID, as specified in your registration with the Member Center.
  • allowedDomains – An array of websites that are allowed to request permission from the user.
  • urlFormatString – The URL to go to when the notification is clicked. Use %@ as a placeholder for arguments you fill in when delivering your notification. This URL must use the http or https scheme; otherwise, it is invalid.
  • authenticationToken – A string that helps you identify the user. It is included in later requests to your web service. This string must 16 characters or greater.
  • webServiceURL – The location used to make requests to your web service. The trailing slash should be omitted.

Creating the Push Package

Now that we have our content (icons + website.json) set up, we can create both manifest and signature files. This is done with createPushPackage.php script (or with push_package gem).

Manifest

The manifest is a JSON dictionary of your each file in push package where filename is the key and SHA1 checksum is the value.

createPushPackage.php contains a function create_manifest($package_dir) for creating the manifest. Use this and it’ll generate a file manifest.json into your .pushpackage directory.

Signature

Remember the .p12 we created in the beginning? This file is passed to the function create_signature($package_dir, $cert_path, $cert_password). If you left the password empty, just pass empty string to the function.

Archive file

There is a function called package_raw_data($package_dir) for creating the ZIP file. This is the package itself we’re serving for the Safari browser. If you’ve successfully completed the previous steps, you should now have created a valid package.

Serving Content and the Push Package

I’ve split this into two sections: server-side and client-side configuration. First we’ll start with the server-side configuration.

Server-side Configuration

My Node / Express application looks like:

var express = require('express');
var app = express();
var port = process.env.PORT || 3000;

app.listen(port);

app.get('/', function(req, res) {
    res.sendfile('index.html');
});

app.post('/v1/pushPackages/web.com.herokuapp.hakonieminotification', function(req, res) {
    res.sendfile('SamuliHakoniemi.pushpackage.zip');
});

app.post('/v1/log', function(req, res) {
});

This should be quite self-explanatory, but let’s go it quickly through:

  • Line #7 – serving the index.html file that requests the permission from the user to use push notifications.
  • Line #11 – serving the push package which is requested by the browser as a POST request
  • Line #15 – for logging (errors), where HTTP body contains a JSON with key logs and as a value there’s an array of strings describing errors.

Server-side Endpoints

As you might have noticed, there’s a certain logic with the endpoints. Notice that “version” is always v1 and deviceToken is the token you’ll receiver from the client when user grants a permission:

  • webServiceURL/version/pushPackages/websitePushID – location of the push package, requested by POST request.
  • webServiceURL/version/devices/deviceToken/registrations/websitePushID – when an user grants a permission or later updates his permission level, a POST request is sent. When user removes the permission for push notifications, a DELETE request is sent.
  • webServiceURL/version/log – when an error occurs a POST request is made to this endpoint

I suggest reading articles in Resources section for more verbose explanation of the endpoints.

Client-side Configuration

There are different code examples of implementing the permission request. This simple piece of code is used on my site:

var pushId = "web.com.herokuapp.hakonieminotification";

var subscribe = document.querySelector("#subscribe");
subscribe.addEventListener("click", function(evt) {
    pushNotification(); 
}, false);

var pushNotification = function () {
    "use strict";
    
    if ('safari' in window && 'pushNotification' in window.safari) {
        var permissionData = window.safari.pushNotification.permission(pushId);
        checkRemotePermission(permissionData);
    } else {
        alert("Push notifications not supported.");
    }
};

var checkRemotePermission = function (permissionData) {
    "use strict";
    
    if (permissionData.permission === 'default') {
        console.log("The user is making a decision");
        window.safari.pushNotification.requestPermission(
            'https://hakonieminotification.herokuapp.com',
            pushId,
            {},
            checkRemotePermission
        );
    }
    else if (permissionData.permission === 'denied') {
        console.dir(arguments);
    }
    else if (permissionData.permission === 'granted') {
        console.log("The user said yes, with token: "+ permissionData.deviceToken);
    }
};
  • Lines #4 – #7 – since I’m using a separate button for subscribing, we need to add event listener for it.
  • pushNotification() – this function is called after the subscribe button is clicked and it will check whether push notifications are actually supported. And if so, it makes the initial call for the checkRemotePermission function.
  • checkRemotePermission() – this function makes the actual request for the permission and is executed again as the callback of function window.safari.pushNotification.requestPermission(url, websitePushID, userInfo, callback).

Above lines of code are from the actual implementation I’ve made. You can test it at: http://hakonieminotification.herokuapp.com.

Possible Problems and Solutions

You may encounter problems while you’re first trying to implement push notifications.

The most common one seems to be that user denies a permission without client even asking for it. This is because the request never reaches the push package (the endpoint isn’t correct). This use case is not described in the Apple’s documentation, which only claims that “denied” state occurs only when user denies the permission.

Other problem seems to be that once you’ve granted or denied the permission, you’re never seeing the permission prompt again. In order to fix that, you can configure permissions from Safari » Preferences » Notifications.

For other troubleshooting and interpreting the log messages, I suggest reading the Troubleshooting section from Apple’s documentation.

Resources

I hope that everything went well after reading my article. In any case, I suggest reading also these articles which contain very valuable information for implementing push notifications.

The final version of iOS 5 has been finally released and there’s lots of buzz going around it’s new features. Most of the discussion focuses on the operating system itself which is totally understandable. There are lots of improvements and nifty little features to play with.

But one thing that seems not to get such attention is what iOS 5 brings to us, web developers, and how it improves the experience with web applications.

In this article I’ll go through most of the major features that are included in iOS 5 for web developer point-of-view.

Table of Contents

-webkit-overflow-scrolling

This is probably most anticipated feature for web applications. Until today it hasn’t been easily possible to add scrollable content in web document.

Briefly, all you need to define is:
elem {
 overflow:scroll;
 -webkit-overflow-scrolling:touch;
}

To achieve proper scrolling support for iOS 4 and/or other devices, I strongly suggest using iScroll 4.

And if you want to display scrollbars all the time, read this post: Force Lion’s scrollbar back. It will help you on displaying the scrollbar while user is not accessing the scrollable area, which is a very good visual guidance for user that content can be scrolled. But be warned: “custom” scrollbar won’t update it’s location while user is scrolling and meantime there are two scrollbars displayed.

position:fixed

Position:fixed is well-known CSS property that hasn’t earlier been included in iOS. But now it’s there, ready to use.

I noticed that setting a fixed element it has partial transparency by default. You even can’t turn it off by setting opacity to 1.0. If you happen to know how to solve this, please comment on my blog.

New Input Types

iOS5 provides several new input types that didn’t exist earlier on iOS4. These input types are: date, time, datetime, month and range.

I have to mention that the user experience with range is awful – with your (fat) finger you end up selecting the whole control instead of value slider all the time.

Note: input type=”file” isn’t still working. “Choose File” button is displayed, but at the same time it’s disabled.

WOFF Font Support

iOS 5 supports WOFF (Web Open Font Format) fonts. This is good news in a way. I haven’t personally tested whether there’s any benefit compared to SVG or TTF from a rendering or performance point-of-view.

Web Workers

Web Workers API is a bit less familiar for many developers. They allow to run long-running scripts without halting the user interface and they’re not interrupted by other actions.

The problem with Web Workers on iOS 5 is – as you may guess – the perfomance. You can try Web Workers with Javascript Web Workers Test. But I have to mention that while it took only about five seconds with my workstation, the same execution time with my iPhone 4 was 106 seconds. So as you can see, there’s a huge difference on performance.

contentEditable

iOS 5 supports contentEditable attribute, which allows rich text editing (RTE) of content. This is very welcomed feature offering the possibility of building WYSIWYG editors that can be used eg. with iPad.

Read more about this feature at: WYSIWYG Editing (contentEditable support) in iOS 5.

classList API

ClassList API is very useful while writing native JavaScript. It has few simple functions (like add(), remove(), toggle()) that are meant for handling classNames in an element.

If you want to implement classList API and ensure backwards compatibility, use classList.js polyfill, written by Eli Grey.

matchMedia()

Function matchMedia() is relatively new function for detecting media queries with JavaScript. The implementation is very simple:

if (matchMedia("(min-width: 1024px)").matches) {
    alert('your screen is at least 1024px wide');
}
else {
    alert('your screen is less than 1024px wide');
}

Can’t say how useful that is yet, since I’ve personally never used it before. But we’re living the times of Responsive Web Design and there may be conditions where this may be needed.

For browsers that doesn’t support matchMedia(), there is a matchMedia.js polyfill available, written by Paul Irish.

And if you’re more interested in similar logic, I suggest reading about yepnope.js.

Changes in Gestures Events

Gestures events (gesturestart, gesturechange, gestureend) now returns pageX and pageY values for events – in addition to scale and rotate values. These values didn’t exist in iOS4, forcing developer to retrieve X/Y-coordinates with corresponding touch events.

Compass

iOS 5 comes also with two neat properties: webkitCompassHeading and webkitCompassAccuracy. You can read more about them and test them at: Taking a new device API for a spin.

WebGL

Well… WebGL is kind of implemented in iOS5. But only for iAd.

However there are rumors promising good, and already it’s said that “things are in place” but they’re just not fully working (or have been disabled). So, let’s keep our fingers crossed that next (minor) update will include support for WebGL.

Anything Else?

Mark Hammonds has written a comprehensive article in mobiletuts+, titled iOS 5 for Web Devs: Safari Mobile Updates. That’s really worth of reading!

And if you’re interested in browser performance in general, then you should read iOS 5 Top 10 Browser Performance Changes.

If there are other things to mention, feel free to comment and bring your ideas up. I’ll keep on updating this post right after new information arises about iOS 5.

More than two years ago CSS Animations were represented in WebKit. Up until now, they’ve been supported only in Safari and Chrome.

Recently I noticed, when upgrading to Android 3.1 that it dramatically enhanced the performance of CSS Animations and Transitions. And only few days ago, Firefox 5 Beta was released which has decent support for keyframes, and also better performance for transitions. Therefore I decided to write a brief article about CSS Animations and using keyframes.

In this article we will go through what it takes to create keyframe animations. I’ll create a simple demonstration of an icon character which comes alive with a little help of keyframes.

Foreword

This article won’t help with the basics and all the details of CSS Keyframes. If you’re unfamiliar with keyframes, I strongly suggest reading Smashing Magazine’s article “An Introduction To CSS3 Keyframe Animations”.

If you’re also unfamiliar with CSS Transitions, you can also read my article “CSS3 Transitions – Are We There Yet?”.

It’s good to notice that there already exists tools for creating proper CSS Animations, like Animatable that are worth of checking. Especially, if you’re not that much of a fan writing endless keyframes rules and css declarations

Browser Support

I’ve tested this example with recent builds of Google Chrome, Firefox 5 Beta, iPhone 4 / iPad and Android 3.1 with Browser (Chrome) and Firefox Beta. So, if you’re viewing this article with any of those, then you’re good to go.

There are indications that also Opera will support CSS Animations in near future. Let’s see when that will be. However, Internet Explorer won’t be supporting CSS Animations – they’re not even supporting CSS Transitions yet.

The Icon

In this example we’ll build an icon with separate head, body and background. We’ll add some movement with keyframes to each object while trying to achieve as realistic result as possible without too much of an effort.

The character icon in demonstration is from Battleheart, developed by Mika Mobile.

The Head

Wizard's head We start by defining the behavior of an animation for the head. This is done by defining a keyframes rule called “breathe-head”.

@-webkit-keyframes breathe-head {
    0% {
        -webkit-transform: rotate(1deg) translate3d(0px, 0px, 0px);
    }
    40% {
        -webkit-transform: rotate(-3deg) translate3d(-2px, -1px, 0px);
    }

    100% {
        -webkit-transform: rotate(1deg) translate3d(0px, 0px, 0px);
    }
}

NOTE: I’m using property called translate3d for moving the head slightly backwards. It’s good to understand that only transformable properties (+ opacity) can be animated with hardware acceleration. Translate3d(0,0,0) is good to have to ensure hardware acceleration of animations even if it’s not needed for any other use. I’ve even encountered many situations where animation performance hasn’t been smooth eg. on iOS Web Applications until (over)usage of translate3d().

Twice the Fun!

For some (unknown) reason, it isn’t possible to add -moz-keyframes rule at the same declaration, so we need to declare keyframes rules again:

@-moz-keyframes breathe-head {
    0% {
        -moz-transform: rotate(1deg) translate(0px, 0px);
    }
    40% {
        -moz-transform: rotate(-3deg) translate(-2px, -1px);
    }

    100% {
        -moz-transform: rotate(1deg) translate(0px, 0px);
    }
}

I’m not using translate3d() since it seems Firefox only understands translate(). But it’s good enough for performance since it should be also hardware accelerated on Firefox.

The Body

Wizard's body Next, we’ll animate the body of the character. We don’t need any wildly bouncing animation since we’re operating with an (small) icon. Constant movement has to be subtle or otherwise it can start to irritate users:

@-webkit-keyframes breathe-body {
    0% {
        -webkit-transform: translate3d(0px,0px,0px);
    }

    40% {
        -webkit-transform: translate3d(0px,-3px,0px);
    }

    100% {
        -webkit-transform: translate3d(0px,0px,0px);
    }
}

And the same rules needs to be applied for -moz-keyframes like we did with the head.

The Background

Wizard's backgroundI wanted to add something more to a movement and decided to draw a subtle background “sun” which keeps rotating behind the character:

@-webkit-keyframes rotate-bg {
    0% {
        -webkit-transform: rotate(0deg);
    }
    100% {
        -webkit-transform: rotate(360deg);
    }
}

Rotating background is very straight-forwarded; we rotate it once per timeline we’ll define later on.

Keyframes are Done – What Next?

Now that we’ve defined keyframe rules, we must take them into use:

.character {
    -webkit-animation: breathe-body 3000ms infinite both ease-in-out;
    -moz-animation: breathe-body 3000ms infinite both ease-in-out;
}

.character .head {
    -webkit-animation: breathe-head 3000ms infinite both ease-in-out;
    -moz-animation: breathe-head 3000ms infinite both ease-in-out;
}

.rotating {
    -webkit-animation: rotate-bg 30s infinite linear;
    -moz-animation: rotate-bg 30s infinite linear;
}

I’m using short-hand declarations, and eg. for .character .head we declare: “Use breathe-head keyframe rules in a three seconds long loop which last infinite time and is animated with in-out easing equation”.

Value “both” stands for animation-fill-mode should define the status of first and last keyframe. But in my case I didn’t notice anything special when I trying other possible values “forwards” or “backwards” (this could be since both start and end keyframe has similar values).

The End Result

I needed to declare more CSS for getting things in correct place. But the example code above is practically the soul and heart of the animation. But here is the end result of an animated wizard icon:

 

 

How do you like it? It’s my first animation ever :).

Please notice this article is outdated, after the client and game mechanics were renewed on May 2011!

I strongly suggest reading STARTERS GUIDE at Shadow Cities forum instead of this article.

Shadow Cities is a location based MMORPG which was just released for iPhone and is currently in beta stage (available only in Finland).

In order to get you started, I decided to write this post. I’ve myself played only for two days, nearly as long as the game has been publicly available. So these advices are from newbie to newbie :). And it’s very possible some of these advices gets outdated in near future.

These advices are unofficial and made from personal perspective. By the way, I’m playing with character called “Macaco” for the Architects.

Last updated on 13th of Nov, 2010

Table of Contents

Read the Help Section

Shadow Cities has a brief and clear help section, which you really should read before starting your career as a mage. It can also be found online from Shadow Cities Help Section.

Seriously, read it.

About the Terminology

Teams
You’ll belong either on the Architects or the Animators. On daily basis, your side will mostly affect on how you’re able to travel (or warp) in your area without moving physically. On weekly basis, there are different kind of campaigns where both teams compete against each other.
Hitpoints
Mages don’t have hitpoints, only spirits do. This means neither you can’t get killed, nor can the other mages. Every time a mage is hit, he’ll lose (only) mana.
Mana
Whenever you want to do something cool, you’ll need mana for that.
Experience
In order to get on next level, you need to gain experience. The best way to gain experience is to kill spirits.
Spirits
Spirits are the non-player characters of the game, which you’ll hunt down and kill until your screen has a greasy Z figure on it. And then you’ll kill some more.
Energy
Energy can be considered as “experience points of the team”. It seems there will be different kind of contest every week between teams and the amount of collected energy is in important role. The main resource for energy are the dominators.
Warping
This is how you travel inside the game. Or of course you can travel physically, but by warping you’ll get to different places very quickly. Warping back and forth doesn’t consume any mana.
Buildings
There are different kind of buildings, and the dominators are the most important ones. These towers has several meanings which you can find out by reading through the help section.
Power
Power is needed in order to build specific type of buildings. Dominators are generating power, while other type of buildings are consuming it.
Energy Gateways
These are burning flames around the realm. They can be conquered by attaching dominators to them. They also can be bought with mana bottles, making the buyer as the Shadow lord of the realm (the close surroundings).

What is Mana?

On the bottom left corner of the main view, there’s a blue bottle and a tiny meter. This is your mana. Good thing to remember is that nearly every action requires mana in some way.

The meter will show much mana you’ve charged with, and the number above the bottle displays the amount of mana bottles. One bottle will recharge your mana completely. Full charge of mana will be enough for 3 – 4 war spells.

Mana bottles are also the currency in the Shadow Cities. This is quite important to realize. Don’t use bottles for recharging whenever you’ve time to wait. Mana will automatically regenerate, but the bottles won’t. Therefore it’s the best way just to wait for recharging. Trust me, you’ll eventually end up in a situation where you’ll curse yourself for spending mana bottles in vain.

There are three ways to gain more mana bottles: 1) buying them from App Store, 2) researching (see “What Are the Captured Spirits?”) and 3) by completing tasks (little yellow exclamation or question mark on bottom right of the screen).

How Do I Gain Experience?

The best way to gain experience is by killing spirits. There are different kind of spirits, but most of them are quite easy catches (Rank 1).

Spirits are flying around and will not attack you until you’ve first attacked them. You should definitely go after them whenever you’ve got enough mana to throw at least two war spells.

It’s not cool either to kill a spirit someone else is trying to kill. No matter if he’s an Architect or an Animator. The amount of experience is nothing compared the amount of disrespect you gain.

What Are the Captured Spirits?

After you kill a spirit, it’s captured. The list of captured spirits can be found by pressing the white Shadow Cities icon on the bottom right. And on the sub menu, go for the yellow icon on the top left.

There are 12 different kind of spirits in total, with three different colors (red, green, blue) and four different houses (Dannan, Drioma, Inrik, Tiermes).

There are two things that makes some spirits more worthy than others: 1) spirits have different values (marked with stars) and 2) some type of spirits are used to research mana bottles.

Captured spirits can be used for generating energy. The value (no star, one star, three star) defines the amount of energy you’ll generate while donating the spirit. They can also be used for researching mana bottles.

The point here is to focus on more valuable spirits and / or spirits that can be used for researching. I’ve noticed that more valuable spirits (especially three stars on them) are harder to capture, but you’ll also gain more experience by killing them. So, I definitely recommend hunting down these certain type of spirits.

How to Kill Other Players?

Never ever go after other players! It just doesn’t make sense. At the moment, other players can’t be killed (I personally hope this get changed). They’ll only lose their mana – and so do you. If you encounter an hostile situation you should just warp away.

Only reasonable situation for attacking opponent players is when they’re trying to destroy your buildings. However, it’s easy for them to logout and come back later with recharged mana and continue the destruction. But at least you’ve tried your best :).

How to research?

You can research by selecting yellow character icon from top left and then the mana bottle from sub menu. In research menu you see three headers labeled as “Research”, “My Public Projects” and “Other Public Projects”.

Currently it seems that “Red Dannan”, “Green Drioma” and “Blue Inrik” are used for researching purposes. I don’t know whether this will change on some interval.

You should check what type of spirits you have for researching purposes from “Research” view. But don’t start your own project yet. Instead you should check through ongoing public projects whether you can contribute to them.

Every mage who participates on research project will gain one mana bottle. If they participate by adding multiple type of spirits they still gain only one bottle. Therefore it makes no sense to contribute with more than one spirit.

When you start your own project, it will appear as public project, but only to your friends. However, when you participate on a project created by someone else, this project will be seen only by his friends.

How to Collect Energy?

The dominators are the main source of energy. Dominators will slowly generate energy, and when they’re filled with energy, a red circle will appear around them and you can harvest the energy. You’re also capable of harvesting your team members dominators. Another way to collect energy is to donate captured spirits (see above).

You’ll also gain (or rob) energy when destroying opponents dominator which is fully charged. It’s extremely rewarding when you stumble upon a field of opponent dominators.

It’s rather important to collect energy. Energy will help your team to win the weekly campaign. And you’ll be rewarded according to the energy you’ve collected.

What Should I Build, And Why?

Build dominators. Focus on building the dominators. And harvest the dominators as often as possible.

Distribute dominators. The amount of power generated by dominators doesn’t depend on the location of dominator. In addition, your dominators will generate more energy in average when they’re distributed to different gateways. One dominator per player, per gateway will generate 12 energy points, while two of them will generate only 8 points each. If you connect eg. five of your dominators to a single gateway, they’ll generate only five energy points each.

Always destroy enemy dominators when you encounter them. This is the situation where mana bottles are essential because you really want to get rid of them all. At the moment it seems not many players are fully aware of this. By destroying opponent’s dominators you both gain experience and harm their infrastructure.

You’ll find out the meaning of all the other buildings while you’re progressing on the game. But the dominators are the constitution of the game.

What is Warping?

In order to get easily on different places, you’ll need to warp. Whenever there’s something that belongs to your team, you can warp on it. That is very good thing to remember.

It’s possible to warp longer distances. This is done through beacons, a specific type of building which has to be built by someone. You can see the available beacons by entering into expanded view by clicking on the white Shadow Cities on the bottom right, and then on the submenu, click the white cloud icon on bottom left.

What Spells Should I Choose?

I have no straight answer on this, so I’ll make a good guess:

  • Upgrade your war spell first
  • Catchers are excellent for capturing loads of (both common and rare spirits). I recommend learning this spell on second.
  • Ability to heal makes you feel like a good mage when you’re donating your mana to other players. However, at the beginning it’s useless for healing buildings while most of them can be destroyed with couple of war spells
  • You won’t be needing beacons in the beginning. They consume lots of power while they won’t provide you any value. Don’t go for them.
  • Traps are always cool. But lower level spell is quite useless, since the trap can be destroyed with one or two war spells

So in general, consider evolving only in the war and catcher spells. They are the spells you’ve personally needing most. Your team will need you, but not when you’re on level 5.

Closing Words

I just hope this helps you to get started. Playing Shadow Cities isn’t that complicated. But I’ve heard some of the new players complaining about the icons and terms that they’re not self explanatory, and you easily end up wandering and doing something meaningless. But it’s good to remember that the game is in beta phase and at least I do think the game will evolve from this point.

CSS3 Transitions - Are We There Yet?
Cascading Style Sheets 3 has been available for “some time” (first time introduced nine years ago). However, CSS3 hasn’t been available in common use for more than two years. CSS3 Transitions in real use were introduced in late 2007 by Safari. At that time, they were referred as “CSS Animations”, but the terminology changed when Safari introduced their proprietary features also called CSS Animations I’ve split this topic in two articles. In this first article I’ll make a generic overview on CSS3 Transitions. Additionally, I’ll introduce some of the basic implementations and evaluate few CSS properties, meant for creating transformations and transitions. This article also contains references to excellent CSS3 articles. So after reading this article, go ahead and upgrade your knowledge about CSS3 Transitions with them.
This article is also published in Finnish, titled as “CSS3 Transitiot – olemmeko jo perillä?” at gfx.fi. Like mentioned above, the whole topic has been split in two parts. The first part is offering a general overview in current status of CSS3 Transitions. Second part is called “CSS3 Transitions – Problems and Solutions”, which will explain in details how CSS3 Transitions behave in different browsers. The first part of the article contains following sections: Getting Started

Getting Started

To get started, you’ll need a browser that supports CSS3 Transitions:

What about Internet Explorer?

At the moment it’s announced that Internet Explorer 9 isn’t going to support CSS3 Transitions. The best support for IE Transitions and Transformations can be achieved with Matrix Filter. Additionally, I recommend reading an article titled Cross-Browser Animated CSS Transforms — Even in IE, written by Zoltan “Du Lac” Hawryluk who is the author of cssSandpaper. The Basics of the Basics

The Basics of the Basics

Unfortunately, there’s no “one rule to rule them all” for transitions. Actually every browser has their own proprietary properties. Fortunately the syntax for values are consistent.

What can be transitioned?

Most properties can be transitioned and therefore I see no reason to list them here explicitly. However, there are some difference between browsers and the most obvious exception is that Firefox 3.7a doesn’t support transition of transformations at all.

The property values for transitions

Transitions have four values to declare at maximum: Shorthand:
-webkit-transition: property_name duration timing_function delay;
-moz-transition: property_name duration timing_function delay;
-o-transition: property_name duration timing_function delay;
transition: property_name duration timing_function delay;
You also can declare every value explicitly: (Target) Property:
-webkit-transition-property: property_name;
-moz-transition-property: property_name;
-o-transition-property: property_name;
transition-property: property_name;
Duration:
-webkit-transition-duration: duration;
-moz-transition-duration: duration;
-o-transition-duration: duration;
transition-duration: duration;
Duration (like delay) can be entered either in seconds (eg. 0.5s) or in milliseconds (eg. 500ms). It’s important to note that if the value is entered without suffix, transition will not work at all. Timing (of motion):
-webkit-transition-timing-function: timing_function;
-moz-transition-timing-function: timing_function;
-o-transition-timing-function: timing_function;
transition-timing-function: timing_function;
Available timing functions:
  • cubic-bezier(cp1x, cp1y, cp2x, cp2y)
  • ease – equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0).
  • linear – equivalent to cubic-bezier(0.0, 0.0, 1.0, 1.0).
  • ease-in – equivalent to cubic-bezier(0.42, 0, 1.0, 1.0).
  • ease-out – equivalent to cubic-bezier(0, 0, 0.58, 1.0).
  • ease-in-out – equivalent to cubic-bezier(0.42, 0, 0.58, 1.0).
Delay:
-webkit-transition-delay: delay;
-moz-transition-delay: delay;
-o-transition-delay: delay;
-transition-delay: delay;
Delay (like duration) can be entered either in seconds (eg. 0.5s) or in milliseconds (eg. 500ms). In general, it’s good to declare transitions on default state selectors without pseudo classes. This will cause transition played in both direction, eg. when hovering. Remember, you have to enter all the properties four times before being cross-browser compliant. Therefore it’d be best to use shorthand codes for keeping your CSS code clean. The Basics

The Basics

Now, I’m going to demonstrate some of the transitions. You must either hover or to click activation buttons for displaying transitions. All the code examples below has no browser proprietary format written – this is for saving space.

Basic Transition: Dimensions and Scaling

I’ll start by demonstrating the basic transition. It also demonstrates the difference between width+height and scale transform.
#widthHeight	{transition:all 500ms;}
#widthHeight:hover	{width:200px;height:200px;line-height:200px;}

#scale	{transition:all 500ms;}
#scale:hover	{transform:scale(2.0, 2.0);}
Width + Height
Scale
 

As you can see, width and height increases normally while scaling is treated almost like absolutely positioned element. On scaling, the transform-origin is set to middle while modifying width+height origin is on the top-left corner.

Transition with Timing Function

Below there are two blocks rotating; one with linear timing-function and second one with ease.
#rotateLinear	{position:relative;clear:both;left:0px;
		transition:all 2500ms linear;}
		
#rotateEasing	{position:relative;clear:both;left:0px;
		transition:all 2500ms ease;}
		
#rotateLinear:target	{left:200px;
			transform:rotate(360deg);}

#rotateEasing:target {left:200px;
			transform:rotate(360deg);}
Linear
Easing
 
Activate LinearActivate Easing
 

As you probably noticed, the movement is different but both transitions ends at the same time (after 2500ms).

Transition with Delay

Delays are useful in some cases. And they’re very easy to implement in transitions:

#bgColorDelay	{background-color:#12142B;
		transition:background-color 500ms linear 800ms;}
#bgColorDelay:hover	{background-color:#336699;}
800ms delay
 

Transition Chaining

Transitions can also be chained. This doesn’t come as a default feature, but chaining can be achieved by adding delay between transitions:

#widthHeightOpacity	{transition:width 500ms, height 500ms linear 500ms, opacity 500ms linear 1000ms;}
#widthHeightOpacity:hover	{width:200px;height:200px;opacity:0.1;}
w+h+opacity
 

This has one caveat: transitions are displayed in same order no matter whether the element is hovered or it’s in default state. And that makes no sense. Therefore we need to reverse the declarations (compared to earlier examples) as following:

#widthHeightOpacity	{
	transition:width 500ms 1000ms, height 500ms linear 500ms, opacity 500ms linear;
}

#widthHeightOpacity:hover	{width:200px;height:200px;opacity:0.1;
	transition:width 500ms, height 500ms linear 500ms, opacity 500ms linear 1000ms;
}

Is There Anything Else?

Well of course, there might be something else I haven’t noticed at this point. But what I’m trying to emphasize is that transitions are rather simple to implement (although they require a bit extra work for cross-browser compliancy).

Conclusions

Conclusions

Are we there yet? Yes, we’re over halfway there. Transitions in general are very cool in proper use. However, I’m personally still bit skeptic with CSS3 Transitions: at this point, you can’t rely on them and you must do cross-browser testing thoroughly. I’ll cover some of the problems at the following part of this article series. And I’m also going to briefly compare CSS3 Transitions with jQuery Animations. If you’re dealing with a platform solely running on WebKit (like iPhone or Adobe AIR) then go ahead and enjoy the full power of both CSS3 Transitions and WebKit animations. External Resources

External Resources

Here are some good resources provided both by browser vendors and other external authors. I strongly suggest reading them for adopting transitions and other CSS3 techniques.

Comments?

Feel free to comment any part of the article. Additionally, if you know good resources about CSS3 Transitions, go ahead and contribute.