Showcase

ML/AI engineer portfolio website, built by Claude Opus 5.5

Hostedvia Claude CodeOpenRouter
Running live in your browserNew tab
Show the code the model wrote
HTML14,001 characters
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Mira Kovač — Machine Learning Engineer</title>
  <meta name="description" content="Mira Kovač, Senior Machine Learning Engineer in Berlin. Ranking, forecasting and fraud models in production since 2017.">
  <meta name="color-scheme" content="dark">
  <meta name="theme-color" content="#0a0c0b">
  <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' fill='%230a0c0b'/%3E%3Crect x='5' y='3' width='6' height='10' fill='%234cf08f'/%3E%3C/svg%3E">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap">
  <style>
    /* One green, one family, one 8px rhythm. Every vertical gap is a multiple of --u. */
    :root {
      --bg: #0a0c0b;
      --fg-strong: #e9eee9;
      --fg: #bcc5be;
      --muted: #7f8981;
      --rule: #1d221f;
      --rule-strong: #2c3430;
      --green: #4cf08f;

      --u: 8px;
      --lh: 24px;
      --gutter: 32px;
      --key: 112px;   /* left key column: years, project names */
      --gap: 48px;    /* key column → content column */
      --section: calc(var(--u) * 10);

      --font: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
      color-scheme: dark;
    }

    *, *::before, *::after { box-sizing: border-box; }
    html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
    body {
      margin: 0;
      background: var(--bg);
      color: var(--fg);
      font: 400 15px/var(--lh) var(--font);
      font-variant-ligatures: none;
      -webkit-font-smoothing: antialiased;
    }
    h1, h2, h3, p, ul, ol { margin: 0; padding: 0; }
    ul, ol { list-style: none; }
    ::selection { background: var(--green); color: var(--bg); }

    a {
      color: var(--fg-strong);
      text-decoration: underline;
      text-decoration-color: var(--rule-strong);
      text-decoration-thickness: 1px;
      text-underline-offset: 4px;
      transition: color .15s, text-decoration-color .15s;
    }
    a:hover { color: var(--green); text-decoration-color: currentColor; }
    a:focus-visible, button:focus-visible { outline: 1px solid var(--green); outline-offset: 4px; }

    .page {
      max-width: calc(736px + 2 * var(--gutter));
      margin: 0 auto;
      padding: calc(var(--u) * 12) var(--gutter) calc(var(--u) * 6);
    }
    .small { font-size: 13px; }
    .muted { color: var(--muted); }
    .accent { color: var(--green); }

    /* ---- intro ---- */
    .prompt { font-size: 13px; color: var(--muted); }
    h1 {
      margin-top: var(--u);
      font-size: 32px;
      line-height: 40px;
      font-weight: 500;
      letter-spacing: -0.01em;
      color: var(--fg-strong);
    }
    .cursor {
      display: inline-block;
      width: 0.5em;
      height: 0.8em;
      margin-left: 0.15em;
      vertical-align: -0.04em;
      background: var(--green);
      animation: blink 1.1s steps(1) infinite;
    }
    @keyframes blink { 50% { opacity: 0; } }
    .headline { margin-top: var(--u); color: var(--fg-strong); }
    .summary { margin-top: calc(var(--u) * 3); max-width: 62ch; }
    .contact {
      margin-top: calc(var(--u) * 4);
      display: flex;
      flex-wrap: wrap;
      gap: var(--u) calc(var(--u) * 4);
      font-size: 13px;
    }
    .contact .k { color: var(--muted); margin-right: var(--u); }

    /* ---- sections ---- */
    section { margin-top: var(--section); }
    .section-title {
      display: flex;
      align-items: center;
      gap: calc(var(--u) * 2);
      margin-bottom: calc(var(--u) * 4);
      font-size: 13px;
      font-weight: 400;
      color: var(--muted);
    }
    .section-title .accent { font-weight: 500; }
    .section-title::after {
      content: "";
      flex: 1;
      height: 1px;
      background: var(--rule);
    }
    .indent { padding-left: calc(var(--key) + var(--gap)); }

    /* ---- timeline ---- */
    .role {
      position: relative;
      display: grid;
      grid-template-columns: var(--key) 1fr;
      column-gap: var(--gap);
      padding-bottom: calc(var(--u) * 6);
      --rail: calc(var(--key) + var(--gap) / 2);
    }
    .role::before {           /* rail */
      content: "";
      position: absolute;
      left: var(--rail);
      top: 0;
      bottom: 0;
      width: 1px;
      background: var(--rule-strong);
    }
    .role:first-child::before { top: 12px; }
    .role:last-child { padding-bottom: 0; }
    .role:last-child::before { background: linear-gradient(var(--rule-strong) 60%, transparent); }
    .role::after {            /* node */
      content: "";
      position: absolute;
      left: calc(var(--rail) - 4px);
      top: 8px;
      width: 9px;
      height: 9px;
      border: 1px solid var(--green);
      background: var(--bg);
    }
    .role.is-current::after { background: var(--green); }

    .when {
      display: flex;
      flex-direction: column;
      align-items: flex-end;
    }
    .when .start { color: var(--green); font-weight: 500; }
    .when .end { font-size: 13px; color: var(--muted); }

    .role h3 { font-size: 15px; font-weight: 500; color: var(--fg-strong); }
    .org { font-size: 13px; color: var(--muted); }
    .org .co { color: var(--fg); }
    .bullets { margin-top: calc(var(--u) * 2); display: grid; gap: var(--u); }
    .bullets li { position: relative; padding-left: calc(var(--u) * 3); }
    .bullets li::before { content: "–"; position: absolute; left: 0; color: var(--muted); }

    /* ---- skills ---- */
    .chips { display: flex; flex-wrap: wrap; gap: var(--u); }
    .chips li {
      padding: 3px calc(var(--u) * 1.5);
      border: 1px solid var(--rule-strong);
      font-size: 13px;
      color: var(--fg);
    }

    /* ---- key / value entries (projects, publication) ---- */
    .entries { display: grid; gap: calc(var(--u) * 3); }
    .entry {
      display: grid;
      grid-template-columns: var(--key) 1fr;
      column-gap: var(--gap);
    }
    .entry .key { text-align: right; }
    .entry .title { color: var(--fg-strong); }
    .entry .meta { font-size: 13px; color: var(--muted); }
    .entry .meta b { font-weight: 500; color: var(--fg); }

    /* ---- footer ---- */
    footer {
      margin-top: var(--section);
      padding-top: calc(var(--u) * 3);
      border-top: 1px solid var(--rule);
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      gap: var(--u) calc(var(--u) * 4);
      font-size: 13px;
      color: var(--muted);
    }
    .linkish {
      font: inherit;
      color: var(--muted);
      background: none;
      border: 0;
      padding: 0;
      cursor: pointer;
      transition: color .15s;
    }
    .linkish:hover { color: var(--green); }

    /* ---- phone ---- */
    @media (max-width: 720px) {
      :root { --gutter: 16px; --section: calc(var(--u) * 7); }
      .page { padding-top: calc(var(--u) * 6); }
      .indent { padding-left: 0; }
      .headline .sep { display: none; }
      .headline .loc { display: block; color: var(--muted); }

      .role { grid-template-columns: 1fr; padding-left: calc(var(--u) * 3); --rail: 0px; }
      .when { flex-direction: row; align-items: baseline; gap: var(--u); }

      .entry { grid-template-columns: 1fr; }
      .entry .key { text-align: left; }
    }

    @media (prefers-reduced-motion: reduce) {
      .cursor { animation: none; }
      a, .linkish { transition: none; }
    }

    @media print {
      :root {
        --bg: #fff; --fg: #222; --fg-strong: #000; --muted: #555;
        --rule: #ccc; --rule-strong: #bbb; --green: #0b7a3e;
        --section: calc(var(--u) * 4);
      }
      @page { margin: 16mm; }
      .page { max-width: none; padding: 0; }
      .cursor, .no-print { display: none; }
      a { text-decoration: none; }
      .role, .entry { break-inside: avoid; }
    }
  </style>
