Skip to content

This page zooms: scrolling moves you closer, from a name into a sentence, into a project, into its code. Use the arrow keys to step between depths, or read the flat version at /all.

Ismail Safwat

I build software for the whole stack: web applications, the services behind them, the firmware inside industrial machines, and once, for the fun of it, a game engine.

I build software for the whole stack: web applications, the services behind them, the firmware inside industrial machines, and once, for the fun of it, a game engine.

this website · 2026 · personal

ismailsafwat.com — this website

This site: one page that zooms from a name down to a piece of code, built on Astro and served from Cloudflare's edge.

Astro · TypeScript · CSS · Cloudflare Pages · Cloudflare Workers

interface · application · services · data

Ismail Safwat 1× Ismail Safwat 4× Wexiödisk, 2023 → 20× Wexiödisk · 2023 → Mjukvaruingenjör a piece of the code ↓ 80× s = target.w / next.w k = 1 / s MAGNIFICATION AGAINST SCROLL · log 1× 10× 100× 1000× 0 1 2 3 4 · depth ≈ 330× out: translate((cx−tx)·p, (cy−ty)·p) scale(k^p) in: translate((tx−cx)·(1−p), …) scale(s^(1−p)) surroundings fade 0.03–0.28 · target 0.28–0.50 · next 0.44–0.66 prefers-reduced-motion → same document, flat 1 2 3 4 5
interface
application
services
data
firmware
a piece of the code ↓

Wexiödisk · 2023 → · work

Software Engineer at Wexiödisk

I write the control software and the Qt/QML touch interface inside Wexiödisk's industrial dishwashers, and the telemetry that reports every machine back to the cloud. Firmware that has to be right in a kitchen at noon, and screens that work with wet hands.

C++ · QML · Linux · Rhapsody · IoT · Embedded Systems

interface · application · services · data · firmware

GND POUR U1 ARM · 480 MHz LINUX · C++ Y1 · 25 MHz J1 · SENSORS T1 temp L1 level S1 door P1 press. K1 HEATER 16 A · 230 V K2 PUMP 8 A K3 DOOR LOCK M1 Wi‑Fi · BLE U2 PMIC F1 · 2 A D1 D2 D3 TP1–3 J3 · FPC 40p J2 RS‑485 ECO 65° 04:12 PROGRAM 2 · WASH WD‑TOUCH · 7" · QML MQTT · TLS 1.3 temp 64.8 · cycle 2 temp 64.5 · cycle 2 door closed · 04:12 120.00 84 A 1 2 3 4 5 6 7 8
interface
application
services
data
firmware
a piece of the code ↓

a distributed enterprise system · 2022 · university

Distributed Enterprise System

A university project where I built a system the enterprise way: several services, each owning its own data, talking over REST. Most of what I know about the boundaries between services I learned by getting them wrong here first.

SOA · Microservices · Service Architecture · Enterprise Patterns

application · services · data

SERVICE ZONE · PRIVATE NETWORK PUBLIC EDGE client browser · JSON gateway auth · JWT rate limit route · retry REST · HTTP/1.1 account :8081 ctrl svc repo accounts person :8082 ctrl svc repo persons bank :8083 ctrl svc repo banks ONE STORE PER SERVICE GET /persons/{id} ONE REQUEST, TIMELINE · req 7f3a client gateway account person t=0 · POST /transfer +4 ms · auth ok +11 ms · owner? +23 ms · 200 +31 ms · 201 created +33 ms timeout 800 ms · 2 retries 1 2 3 4 5 6
interface
application
services
data
firmware
a piece of the code ↓

Kundvagn · 2021 · university

Kundvagn - Shopping Cart Android App

A university project: an Android shopping-cart app in Kotlin. The part I cared about was sync: two phones, one cart, and Firestore keeping them honest in real time.

Kotlin · Android SDK · Firebase · Firestore · Mobile Development

interface · application · data

09:41 09:41 kundvagn uid 3f…A mjölk×2 · 34 kr bröd×1 · 42 kr kaffe×1 · 69 kr pay · 145 kr PHONE A · ADDS kundvagn uid 3f…B mjölk×2 · 34 kr bröd×1 · 42 kr kaffe×1 · 69 kr pay · 145 kr PHONE B · LISTENS Firestore europe‑west1 carts/ {uid}/ items/ k7f2 { name:"kaffe", qty:1 } a91c { name:"mjölk", qty:2 } c04e { name:"bröd", qty:1 } rules: auth.uid == uid index: items.addedAt ↑ offline: writes queued set() onSnapshot onSnapshot set() NO CONNECTION set() waits locally → replayed on reconnect ~200 ms write to visible change, Jönköping → europe‑west1 → Jönköping 1 2 3 4 5
interface
application
services
data
firmware
a piece of the code ↓

Shape Shooters · 2020 · university

Shape Shooters - C++ Game Engine

A university project: a multiplayer arcade shooter and the small engine under it, written from scratch in C++ with SFML. My first real lesson in game loops, timing, and why collision detection is never quite finished.

C++ · SFML · OOP · UML · Game Development

interface · application

SCORE 0420 LIVES 3 · WAVE 4 grid 80 px · 18 cells AABB 56² Ship · p(234,248) v(0,42) v(‑26,36) v(‑40,0) hit · +20 CLASSES Entity pos · vel · box Ship Enemy Bullet entities 14 collision tests 31 / 91 grid saves 66 % frame time · 60 Hz ONE FRAME · 16.7 ms input 0.4 · update 2.1 collide 1.3 render 6.8 idle 6.1 · vsync dt = clock.restart() · position += velocity · dt 1 2 3 4 5
interface
application
services
data
firmware
a piece of the code ↓
// Between depth i and i+1, p runs from 0 to 1.
// The outgoing layer grows around its target;
// the incoming layer shrinks onto that same target.
const s = target.width / incoming.width; // < 1
const k = 1 / s;

out.style.transform =
  `translate(${(cx - tx) * p}px, ${(cy - ty) * p}px) scale(${k ** p})`;

inc.style.transform =
  `translate(${(tx - cx) * (1 - p)}px, ${(ty - cy) * (1 - p)}px) scale(${s ** (1 - p)})`;
enum class State { Idle, Fill, Heat, Wash, Drain, Fault };

State next(State s, const Sensors& in) {
  switch (s) {
    case State::Idle:  return in.doorClosed && in.start ? State::Fill  : s;
    case State::Fill:  return in.level >= target.level  ? State::Heat  : s;
    case State::Heat:  return in.temp  >= target.temp   ? State::Wash  : s;
    case State::Wash:  return timer.expired()           ? State::Drain : s;
    case State::Drain: return in.level <= 0             ? State::Idle  : s;
    case State::Fault: return s;
  }
  return State::Fault;
}
@GET
@Path("/accounts/{id}/balance")
public Response balance(@PathParam("id") String id) {
    Account account = accounts.find(id)
        .orElseThrow(NotFoundException::new);
    Person owner = personService.get(account.ownerId()); // another service, over REST
    return Response.ok(new BalanceDto(owner.name(), account.balance())).build();
}
cartRef.addSnapshotListener { snapshot, error ->
    if (error != null) return@addSnapshotListener
    val items = snapshot?.documents?.mapNotNull { it.toObject<CartItem>() }.orEmpty()
    _cart.value = items.sortedBy { it.addedAt }
}
while (window.isOpen()) {
    float dt = clock.restart().asSeconds();
    handleInput(window);
    for (auto& entity : entities) entity->update(dt, world);
    resolveCollisions(entities);
    window.clear();
    for (auto& entity : entities) entity->draw(window);
    window.display();
}