How we built a pinball

Ouigo Let’s Play — User Journey

The brief

Rosapark agency imagined a new brand platform for Ouigo, using a pinball as main reference, since it’s fun, fast and cheap. The briefing was then pretty simple : “Let’s build a pinball game for the web as well as an arcade cabinet version, for real!” — which we (naively) answered: OK, let’s go!

On May 2017, Ouigo (a French low-cost railway service by SNCF) launched Ouigo — Let’s play, a pinball game you can play directly in your web browser, where the old school plunger is replaced by a train and the missions by the brand new destinations served by Ouigo in 2017.

Starting from scratch

  • First of all, we didn’t have any assets from the TV commercial, except a rough storyboard and a few print posters not even approved. The production of the TVC was made simultaneously with the game, which made the work very complicated, since we had to be consistent between the two mediums. Then, how could we move forward and make sure we’re not going off the rails?
  • We have never designed a pinball. We’re not even pinball players. We just used to play 3D Pinball: Space Cadet on Windows 95, that doesn’t make us pinball players.
  • That also implies some technical challenges like: What physics engine should we use? How will we work with designers? How could we make it work on a smartphone?
  • And finally, we have never built an arcade cabinet (from scratch)! 🕹

Digging into the pinball world

OK, we all know what a pinball is, don’t we? That shiny & flashing big table standing into the bar corner, waiting for you to break that record a guy did 10 years ago. Damn. But still, everyone always get really fun time playing pinball — youngsters as elders. BINGO! Here was the starting point of the whole R&D phase: what makes a pinball so cool?

Here at Merci-Michel we always discuss, debate (sometimes struggle) about everything, especially when we start a project. So everyone joined these sessions with his/her own ideas about what a good pinball game should be — the client & us — and immediately we had a first challenge to deal with: the vocabulary.

While discussing, we were all using different words for the same stuff. For example, in french (yes, we are french if you didn’t notice 🇫🇷), we call a pinball “un flipper” but a flipper is a different thing in english. Actually, a flipper is a pinball item and a flipper in french is also “un flipper”… What The French!

The first job has been to dive into dozens of Pinball’s design documents and different Pinball games, in order to find out how to design a cool pinball for beginners as well as tryharders:

  • Missions to complete
  • Jackpot & multi-ball (must-have)
  • A good ball flow around the playfield, meaning a good geometry
  • Sound design, sound design, sound design!
  • The dot matrix display
  • Bonus everywhere
  • Ramps

Then we mixed them up with what had to communicate the OUIGO — Let’s play Pinball experience: 5 destinations to be highlighted based on print ads and a TVC (work by Nikopicto).

Here was the starting point! We might start designing a pinball now.


How to design a pinball? What makes it cool? We had to test several pinball games, in order to feel how the flippers should react, how the ball should bounce against the walls, how bumpers should kick the ball and so on.

Schematics from Apollo 13 Pinball manual

Best parts in the pinballs we played, real or virtual, were:

  • Having a ball saver — being a noob has it good parts 😇
  • Taking a ramp 🎢
  • Kicking balls everywhere in multi-ball mode 🎊
  • Achieving a mission 🎉
  • Winning a jackpot 💰
  • Discovering modules as the wizard — FINAL BOSS! 👹

Designing the layout

Ok, the research work is done: we have a precise set of cool features in mind. Also, at that moment, Rosapark told us what key visual elements would be in the TVC, so we had to integrate some of those.

To keep going, we gathered the features and the key visuals into a design document. We were inspired by existing pinball manuals and schematics.

Then we wanted to have the big picture. So we started to draw a layout like the draft 7 (the first acceptable draft). And after discussing about the elements to integrate, we had this almost final layout draft 12.

Draft 7 — Draft 12

With this blueprint, we could start building prototypes, we had to! We needed to know if this pinball layout could be playable and how much fun it could bring to the player!

Determining physics engine requirements

For a pinball, we have specific needs regarding the physics engine:

  • CCD (continuous collision detection) or Stepped World — we need to avoid tunnelling (when an object is too fast that it can go through a wall without triggering a collision).
  • Not too resource intensive in order to be run on a smartphone — a 3D physics engine might need more resources than a 2D one.
  • Collision groups — if we use a 2D physics engine, we might need to handle the ramps separately than the rest of the board.

