Bringing card design to a new level.

A physical desktop approach beyond Material Design

Written by Nicolay Mausz, flying dog software

View demo Source on gitHub

Websites or user interfaces with card-based design on web or mobile applications are getting more propular these days. Twitter, Facebook, Google, Pinterest, LinkedIn – they are all using card-based design. Since the announcement of Material Design at Google’s I/O annual developers conference in 2014 it is one of the most talked digital design trends.

Cards from Material Design are made for mobile and not really for the desktop.

If you take a closer look at the Google Material Design guidelines (or a collection of Material Design cards for web in CSS & HTML) you see, that only animations on transitions between states of single cards are used. This is a result of the "mobile first" paradigm. So all examples are made to fit on a smartphone screen - showing maximum 1-3 cards at the same time one below the other. But in desktop applications the much larger available screen space is not used at all. This is the only example I found which brings some ideas here: Baraja. The Google Material Design guidelines only describe a single card and not the interaction of multiple cards on a much larger screen than a smartphone display:

A card is a piece of paper with unique related data that serves as an entry point to more detailed information. For example, a card could contain a photo, text, and a link about a single subject.

Google Material Design Guidelines

A 10 years old Flash website beats current cards design!

As I played around with current examples an old link came to my mind. It took me some time to find the right URL and luckily the portfolio website of a Japanese architectural company is still up and unchanged. This website offers a lot:

  • Placement of many cards across the screen like on a real desktop
  • Moving them around with correct physical bevaviour
  • Grouping and sorting cards in stacks
  • Zoom in the full desktop to show one card
  • And transitions of one card to show more information

In my opinion this working example from year 2005 is much more powerful and convincing than all Material Design examples in year 2015 for desktop use. In this article I will show how to implement a similar cards desktop with current technology.


Box2D is a free open source 2-dimensional physics simulator engine often used in games. This engine has been ported to many programming languages and environments. We use a Javascript version here. In my prototype I wanted to use full HTML and CSS features so it should support the HTML DOM tree and CSS, but the better implemented Javascript versions are usually using WebGL or Canvas. After some search I found a great looking prototype on gitHub made for a jQuery conference. The following code is mainly based on it.

A user administration demo based on cards

Using Box2D I set up a user administration demo. The cards represent the users with some information on it. I didn't care about creating or editing user data, the demo is only about a new approach to the user interface.

The Box2D scene consists of the cards and of borders in the same size as the browser window. At the borders the cards can collide. Collision between the cards is usually deactivated, but collision between cards and the window border is possible. The cards are placed random on the screen with random rotation. A global SCALE variable controls the current zoom into the desktop. A new card is added to the scene with the following code including a simple collision detection:

bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_dynamicBody; // element can move around
bodyDef.position.x = x / SCALE;
bodyDef.position.y = y / SCALE;
fixDef = new b2FixtureDef;
fixDef.density = default_density;
fixDef.friction = default_friction;
fixDef.restitution = default_restitution;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(width / SCALE, height / SCALE);
// minus value: element of this group do not go into
// collision detection (= minus value overlapping cards)
fixDef.filter.groupIndex = -8;

A global drawDOMObjects function reads all Box2D objects with the modified values - from animation like collision or movement by mouse - and transforms these objects into CSS values for each card. With var angularVelocity = Math.abs(body.m_fixtureList.GetAngularVelocity()); the current angular velocity is read. This is used to add shadow dependent on that value: the shadow is more far away from the card when the card is rotating faster. The physical behavior of the interaction between mouse drag and a Box2D object is already implemented in Box2D with mouse joints. A card with Box2D body selectedBody is connected to the mouse pointer like this:

md = new b2MouseJointDef();
md.bodyA = world.GetGroundBody();
md.bodyB = selectedBody;, mouseY);
md.collideConnected = true;
md.dampingRatio = 0;
md.frequencyHz = 100;
md.maxForce = 30000.0 * selectedBody.GetMass();
mouseJoint = world.CreateJoint(md);

