/work/enpal-product-work

One Foundation, Three Products

The Enpal design family, and the portal, website and back office built on it

Company
Enpal Energy
Role
Founding Designer / Design Engineer
Timeline
Mar – Sep 2026
Status
Shipped · in use at Enpal
Platform
Web, mobile & internal tools
Scope
Design system, token pipeline, UX/UI, prototyping
Stack
Figma, Design Tokens, React, TypeScript, shadcn/ui, Ant Design
Ship time−20%across product teams
Kick-off time−50%for new projects
Enpal design family documentation site

Overview

Enpal Energy was a new venture within the Enpal group, and I was its founding designer. Its products ran from consumer marketing to dense internal software: one brand, very different contexts. New products needed a system from day one, and design decisions needed to land in code without loss. So I built one shared foundation, the Enpal design family, and used it to ship a customer portal, a marketing site and a back-office tool in parallel. Teams shipped on brand from the start, cutting ship times by 20% and kick-off times by 50%.

Why a family, not a system

The trigger was practical. Enpal Energy was standing up new surfaces, a customer portal and a back-office platform among them, and they needed a system from day one rather than a retrofit later. At the same time, design-to-code handoff was slower and lossier than it should have been: decisions made in Figma were being re-derived in code and drifting a little each time.

The harder question was structural. A marketing page selling to homeowners, a returning customer managing their energy and an operations screen full of data tables have almost nothing in common visually, yet they belong to the same brand and often serve the same customer. One monolithic system would have flattened those contexts into a compromise that served neither. Fully separate systems would have fractured the brand and multiplied the maintenance. The answer I landed on was a family: one parent layer holding the primitives every surface shares, and product systems above it that are free to feel different precisely because the foundations underneath them are identical.

My role

My official title at Enpal was Senior Product Designer. In practice this work was product design engineering: I made the case for the family, designed the token architecture and the systems themselves, and built the delivery end to end, including the documentation site, the token pipeline, the React/shadcn registry and the Ant Design theme. The mobile team owned NEMO day to day; it consumed the shared primitives like everything else.

That last mile matters to me. A design system that stops at a Figma library is a picture of a system. The version teams actually adopt is the one that turns up in their codebase, so I chose to own that part rather than hand it over.

One parent, three dialects

Four systems, one hierarchy. The parent holds what everyone shares; each product system speaks its own dialect on top.

enpal.design: the family's home, with the system architecture front and centre

enpal.design: the family's home, with the system architecture front and centre

Enpal DS, the parent layer

Five brand colour ramps, a two-family type system (Poppins for display, Inter for UI and data), a 14-step spacing scale on a 4pt grid, and six radius values. Every product system maps to these primitives under its own prefix: same values, different namespace. Cross-system consistency is enforced by construction rather than by review.

NEMO, consumer mobile

The system for the iOS and Android consumer apps. Native-feeling, touch-optimised patterns, maintained by the mobile team on top of the shared foundations.

VERSO, consumer web

Mirrors NEMO's warmth on the web for marketing surfaces: pill buttons, elevation cards, generous spacing, editorial layouts, and dark mode.

FOLIO, software UI

The dense end of the family, serving the customer portal and internal software. Built for data tables, forms and workflow screens where efficiency beats atmosphere. This is where the token architecture earns its keep: tabular numerals for column alignment, a chart palette kept deliberately separate from status colours, and a four-tier text hierarchy for layered information.

FOLIO's documented patterns: portal navigation and the live tariff dashboard

FOLIO's documented patterns: portal navigation and the live tariff dashboard

Decisions I would defend

A few of the calls that shaped the family, and the reasoning behind them.

Semantic tokens are the only public surface

The family carries 170+ tokens in two tiers: primitive scales and semantic roles. Components are only allowed to consume the semantic layer; raw primitives stay private to it. That one rule is what makes dark mode a mapping exercise instead of a redesign. Surfaces invert to ink-derived backgrounds, text inverts to paper, amber lifts one step for legibility, and shadows become soft inset glows, all without a single component changing.

The same page in dark mode: a remap of semantic roles, not a redesign

The same page in dark mode: a remap of semantic roles, not a redesign

Yellow is for conversion, nothing else

