← Back to projects

Telecom

German eSim Provider

2023 – 2025

Overview

Content-rich marketing and product website for a digital-first mobile carrier (Telekom sub-brand). The project prioritised sophisticated scroll-driven animations and third-party content integration, targeting a digitally native audience expecting a premium, app-like web experience.

Architecture

Nuxt 3 (SSG — static generation)
  │
  ├── GSAP + DrawSVGPlugin + ScrollTrigger
  │     └── Card icon animations — stroke-draw on mount/hover
  │
  ├── Content integrations (build-time)
  │     └── App Store + Google Play ratings (app-store-scraper)
  │
  ├── Fuse.js — fuzzy FAQ search (zero-latency, client-side)
  ├── Swiper — product carousel + feature gallery
  ├── focus-trap-vue — WCAG modal & drawer focus management
  └── Tealium · UTM redirect tracking · Salesforce live chat

  Histoire — component library docs for the distributed team

Key Contributions

Code Examples

GSAP DrawSVG Card Animation Timeline

Each feature card SVG starts fully undrawn. On hover or focus the GSAP timeline plays forward — stroking every path via DrawSVGPlugin, sliding clip masks, and scaling icon elements with staggered easing.

composables/useCardAnimation.ts
import gsap from "gsap";
import DrawSVGPlugin from "@/app/DrawSVGPlugin";

export const useCardAnimation = (cardlet: HTMLElement): gsap.core.Timeline | undefined => {
  gsap.registerPlugin(DrawSVGPlugin);
  if (!cardlet) return;

  const icon1Clip    = cardlet.querySelector(".card__icon-clip-mask--euro");
  const iconEyeDot   = cardlet.querySelectorAll(".card-icon__eye-dot");
  const iconAppLogo1 = cardlet.querySelector(".app-logo__clip-path");
  const iconAppLogo2 = cardlet.querySelector(".app-logo__clip-path--2");

  const tl = gsap.timeline({ paused: true });

  // Start with all paths undrawn
  tl.set(cardlet.querySelectorAll("rect, path, line, circle, polygon, polyline"), {
    drawSVG: "0% 0%",
  });
  if (icon1Clip)        tl.set(icon1Clip,    { x: -105 });
  if (iconEyeDot.length) tl.set(iconEyeDot,  { scaleY: 0.5, y: 3 });
  if (iconAppLogo1)     tl.set(iconAppLogo1, { x: -80 });
  if (iconAppLogo2)     tl.set(iconAppLogo2, { x: -60 });

  // Animate all strokes into view
  tl.to(cardlet.querySelectorAll("rect, path, line, circle, polygon, polyline"), {
    duration: 1, drawSVG: "0% 100%", ease: "power1.out", delay: 0.1,
  }, 0);

  if (icon1Clip)
    tl.to(icon1Clip,    { duration: 1,   x: -35, ease: "power1.out"        }, 0);
  if (iconEyeDot.length)
    tl.to(iconEyeDot,   { duration: 0.2, scale: 1, y: 0, ease: "power1.out" }, 0);
  if (iconAppLogo1)
    tl.to(iconAppLogo1, { duration: 0.6, x: 0, ease: "power1.out"          }, 0.4);
  if (iconAppLogo2)
    tl.to(iconAppLogo2, { duration: 0.8, x: 0, ease: "power1.out"          }, 0.2);

  return tl;
};

Icon Gallery

Each card icon starts fully undrawn. GSAP's DrawSVGPlugin strokes every path into view on hover — the CSS animation below replicates the same effect.

Flat rate
No hidden costs
eSIM / App

Tech Stack

Framework
  • Nuxt 3
  • Vue 3
  • TypeScript
Animation
  • GSAP
  • DrawSVGPlugin
Styling
  • Sass / SCSS
UI Libraries
  • Swiper
  • focus-trap-vue
Utilities
  • Fuse.js
  • VueUse
Dev Tooling
  • Histoire
  • Vitest