Double click on one card zooms in the whole desktop with the selected card in focus. During animation other cards do not show their content because I got speed problems (e.g. with Safari, newest iMac). With the scrollTo jQuery plugin the clicked card is shown in center of the screen. This animation is not perfect and needs improvement because sometimes it jumps a little. After the first prototypes I thought that cards, that are rotated upside down, ruin the user experience. In the old Flash site the whole desktop is rotated to the card orientation, which is not very easy to understand as well. So I come to the solution to force the final rotation always to show a card upright after finishing the animation. To archive this we need the following steps after mouse button up:

  1. Waiting one second and show normal physical animation from mouse drag
  2. Now stop the rotation from mouse physics by calling SetAngularVelocity(0) on card body
  3. Calculate new final angle and set again new rotation velocity by SetAngularVelocity(desiredAngle - bodyAngle) where bodyAngle is the current rotation angle of the card
  4. Check the current angle in a loop and if it is close to desired angle stop body movement and rotation by SetAwake(0)

Grouping of cards with collision and joints

In the user management demo a useful feature is the grouping of users. This can be made automatically from user data like gender, location, ... but more interesting a manual grouping feature is implemented in the demo. A group can be selected by a mouse lasso around some users. The selected cards are moving apart so they are not overlapping themself. A piece of paper is added below the card group to which the cards are pinned. A name can be assigned to the group.
Normally cards don't collide with other cards. But to prevent overlapping of the selected cards we change this temporarily with a more complex collision scenario:

  • Walls (=browser window border) which support collision with all cards.
  • Normal cards which collide with walls only.
  • Grouped cards which collide with themselves for a short time period and walls only.

This new scenario is set up with the so called collision bits. There are two collision values categoryBits the collision category bits (normally this would just set one bit) and maskBits which states the categories that this shape would accept for collision. In our scene we have to set these to the following values:

Card in new group100101

After setting these bits for all cards in the group a small impulse is set to wake them up for animation of collision:

var force=new b2Vec2(0,-40);

After 500ms an impulse in opposite direction is fired and after another 500ms the animation is stopped and a new box around the cards is generated.
So we used collision to arrange the cards without overlapping.

Now the cards have to be pinned on a new card/paper below of it. In Box2D there are different kind of joints to connect objects. A connection with the mouse pointer is shown above. With the revolute joint the pinned connection is simulated perfectly. A revolute joint constrains two bodies to share a common point while they are free to rotate about the point. The relative rotation about the shared point is the joint angle. But in our example we have to limit that angle with a lower and upper angle. So the cards do only rotate a little and not fully around.

for(var i=0;i<bodyList.length;i++) { // bodyList: all card bodies in group
   var cardBody=bodyList[i];
   var rjd = new b2RevoluteJointDef;
   rjd.lowerAngle = 0.1;
   rjd.upperAngle = 0.4;
   rjd.bodyA = groupBody;
   rjd.bodyB = cardBody;
   // calculate the relative position of card inside group:
   var cardPosition=cardBody.GetPosition();
   var x=cardPosition.x-groupPosition.x;
   var y=cardPosition.y-groupPosition.y;
   rjd.localAnchorA.Set(x,y); // position of card in group
   rjd.localAnchorB.Set(0,0); // local joint point is middle of card
   rjd.collideConnected = false;

Another demo: desktop with editable notes

The second example shows a different setup with a desktop and three moveable notes and a pen on it. The user can double click on a note and zoom it in. In that mode each note can be edited and by clicking on the pen the selected text will be underlined. This example is less complex because it doesn't use the grouping feature.

Final thoughts

These prototypes show, what is possible today with technology used in games combined with HTML5. The code is unpolished and needs some work to finish. It is also not optimized for all browsers. So for a real website I would not recommend it at the moment.
The purpose of the user administration demo is to find new ways to create innovative user interfaces for classic business applications. That's what we do at flying dog software.

Nicolay Mausz is owner of flying dog software. Our products range from Enterprise Content Management to Business Process Management and Social Intranet solutions. We want to establish cutting edge technology and user interface design in this area like no other before.