The family holds to five written non-negotiables. The brand's yellow is reserved for conversion moments; in dense UI the default is ink; amber carries the secondary brand voice; paper dominates surfaces; and decoration gives way to restraint, soft glows and multi-stop shadows rather than borders and ornament. Writing these down gave design reviews a shared language. 'That button should not be yellow' stopped being an opinion and became a rule you could cite.

The mixed CTA strategy in the component docs: yellow for conversion, ink for dense-UI primaries

The mixed CTA strategy in the component docs: yellow for conversion, ink for dense-UI primaries

Meet teams in the framework they already use

My surfaces, the portal and back office in the VPP energy space, run on React with shadcn. But the wider organisation has internal dev teams with an established Ant Design stack, and a system those teams cannot consume is a system they will work around. So the family ships both: a React/shadcn registry for the product surfaces, and an Ant Design theme generated from the same tokens so existing teams elsewhere in the org can adopt the family without retooling.

The pragmatism cuts both ways. shadcn had no real data table, so rather than build one from scratch the back office runs shadcn with Ant Design's table inside it, themed to match. Nobody has ever noticed the seam, which is rather the point. Purity lost, adoption won.

Motion that earns its place

Quiet by default: 220ms ease-out for standard transitions, instant response on hover and focus, entrance animation reserved for genuinely new content. One signature is allowed to breathe, a 2.4s amber pulse on live indicators, and it is the only ambient motion in the system. Reduced-motion preferences are respected throughout, with state still communicated through colour and opacity.

The delivery layer

Everything flows from a single token source. It generates the CSS custom properties and JSON packages developers pull, and the Figma Variable collections designers work with, so both sides of the handoff read from the same file. When a value changes, it changes everywhere or nowhere.

Documentation lives on a site I designed and built: foundations, components, patterns, templates, email, brand and assets, with getting-started paths for designers, developers and product teams.

The family is also AI-first by design. Every system ships a written markdown brief covering the non-negotiables, palette logic, component conventions and, just as importantly, what not to do. The docs put this front and centre: drop FOLIO.md into a Claude project and an assistant can build portal surfaces to the system's rules without constant prompting. Guidelines written for machines turn out to be excellent guidelines for people too; the discipline of making rules explicit enough for an AI removes the ambiguity that humans were tripping over anyway.

Releases are versioned with a changelog, v1.9.0 when I left. Consuming teams can see what changed and when. It sounds basic, and it is, but it is also the difference between a system teams trust and a system teams fork.

Ownership ran hub and spoke. I owned the parent layer, FOLIO and VERSO; the mobile team owned NEMO. The non-negotiables and the token contract were the interface between us: full autonomy inside each system, agreement at the boundary.

Foundations: colour scales, usage rules, and the AI brief given top billing

Foundations: colour scales, usage rules, and the AI brief given top billing

The brand rulebook: three marks, three contexts, with usage rules for each

The brand rulebook: three marks, three contexts, with usage rules for each

Consumer web: the marketing site (VERSO)

The brief here was brand and tone: set a confident north star for Enpal Energy's consumer web, not win a conversion test. So I designed a landing page in the VERSO language, all expressive display type, a real-photo hero, pill buttons and borderless cards on a deep ink surface warmed by the family's aurora wash.

The tariff calculator is the one conversion moment on the page, so it's the thing that earns the reserved brand yellow, and everything else stays quiet around it. The trust signals (independent reviews, households served, certification) sit right under the headline.

It matters to the system because it proved the shared primitives could stretch from a calm product dashboard all the way to an expressive consumer page, without either one feeling like a different brand. The jump from landing page into the portal is a deliberate VERSO-to-FOLIO handoff.

Consumer landing (VERSO): real-photo hero, with the tariff calculator as the one conversion moment

Consumer landing (VERSO): real-photo hero, with the tariff calculator as the one conversion moment

The customer portal (FOLIO)

The portal is where a customer manages their energy: consumption, meter readings (Zählerstand), tariff and billing. It's a returning-user surface, so it follows FOLIO's calm, dense conventions (ink primaries, status pills, one restrained upsell), in German, with full light and dark support.

The overview pulls together the next payment, the last meter reading, a live tariff timeline showing the cheaper and standard windows, and a savings breakdown against the local basic supplier. Contextual nudges, like a cheaper window tonight or a cold weekend ahead, only show up when they're actually useful.

