Charles Krook

Senior Software Engineer

charles.krook@gmail.com · charleskrook.com · linkedin.com/in/charleskrook · github.com/ckrook · instagram.com/charleskrook

Work

Fullstack engineer at Umain. My work spans e-commerce platforms, design systems, and content-driven sites, where the engineering exists to serve the design.

Place

Stockholm, Sweden. Grew up just outside it, spent a few years moving between cities, and came back in 2019.

Off-hours

Outdoors whenever I can. Mostly on the road bike and swiming.

Experience

Fullstack developer, Umain

2023 - Now

Umain is a digital consulting firm who works with a range of brands, everything from mcDonalds, Scania and biamp. Umain offers both web and digital services

Clients: Scania, Poc Sports

Frontend developer, Grebban

2023 - 2023

Grebban is a retail e-commerce firm who create extraordinary e-commerce experiences and digital flagship stores for brands globally.

Clients: Grandpa, Byon, Norstedts, Hestra Gloves

Frontend Developer, Sopra Steria

2022 - 2023

I worked at Sopra Steria, a big tech and consulting company helping businesses with digital solutions and transformation.

Clients: Radiohjälpen

Frontend developer, Freelance work

2016 - 2019

Freelance developer during a longer period of my life. developing sites for clients and businesses.

Selected work

Poc sports · Software Engineer

2023-2024

Led frontend for a new e-commerce platform, from architecture to UI for a fast, modern customer experience.

Centra, Tailwind, Nextjs, Sanity, Klaviyo, Adyen, Gladly, Playwright

Tegel Design System · Codeowner (consultant)

Oct 2024 – 2026

Scania's multibrand design system, powering Scania products across the organization suporting mulit frameworks.

Stenciljs, npm, aws

Scania Experience Center · Senior Software Engineer

2025-2026

An interactive museum platform with 3D installations synced across touchscreens and wall displays in real time.

Technologies

Nextjs, Stenciljs, Tailwind, React, Centra, Sanity, Hygraph, Gladly, Klaviyo, Adyen, Playwright, npm, aws

Charles Krook
Charles Krook
Fullstack engineer
  1. Home
  2. About
  3. Projects
  4. Contact
Charles Krook

Charles KrookFullstack engineer

Scania Experience Center

2025-2026

An interactive museum platform with 3D installations synced across touchscreens and wall displays in real time.

4 installations · 2 languages · 1920px → 6835px+ displays · runs unattended, all day

The problem

One experience, many screens, real time. A visitor touches the table; the wall reacts, and they can't drift apart.

Content changes often, in two languages, edited by curators not engineers. Installations run unattended all day and must recover on their own when a visitor walks off or a screen idles.

Four installations

  • Globe: interactive 3D globe (R3F) with multiple themes plus a story mode that plays a film on the wall while the table drives it.

  • Timeline: auto slideshow of Scania's history with openable milestones; a separate build for rooms past 6835px.

  • Quiz: scored multiple choice with live feedback.

  • Remote: a phone that lets staff drive playback and reset any installation from the floor.

The part I'm proudest of: sync

Table and wall never talk directly. They share a few realm variables over a WebSocket (PIXILAB Blocks). One screen publishes, the rest react.

Hardest piece: story-mode video. Lockstep playback meant time-stamped play/pause/seek commands, position/duration reporting, and handling players that aren't ready or films that have ended.

To build it without a museum on my desk, I made a localStorage fallback so two browser tabs behave like the real table and wall.

Curators own the content

Everything visitors see comes from Sanity: pages, globe content, quiz questions, Swedish translations, no code required. Next.js fetches and caches it.

Around it: an idle reset timer, a broadcast refresh trigger, an access whitelist, per-installation Plausible analytics, and layouts from 1920px to ultrawide.

How it's built

Next.js 14 (App Router) · Three.js / R3F · GSAP + Lottie · Redux Toolkit · Tailwind + Styled Components · Sanity.

The rule that kept it sane: local state → Redux. Shared-across-displays state → realm variables only. Always one home for every piece of state.

What I'd do differently

Write the realm-variable contract down sooner. Once a remote and several installations depend on the same variables, the names and defaults are an API, so treat them like one.

Photography and video by Ludwig Mattsson.