Solving requirements

No need to compare all the existing physics engines, p2.js was a perfect match:

  • CCD and Stepped World are supported.
  • It is a 2D physics engine and looks good on mobile since it’s very light.
  • Collision groups are supported.

After starting to prototype, we quickly realized that:

  • Stepping the world is more flexible: we can be more accurate by testing different parameters.
  • 2D over 3D is such a performance gain. After all, a pinball is mostly in 2D. The only problem is to deal with ramps (elevations and layers). We will talk about that further.
  • For collision groups, we swapped collision groups that way:
On board, the ball collides with black. When it hits green sensor, collision group is swapped, so the ball now collides with red. When the ball hits blue sensor, collision group is swapped back.

So what’s the deal with ramps if we use a 2D physics engine? Well, at a certain point we would have to map coordinates from the physics engine to three.js, the visual interface. This interface is in 3D, so, the ball has to elevate itself in order to follow the path of ramps in the height perspective.

At the end, we solved this by setting a 3D scene with the whole pinball mesh and an orthographic camera looking at it from the top. Then, we did a snapshot by setting the material of the pinball model with a THREE.MeshDepthMaterial which has a depthPacking set to THREE.RGBADepthPacking to get more precision than the THREE.BasicDepthPacking.

Heightmaps generated

Ok, that’s a bit of a relief! Let’s move on with the design team!

3D Modeling

As planned with Rosapark, we won’t have any assets from the TVC until a while and we had to produce some assets that stay consistent with the campaign’s look’n feel. Fortunately, we had a few references to rely on and the key elements were not supposed to look exactly the same as in the TVC.

Because we had to highlight some destinations, we decided to build models that represent some of them. For example, Marseille with the beach, Paris with the Eiffel Tower and the french cancan dancers, Rennes with the lighthouse, Strasbourg with the white stork, etc.

Firstly, we modeled and illuminated the whole scene in High poly (7M+ polygons) based on the path used by the physics engine (read further).

It would have been impossible to play on a smartphone with so many polygons and lights in real time. To make it possible, we modeled a second version of the scene that was simplified with less than 50K polygons.

Then, we projected textures and lights from the high definition version to the low definition’s (i.e. baking technique).

High poly version (7M+ polygons)
Low poly version (49.5K polygons)
From HD to LD in real time
Before (7M+ polygons)
After (49.5 polygons)

Once this process done, in order to optimize loading time and memory usage, we packed as many textures as we could, in a minimum number of files.


We also had to make things move:

  • the bumpers should bounce
  • the clouds and rainbow should be floating
  • the sun should be spinning when a ball passes through the ramp
  • the light from the lighthouse should spin

Dot Matrix Display

A pinball without a dot matrix display is not a real pinball. A dot matrix display should give the player feedbacks on his game : score, activating and achieving a mission, stacking points for the jackpot and so on. Missions are key factors of a pinball, so we have to make sure the player understands what he’s doing and what he has to do.

Left: Launch the ball / Right: Ball lost
Left: Wizard module opened / Right: Paris mission enabled
Left: Multiball module in progress / Right: Chance module opened
Game over

Moving on

Next, we had to check with the dev team how we could work together:

  • how to export 3D assets?
  • how to design the layout of the pinball and test it right away?

Working with design team

3D assets workflow

We wanted to use glTF format because it can contain a lot of information (node hierarchy, materials, cameras, geometries, animations, textures) like collada format, but it is more optimized for loading and also processing. Besides that, there is a three.js glTF Loader that works pretty well.

The 3D team was working on 3DS MAX. But there’s nothing to export to a glTF format on 3DS MAX. So they had to export in collada, then import it into Blender and with a glTF exporter, output the final asset.

Pinball layout workflow

We wanted to find an efficient production pipeline, from designing the pinball to playing with it, so that it would be easier to test different geometries and fine tune the gameplay.

One of the first things we had to achieve, was working on a same file as a basis. This file, the pinball layout, would define every path for ramps, walls, sensors, bumpers, … everything! And it would be used as a layout for the 3D scene but also as physics items’ definitions. And because we decided to have a physics engine in 2D for performance issues, we had to match the 3D items with the physics engine items, in 2D.

