In this project, I will describe some of the technical details of implementing the Wobbly Windows feature from Compiz to MacOS.

I have always been a fan of the Compiz project. It adds a bunch of neat (but sometimes over-the-top) animations to improve the user interaction with the window manager. One plugin I particularly like is Wobbly Windows, which uses a spring-and-friction model to make windows move like gelatin. From a UX perspective, it is actually a great way of adding affordances to the otherwise static interaction with windows. Consider still frames of moving a regular window: you will not be able to tell it’s direction or speed. In contrast, you can immediately tell the direction of a wobbly window due to it’s deformation, and it will stretch out more as more force is applied (as a result of quicker interaction). This may not seem like much, but such visual cues make the information easier to process for your brain, improving the experience. This is much like how bad typography impaired reading performance and yielded physical frowns on the faces of participants (see study).

Unfortunately, Compiz is only supported on Unix based systems, and I recently switched to using a Macbook Pro as my daily driver. While mentioning this to some friends, they asking “then why don’t you built it yourself, you are a developer after all”. Clearly, injecting into a properietary and closed system like MacOS is no easy task. However I decided to give it a shot anyway.

Three main parts are required in order to make this a reality:

  1. injecting code into MacOS in order to gain access to the native NSWindow objects of every application.
  2. affecting the way NSWindow is drawn.
  3. building a physics engine to simulate the spring-and-friction animations.

Injecting into MacOS

I was delighted to find that there is an active community working on exactly this. SIMBL (SIMple Bundle Loader) loads code via the InputManager system, which was developed to support foreign input methods. It has traditionally been used to create plugins for Safari when it did not natively support those.

A significant disadvantage is that SIP (System Integrity Protection) needs to be disabled in order to use SIMBL on a modern system. I would strongly advice against doing this on your personal device. I am aware of (very hacky) ways around this problem, but have not yet looked into this.

By writing a simple mySIMBL plugin I was able to get a reference to the NSWindow instance, and use that to change any running program in MacOS, perfect! Next up, we will look at how to influence the rendering process.

NSWindow rendering

To affect the way NSWindows are rendered we can use a private Core Graphics method called CGSetWindowWarp. This method is mainly used for rendering the genie animation when minimizing and maximizing windows. For more information, check out Kevin Ballard’s blog post.

The method signature is:

typedef int CGSWindow;      // Obtained with CGSWindow(window.windowNumber)
typedef int CGSConnection;  // Obtained with _CGSDefaultConnection()
typedef struct CGPointWarp { CGPoint local; CGPoint global; } CGPointWarp;

extern CGError CGSSetWindowWarp(
  const CGSConnection cid,
  const CGSWindow wid,
  int w,
  int h,
  CGPointWarp* mesh
);

The CGPointWarp mesh used is a 2-dimensional grid of local points with associated global points. The local points are in the window’s coordinate system, whereas the global points are in the screen’s coordinate system. Perfect for our purpose, by keeping track of the window coordinates and translating them by the physics simulation offset, we should be able to warp the windows.

Note: a downside of this method is that the transformations are not perfectly smooth. The transformation up close reveals hard corners if we use very few mesh points. To circumvent this ideally we would a very fine grid for the simulation, but this will prevent us from simulating at 60fps. Hence we keep the springK constant high, such that very strong deformations are not possible.

Physics engine

In another project of mine I developed a physics engine in pure Javascript. I used this as a basis for a simple physics engine written in Swift.

As a quick refresher, a basic engine consists out of particles and forces and constraints acting on these particles. The simulation has a global loop in which the position should be recomputed for every timestep. Force (as you may remember from secondary school) is defined as mass times acceleration. To determine the position of the particles after forces have been applied, we need numerical integration. Many schemes are available (e.g., Euler and Runge-Kutta) but for our purpose Verlet integration strikes the right balance between stability and quick computation.

Next, we apply the following axis-aligned spring force, which is the same as used in the Compiz project. This force will apply spring forces to keep two particles at the same position away from each other, defined in the offset attribute in the Spring class.

class Spring {
  var offset: CGPoint
  var springK: CGFloat

  func apply(pa: Particle, pb: Particle) {
    let fa = CGVector(
      dx: springK * 0.5 * (pb.x - pa.x - offset.x), 
      dy: springK * 0.5 * (pb.y - pa.y - offset.y)
    )

    let fb = CGVector(
      dx: springK * 0.5 * (pa.x - pb.x + offset.x), 
      dy: springK * 0.5 * (pa.y - pb.y + offset.y)
    )

    pa.apply(force: fa)
    pb.apply(force: fb)
  }
}

This is the final essential component of the technique. It took me quite some fiddling to get everything to work together correctly, but eventually managed to get a functional wobbly windows implementation working.

Result

Below you can see a video demonstrating the final implementation:

The source code for this project is available at GitHub:

Jello