</head>
<body>
  <div class="page">
    <header>
      <p class="prompt"><span class="accent">$</span> whoami</p>
      <h1>Mira Kovač<span class="cursor" aria-hidden="true"></span></h1>
      <p class="headline">Senior Machine Learning Engineer<span class="sep"> · </span><span class="loc">Berlin</span></p>
      <p class="summary">
        Nine years taking ranking, forecasting and fraud models from notebook to production.
        I care most about the unglamorous middle: offline evaluation you can trust,
        latency budgets, and monitoring that pages the right person.
      </p>
      <ul class="contact" aria-label="Contact">
        <li><span class="k">mail</span><a href="mailto:hello@mirakovac.dev">hello@mirakovac.dev</a></li>
        <li><span class="k">github</span><a href="https://github.com/mirakovac">mirakovac</a></li>
        <li><span class="k">linkedin</span><a href="https://www.linkedin.com/in/mirakovac">in/mirakovac</a></li>
        <li><span class="k">tz</span>CET (UTC+1)</li>
      </ul>
    </header>

    <main>
      <section aria-labelledby="experience">
        <h2 class="section-title" id="experience"><span class="accent">01</span>experience</h2>
        <ol class="timeline">
          <li class="role is-current">
            <p class="when"><span class="start">2022</span><span class="end">→ now</span></p>
            <div>
              <h3>Senior Machine Learning Engineer</h3>
              <p class="org"><span class="co">Zalando</span> · Search &amp; Browse Ranking</p>
              <ul class="bullets">
                <li>Tech lead for catalog browse ranking: replaced a GBDT ranker with two-tower retrieval and a transformer re-ranker, +2.8% CTR and +1.1% revenue per session in a six-week A/B test across six markets.</li>
                <li>Distilled the re-ranker into a 4-layer student served on CPU via ONNX Runtime — p99 latency from 140 ms to 38 ms and roughly €400k a year less GPU spend.</li>
                <li>Built an IPS-weighted counterfactual replay harness on logged impressions; it now gates ranking releases for five teams.</li>
              </ul>
            </div>
          </li>
          <li class="role">
            <p class="when"><span class="start">2019</span><span class="end">→ 2022</span></p>
            <div>
              <h3>Machine Learning Engineer</h3>
              <p class="org"><span class="co">Delivery Hero</span> · Logistics</p>
              <ul class="bullets">
                <li>Owned delivery-time (ETA) prediction for 11 markets — quantile LightGBM over ~40M orders a month; cut MAE by 17% and late-delivery complaints by 9%.</li>
                <li>Stood up a Feast + Redis feature store with point-in-time joins, taking feature-to-production time from about three weeks to four days.</li>
                <li>Added PSI-based drift monitoring with retraining triggers; it caught a rider-app logging regression before it reached live forecasts.</li>
              </ul>
            </div>
          </li>
          <li class="role">
            <p class="when"><span class="start">2017</span><span class="end">→ 2019</span></p>
            <div>
              <h3>Data Scientist</h3>
              <p class="org"><span class="co">N26</span> · Financial Crime</p>
              <ul class="bullets">
                <li>Built the real-time card-fraud scorer — XGBoost on Kafka streaming features, p99 under 50 ms — lifting recall at a fixed 0.1% false-positive rate from 61% to 74%.</li>
                <li>Wrote the model documentation and validation pack for BaFin review; it became the template for every risk model that followed.</li>
              </ul>
            </div>
          </li>
        </ol>
      </section>

      <section aria-labelledby="skills">
        <h2 class="section-title" id="skills"><span class="accent">02</span>skills</h2>
        <ul class="chips indent">
          <li>Python</li>
          <li>PyTorch</li>
          <li>LightGBM / XGBoost</li>
          <li>Learning to rank</li>
          <li>Spark</li>
          <li>Kubernetes</li>
          <li>ONNX Runtime</li>
          <li>Experimentation</li>
        </ul>
      </section>

      <section aria-labelledby="projects">
        <h2 class="section-title" id="projects"><span class="accent">03</span>projects</h2>
        <ul class="entries">
          <li class="entry">
            <a class="key" href="https://github.com/mirakovac/tinyrank">tinyrank</a>
            <p>Learning-to-rank losses (LambdaRank, ListNet, ApproxNDCG) in ~600 lines of PyTorch, tested against reference NDCG@k.</p>
          </li>
          <li class="entry">
            <a class="key" href="https://github.com/mirakovac/driftwatch">driftwatch</a>
            <p>CLI that diffs two Parquet snapshots and flags feature drift (PSI, KS) — drops into any CI pipeline.</p>
          </li>
          <li class="entry">
            <a class="key" href="https://github.com/mirakovac/ubahn-eta">ubahn-eta</a>
            <p>Quantile forecasts of Berlin U-Bahn delays from the VBB GTFS-realtime feed, with a live calibration plot.</p>
          </li>
        </ul>
      </section>

      <section aria-labelledby="publication">
        <h2 class="section-title" id="publication"><span class="accent">04</span>publication</h2>
        <ul class="entries">
          <li class="entry">
            <p class="key accent">2023</p>
            <div>
              <p class="title">Counterfactual Evaluation of Neural Re-rankers under Position Bias at Catalog Scale</p>
              <p class="meta"><b>M. Kovač</b>, J. Brandt, T. Okafor · RecSys ’23, Industry Track · Singapore</p>
            </div>
          </li>
        </ul>
      </section>
    </main>

    <footer>
      <p>© 2026 Mira Kovač</p>
      <button class="linkish no-print" type="button" onclick="window.print()">$ print --pdf</button>
    </footer>
  </div>
</body>
</html>

Same prompt, other models

8 more
Compare side by side

One email when a new model lands on the board or in the showcase. Unsubscribe anytime.