Well, this was a huge pain, we tried several imports / exports in different ways with many softwares / libraries and almost none was successful. The only one that worked relatively well, was to draw the layout in Adobe Illustrator with a SVG format. This could be easily imported in 3DS MAX (so the 3D team could align meshes based on this layout) and also in p2.js. With this process we were able to draw each shape multiple times, to get the lower polygon count for the physics to compute. In addition to that, we adjusted the time step and the maximum number of sub steps to get the best performances and add a velocity constraint on balls to avoid tunneling.

This effort allowed us to tweak any gameplay — which is so important in a pinball game! We didn’t want to have a weird feeling when a ball leaves the ramp or when a ball hits a wrong item when launched from the plunger. So this fine tuning was really crucial!

Final layout

In the end, we had to match ball coordinates from physics engine to 3D engine. We used a pattern, which should be at size 2000x2000, that allowed us to compute the scaling between the 3D and the physics engine. We made sure of that through this debug view (debug code removed from bundle in production with conditional compilation) :

Latest debug view

For debug purposes, we also added a cool slow motion mode.


Game design

We designed 8 missions : dedicated modules and basic missions.

Dedicated modules were “multiball”, “chance” and “jackpot”. You could access those modules if you take the related ramp, but first you had to hit the targets on both sides of the ramp (it would point the railway track in the right way).

Basic mission activation

Basic missions purpose was to highlight some destinations served by Ouigo. The main hub of the Ouigo network is Paris, so it made sense to use a ramp with the Eiffel Tower as the entrance, to activate a mission, as if you were about to leave Paris to go somewhere.

Strasbourg mission achieved

When a mission is activated, you have to hit specific targets or take specific ramps in order to achieve this mission.

Once achieved, you have a related letter of the word “OUIGO” that lights on, on the board. It is your progression state through the 5 missions.

If you achieve the 5 missions, you can earn a reward by accessing the jackpot module, then hit each of the 4 targets 3 times and finally get through the main door. This will results in winning the jackpot, stacked all along your game. So, YES, you could win a pretty big stack of points!

Jackpot module

Apart from missions, we had to make a pinball that is not too hard for a wide range of people but that is also enjoyable to play. For us, that meant:

  • finding the right gap distance for the lower flippers
  • being able to control the ball with higher flippers
  • animate some objects when player does something cool (e.g. the sun rotates when you take the ramp)
  • having nice animated sequences in the dot matrix display
  • the higher the rewards the harder it is to get (e.g. blue ramp for jackpot is harder than the other ramps)
  • being able to pass the ball between two flippers
Pass the ball between flippers

Choosing an arcade cabinet pattern


We liked the style of the Moon Patrol / Joust pattern.

Moon Patrol and Joust arcade cabinet







The right way to apply stickers is to do it before assembling. By doing so, you have clean and precise cuts. Unfortunately, at that time, the visuals for the stickers were not yet approved. So we applied them once the arcade cabinet was built. It required more carefulness and technique in order to avoid wrinkles and bad cuts.

Draft stickers before approval
Sticking once approved

Final product

The arcade cabinet runs a dedicated version of the project, connected via web socket to an arduino, through a node server using and serialport.

After an highscore, type your name with only 3 buttons


It’s been an amazing journey and we learnt a lot in each phase of the project.
Today, we are so pleased to be awarded by multiple juries:

  • Awwwards : Developer award, SOTD, SOTM, and SOTY,
  • and hopefully more to come!

Want to join us?

We are actually looking for talented people! More informations here:
Submit your profile/references here:

Sincerely Merci-Michel
Follow @mercimichel on Twitter
Like us on Facebook




Interactive Design & Storytelling Studio

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Using GitHub Pages to Host Documetnation

CS373 Spring 2022: Nathan Gates Week 9

Series of CTF machines walkthrough #2 “LazyAdmin TryHackMe”.

The Updated Decision on Brazil Traceability Timeline

Kind of a Newsletter: New Horizons

A Real-World Application Deployment on Kubernetes

Developer Diary: Tales from a deeply-nested JSON object

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Merci-Michel ®

Merci-Michel ®

Interactive Design & Storytelling Studio

More from Medium


Why are people not using DuckDuckGo as much as they use Google?

Blender Basics Part 4: More Edit Mode

Blender Basics Part 4

Web 3.0 simplified