I took it from a high-fidelity interactive prototype through to a production-ready TypeScript scaffold: React, Vite and React Router, consuming FOLIO as a shadcn registry with no vendored CSS, plus a typed API contract with mock fixtures. The idea was that backend and frontend could build the first version without having to re-argue routes, contracts or design-system bindings.

Customer portal overview (FOLIO), light

Customer portal overview (FOLIO), light

The same overview, dark mode

The same overview, dark mode

Sign-in from the production TypeScript build

Sign-in from the production TypeScript build

The back office: Hyperion

Hyperion is the operational counterpart to the portal, a focused customer-360 tool for the teams who actually run the energy business. It uses the exact same FOLIO tokens and components as the portal, with a thin back-office layer on top, which is probably the clearest proof that the foundation carries all the way from a customer-facing product to dense internal software.

The customer view uses a products-as-context pattern: pick a product or contract on the left and the Registration, Contract, Payment and Communications tabs update on the right, right down to the regulated market identifiers (MaLo, MELO, DSO, TSO). Status pills are the shared language across customers, contracts and products, a two-tier navigation keeps top-level taxonomy and per-section context apart, and a ⌘K command palette is the global launcher. Everything shown here runs on fictional fixture data.

Hyperion: customer-360 detail (light)

Hyperion: customer-360 detail (light)

Customer-360 detail, dark mode

Customer-360 detail, dark mode

Operations dashboard: active customers and onboarding funnel

Operations dashboard: active customers and onboarding funnel

The ⌘K command palette: search, jump and run actions

The ⌘K command palette: search, jump and run actions

Design-engineering craft

A few decisions that don't really show up in a screenshot but made the pace possible:

  • Tokens are the single source of truth. The CSS, the shadcn registry, the Ant theme and the Figma variables are all generated from one token file, so a change propagates everywhere instead of forking.
  • Products consume the system, they don't copy it: a shadcn registry or a single stylesheet link, nothing vendored.
  • Theming with no flash. A shared storage key and a pre-paint script set the theme before the CSS parses, and the View Transitions API handles the cross-fade. Light and dark are equal citizens.
  • Prototype to typed scaffold as a deliberate handoff: a single-file interactive demo to agree on the feel, then a strict-TypeScript scaffold that locks down routes, contracts and design-system bindings.
  • Governance as design: adoption is informed or requested, never forced, with a written propagation order from system to portal to web.

Outcomes

One foundation now carries three surfaces: a consumer landing page, a customer portal (a prototype plus a production-ready TypeScript scaffold), and an internal customer-360 tool, all speaking the same visual language, in light and dark. All three are in use at Enpal.

New surfaces start from the system rather than from a blank file, so product teams stopped building custom UI per project: ship times fell by 20% and new projects kicked off in half the time. Screens are assembled from documented components on shared tokens, with accessibility inherited rather than re-argued per screen (WCAG AA contrast, focus states and keyboard patterns are specified at system level).

Design decisions land in code unchanged. Because the registry and the themes are generated from the token source, the gap between the Figma file and the shipped screen largely stopped being a review topic. And the brand holds from one end of the company to the other: the same ramps and type serve a marketing hero and an operations table without either pretending to be the other.

The venture was later merged back into the parent company after its ways of working were adopted group-wide.

  • 170+ design tokens across primitive and semantic layers, generated as CSS, JSON and Figma Variables from one source
  • 25+ documented components and 11 documented product patterns, light and dark throughout
  • Four systems on one parent layer, consumed across mobile, consumer web and internal software
  • Versioned releases with a changelog, v1.9.0 when I left

What I would do next

Some of it was already in motion. Proper package distribution for the developer artefacts (the shadcn theme and components and the Ant Design theme) was the next step when I left, with the DevOps approach already mapped out on a dedicated branch: versioned packages teams install rather than files they download.

Beyond that, it is worth being clear about where the system was thin. When I left, adoption was ahead of governance: the contribution model was still 'talk to me', which worked at that scale and wouldn't at twice it. Next I'd have added usage analytics on tokens and components, so deprecation decisions are informed rather than felt, and continuous Figma-to-code parity checks, because drift between the library and the registry is the failure mode to watch.

If you would like the tour, the documentation site is the best artefact. It is both the system's home and a demonstration of the system describing itself. Ask me for the link.