// Our Skills — Apple-style vertical panels with rich, smooth WOW animations. const RED = '#ff2e4d'; const RED_GLOW = '#ff4d6a'; const CYAN = '#5cf0ff'; const GREEN = '#38e29a'; const AMBER = '#ffb547'; function useTick(ms = 1000) { const [t, setT] = React.useState(0); React.useEffect(() => { const id = setInterval(() => setT((x) => x + 1), ms); return () => clearInterval(id); }, [ms]); return t; } function useRaf() { const [t, setT] = React.useState(0); React.useEffect(() => { let raf, start; const loop = (ts) => { if (!start) start = ts; setT((ts - start) / 1000); raf = requestAnimationFrame(loop); }; raf = requestAnimationFrame(loop); return () => cancelAnimationFrame(raf); }, []); return t; } const easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2; const lerp = (a, b, t) => a + (b - a) * t; // Smooth Catmull-Rom -> Bezier path through points function smoothPath(pts) { if (pts.length < 2) return ''; let d = `M${pts[0][0].toFixed(1)},${pts[0][1].toFixed(1)}`; for (let i = 0; i < pts.length - 1; i++) { const p0 = pts[i - 1] || pts[i]; const p1 = pts[i]; const p2 = pts[i + 1]; const p3 = pts[i + 2] || p2; const cp1x = p1[0] + (p2[0] - p0[0]) / 6; const cp1y = p1[1] + (p2[1] - p0[1]) / 6; const cp2x = p2[0] - (p3[0] - p1[0]) / 6; const cp2y = p2[1] - (p3[1] - p1[1]) / 6; d += ` C${cp1x.toFixed(1)},${cp1y.toFixed(1)} ${cp2x.toFixed(1)},${cp2y.toFixed(1)} ${p2[0].toFixed(1)},${p2[1].toFixed(1)}`; } return d; } /* ============================================================ 1. ANALYTICS — multi-series, sweeping cursor, ticker, axis labels ============================================================ */ function DemoAnalytics() { const t = useRaf(); const N = 32; // Three "datasets" — we lerp between them on a slow loop for live feel const datasets = React.useMemo(() => [ Array.from({ length: N }, (_, i) => 0.35 + Math.sin(i * 0.4 + 0.5) * 0.18 + i * 0.012), Array.from({ length: N }, (_, i) => 0.5 + Math.sin(i * 0.32 + 1.6) * 0.22 + Math.sin(i * 0.6) * 0.08 + i * 0.014), Array.from({ length: N }, (_, i) => 0.42 + Math.sin(i * 0.5 + 2.4) * 0.2 + i * 0.018), ], []); const cost = React.useMemo(() => [ Array.from({ length: N }, (_, i) => 0.25 + Math.sin(i * 0.35) * 0.1 + i * 0.006), Array.from({ length: N }, (_, i) => 0.32 + Math.sin(i * 0.28 + 1.0) * 0.12 + i * 0.008), Array.from({ length: N }, (_, i) => 0.28 + Math.sin(i * 0.42 + 2.0) * 0.11 + i * 0.007), ], []); const cycleLen = 4.5; const phase = (t / cycleLen) % datasets.length; const a = Math.floor(phase); const b = (a + 1) % datasets.length; const lp = easeInOut(phase - a); const cur = datasets[a].map((v, i) => lerp(v, datasets[b][i], lp)); const curCost = cost[a].map((v, i) => lerp(v, cost[b][i], lp)); // Sweeping cursor const sweep = (Math.sin(t * 0.55) + 1) / 2; const ixF = easeInOut(sweep) * (N - 1); const ix = Math.round(ixF); const W = 900, H = 480, padX = 50, padY = 110, padB = 100; const innerW = W - padX * 2, innerH = H - padY - padB; const yFor = (v) => padY + innerH - v * innerH * 0.95; const xFor = (i) => padX + (i / (N - 1)) * innerW; const ptsR = cur.map((v, i) => [xFor(i), yFor(v)]); const ptsC = curCost.map((v, i) => [xFor(i), yFor(v)]); const pathR = smoothPath(ptsR); const pathC = smoothPath(ptsC); const areaR = pathR + ` L ${xFor(N-1)},${H-padB} L ${xFor(0)},${H-padB} Z`; const areaC = pathC + ` L ${xFor(N-1)},${H-padB} L ${xFor(0)},${H-padB} Z`; // Interp cursor on the curve const cx = lerp(ptsR[Math.floor(ixF)][0], ptsR[Math.ceil(ixF)][0], ixF % 1); const cy = lerp(ptsR[Math.floor(ixF)][1], ptsR[Math.ceil(ixF)][1], ixF % 1); const cyC = lerp(ptsC[Math.floor(ixF)][1], ptsC[Math.ceil(ixF)][1], ixF % 1); // Big number — smoothly count const sumR = cur.reduce((s, v) => s + v, 0) / N; const value = sumR * 2.6; // in millions const delta = (8.4 + (sumR - 0.5) * 18 + Math.sin(t * 0.4) * 0.3); // Bars at bottom (7 days) const bars = Array.from({ length: 7 }, (_, i) => { const ph = (t * 0.6 + i * 0.7); return 0.45 + Math.sin(ph) * 0.22 + Math.sin(ph * 0.5) * 0.1; }); const peakBar = bars.indexOf(Math.max(...bars)); // Period highlight const months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; const visMonths = months.slice(0, 12); const tooltipVal = (sumR * (0.7 + cur[ix]) * 220).toFixed(0); return (
Revenue · this quarter
${value.toFixed(2)}M
↗ {delta.toFixed(1)}% vs last quarter
Active
{(12400 + Math.floor(sumR * 800)).toLocaleString()}
[i*11, 20 - (Math.sin(i*0.7 + t*0.4)+1)*8 - i*0.6]))} fill="none" stroke={CYAN} strokeWidth="1.6" strokeLinecap="round"/>
Conv.
{(3.4 + Math.sin(t*0.5)*0.2).toFixed(2)}%
[i*11, 16 - (Math.sin(i*0.5 + t*0.3 + 1)+1)*6 - i*0.4]))} fill="none" stroke={GREEN} strokeWidth="1.6" strokeLinecap="round"/>
{/* gridlines */} {[0.25, 0.5, 0.75, 1].map((p, i) => ( {(value * (1 - p)).toFixed(1)}M ))} {/* x-axis labels */} {[0, 0.25, 0.5, 0.75, 1].map((p, i) => ( {visMonths[Math.floor(p * 11)]} ))} {/* Areas */} {/* Costs line */} {/* Glow under main line */} {/* Main line */} {/* Cursor */} {/* Tooltip floating */} {visMonths[Math.floor(ix / N * 11)].toUpperCase()} · WK {ix + 1} ${tooltipVal}k {/* Bars at bottom */} {bars.map((v, i) => { const bx = padX + innerW * 0.05 + i * (innerW * 0.9 / 7); const bw = innerW * 0.9 / 7 - 6; const bh = v * 50; return ( ); })}
); } /* ============================================================ 2. MOBILE — phone with floating UI cards + screen morphing ============================================================ */ function DemoMobile() { const t = useRaf(); const dishes = [ { name: 'Nasi Lemak', cn: '椰浆饭', tag: 'Chef pick', price: '18.00', rating: '4.9', cook: '12 min', cat: 'Rice', img: 'https://images.unsplash.com/photo-1626804475297-41608ea09aeb?w=400&q=80&auto=format&fit=crop' }, { name: 'Char Kway Teow', cn: '炒粿条', tag: 'Spicy', price: '16.00', rating: '4.8', cook: '9 min', cat: 'Noodle', img: 'https://images.unsplash.com/photo-1645177628172-a94c1f96e6db?w=400&q=80&auto=format&fit=crop' }, { name: 'Hainanese Chicken Rice', cn: '海南鸡饭', tag: 'Top pick', price: '15.00', rating: '4.9', cook: '8 min', cat: 'Rice', img: 'https://images.unsplash.com/photo-1569058242253-92a9c755a0ec?w=400&q=80&auto=format&fit=crop' }, { name: 'Satay Ayam', cn: '沙嗲鸡', tag: '10 sticks', price: '14.00', rating: '4.7', cook: '15 min', cat: 'Grill', img: 'https://images.unsplash.com/photo-1529193591184-b1d58069ecdd?w=400&q=80&auto=format&fit=crop' }, { name: 'Roti Canai', cn: '印度煎饼', tag: 'Best seller', price: '4.50', rating: '4.8', cook: '6 min', cat: 'Snack', img: 'https://images.unsplash.com/photo-1631292784640-2b24be784d5d?w=400&q=80&auto=format&fit=crop' }, { name: 'Teh Tarik', cn: '拉茶', tag: 'Classic', price: '3.50', rating: '4.9', cook: '3 min', cat: 'Drink', img: 'https://images.unsplash.com/photo-1572490122747-3968b75cc699?w=400&q=80&auto=format&fit=crop' }, ]; // Featured rotates through first three dishes; "Add" pulse comes at end of each beat. const cycle = 4.0; const idx = Math.floor((t / cycle) % 3); const phase = (t / cycle) % 1; const added = phase > 0.74; const featured = dishes[idx]; const tick = Math.floor(t / cycle); // Menu list = the other 3 dishes (Satay, Roti, Teh Tarik) const menu = dishes.slice(3); // Cart line items grow with the cycle const cartCount = 2 + (added ? 1 : 0); const cartTotal = (42 + (added ? Number(featured.price) : 0)).toFixed(2); // Animated floating-card numbers const orders = 247 + Math.floor(t * 0.3); const rating = (4.8 + Math.sin(t * 0.6) * 0.05).toFixed(1); const cats = [ { k: 'All', n: 24 }, { k: 'Rice', n: 6 }, { k: 'Noodle', n: 5 }, { k: 'Grill', n: 4 }, { k: 'Drink', n: 9 }, ]; const catActive = featured.cat === 'Rice' ? 1 : featured.cat === 'Noodle' ? 2 : 0; return (
{/* Floating cards */}
Order paid
Table 14 · RM 42.00
{orders}
Orders
today
[i*10, 16 - (Math.sin(i*0.8 + t*0.5)+1)*5]))} fill="none" stroke={GREEN} strokeWidth="1.5"/>
{[0,1,2,3,4].map(i => )}
{rating}
1,284 reviews
{/* Status bar */}
9:41
{/* Header */}
Table 14 · 666 Bistro
Hello, Adam
AL
{/* Search */}
Search the menu… ⌘K
{/* Category chips */}
{cats.map((c, i) => ( {c.k}{c.n} ))}
{/* Featured card */}
Featured today {dishes.slice(0,3).map((_, i) => )}
{featured.name}
{featured.tag}
{featured.name}
{featured.cn} · {featured.cook}
RM {featured.price}
{/* Section header */}
Popular nearby See all →
{/* Menu list */}
{menu.map((d, i) => (
{d.name}
{d.name}
{d.rating} · {d.cook}
RM {d.price}
))}
{/* Floating cart bar */}
{cartCount}
View cart
{cartCount} items · est. 12 min
RM {cartTotal}
{/* Tab bar */}
{cartCount}
{/* fly-to-cart particle */} {added && (
)}
); } /* ============================================================ 3. COMMERCE — real product detail page (browser chrome, thumbs, breadcrumb, rating, sale price, size, trust row) ============================================================ */ function shadeHex(hex, p) { const n = parseInt(hex.slice(1), 16); const r = Math.max(0, Math.min(255, ((n >> 16) & 255) + Math.round(p * 255))); const g = Math.max(0, Math.min(255, ((n >> 8) & 255) + Math.round(p * 255))); const b = Math.max(0, Math.min(255, (n & 255) + Math.round(p * 255))); return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); } function DemoCommerce() { const t = useRaf(); const tick = Math.floor(t / 2.8); const variants = [ { name: 'Sand', color: '#c9b896', price: 459, img: 'https://images.unsplash.com/photo-1539533018447-63fcce2678e3?w=600&h=760&fit=crop&q=80&auto=format' }, { name: 'Charcoal', color: '#2a2c33', price: 459, img: 'https://images.unsplash.com/photo-1544022613-e87ca75a784a?w=600&h=760&fit=crop&q=80&auto=format' }, { name: 'Rust', color: '#a8472c', price: 489, img: 'https://images.unsplash.com/photo-1591047139829-d91aecb6caea?w=600&h=760&fit=crop&q=80&auto=format' }, { name: 'Bone', color: '#e8e2d2', price: 459, img: 'https://images.unsplash.com/photo-1539109136881-3be0616acf4b?w=600&h=760&fit=crop&q=80&auto=format' }, ]; const sizes = ['XS', 'S', 'M', 'L', 'XL']; const soldOut = new Set(['XS']); // shows realistic stock state const sel = tick % variants.length; const sizeIdx = 2; // M selected (realistic — stays still) const v = variants[sel]; const oldPrice = 689; const discount = Math.round((1 - v.price / oldPrice) * 100); // live viewer count (drifts slowly) const viewers = 12 + Math.floor((Math.sin(t * 0.4) + 1) * 6); return (
{/* Browser chrome */}
maison.shop/coats/wool-overcoat
2
{/* Product viewer: vertical thumbnail rail + hero image */}
{variants.map((vr, i) => ( ))}
+4
−{discount}% NEW IN
{`${v.name} { e.currentTarget.style.display = 'none'; }} />
22 SS {v.name.toUpperCase()}
MAISON
{viewers} viewing now 1 / 5
{/* price tag fly-in */}
RM {v.price}
Coats Wool overcoats 22 SS
MAISON
Wool overcoat
4.8 · 124 reviews
RM {v.price} RM {oldPrice} or 3× RM {Math.round(v.price/3)} interest-free
Color · {v.name}
{variants.map((vr, i) => ( ))}
Size · {sizes[sizeIdx]} Size guide ↗
{sizes.map((s, i) => ( ))}
Free shipping 30-day returns Authentic
In stock · ships in 24h from KL
); } /* ============================================================ 4. SCHEDULING — wave-fill calendar + animated booking detail ============================================================ */ function DemoCalendar() { const t = useRaf(); const tick = Math.floor(t / 1.2); const cols = 7, rows = 4; const total = cols * rows; // Wave-fill from upper-left const waveProg = ((t * 0.6) % 6) / 6; const filled = new Set(); const filledPattern = [3, 9, 15, 8, 11, 18, 6, 17, 20, 13, 5, 10, 22, 25, 1, 19]; const cutoff = Math.floor(waveProg * (filledPattern.length + 3)); filledPattern.slice(0, cutoff).forEach(i => filled.add(i)); const selected = filledPattern[tick % filledPattern.length]; const slots = [ { t: '09:00', n: 'Dr. Tan', s: 'Consult' }, { t: '10:30', n: 'Dr. Lim', s: 'Follow-up' }, { t: '11:15', n: 'Dr. Wong', s: 'Scan' }, { t: '14:00', n: 'Dr. Tan', s: 'Consult' }, { t: '15:45', n: 'Dr. Lim', s: 'Follow-up' }, ]; const slotIdx = tick % slots.length; const utilization = Math.min(100, Math.floor((filled.size / total) * 100)); return (
May 2026
Week 20 · Showroom KL
{utilization}%
Booked
{['M','T','W','T','F','S','S'].map((d,i) => {d})}
{Array.from({ length: total }).map((_, i) => { const isFilled = filled.has(i); const isSel = i === selected; return (
{i + 1} {isFilled && }
); })}
{slots.map((sl, i) => (
{sl.t} {i === slotIdx ? 'Selecting…' : sl.n}
))}
); } /* ============================================================ 5. DEVOPS — full production deploy dashboard ============================================================ */ function DemoCode() { const t = useRaf(); const CYCLE_LEN = 18; // seconds const cycle = (t % CYCLE_LEN) / CYCLE_LEN; // Pipeline stages — realistic CI/CD with elapsed times const stages = [ { id: 'install', l: 'Install dependencies', from: 0.00, to: 0.07, dur: 12.4 }, { id: 'lint', l: 'Lint & typecheck', from: 0.07, to: 0.16, dur: 9.1 }, { id: 'test', l: 'Unit + integration', from: 0.16, to: 0.34, dur: 24.7 }, { id: 'build', l: 'Build & containerize', from: 0.34, to: 0.62, dur: 38.2 }, { id: 'deploy', l: 'Rolling deploy · 6 regions', from: 0.62, to: 0.95, dur: 47.3 }, ]; let activeIdx = stages.findIndex((s) => cycle >= s.from && cycle < s.to); const done = cycle >= 0.95; if (done) activeIdx = stages.length; if (activeIdx === -1 && !done) activeIdx = 0; const stageProgress = (i) => { const s = stages[i]; if (cycle < s.from) return 0; if (cycle >= s.to) return 1; return (cycle - s.from) / (s.to - s.from); }; const overall = Math.min(1, cycle / 0.95); // Regions roll out in sequence const regions = [ { loc: 'SIN', city: 'Singapore' }, { loc: 'TYO', city: 'Tokyo' }, { loc: 'HKG', city: 'Hong Kong' }, { loc: 'SYD', city: 'Sydney' }, { loc: 'FRA', city: 'Frankfurt' }, { loc: 'IAD', city: 'N. Virginia'}, ]; const dStart = 0.62, dEnd = 0.95; const dSpan = dEnd - dStart; const regionStatus = (i) => { const w = dSpan / regions.length; const start = dStart + w * i; const end = start + w * 0.85; if (cycle < start) return { s: 'queued', p: 0 }; if (cycle >= end) return { s: 'live', p: 1 }; return { s: 'rolling', p: (cycle - start) / (end - start) }; }; // Live log stream — appears as cycle progresses const allLogs = React.useMemo(() => [ { c: 0.005, l: '$ pnpm install --frozen-lockfile', k: 'cmd' }, { c: 0.030, l: 'Lockfile is up to date · 1,834 packages · cached', k: 'mute' }, { c: 0.060, l: 'done in 11.8s', k: 'ok' }, { c: 0.080, l: '$ pnpm lint && tsc --noEmit', k: 'cmd' }, { c: 0.110, l: 'eslint src/** · 0 errors 0 warnings', k: 'mute' }, { c: 0.145, l: 'tsc · checked 4,212 files · 0 errors', k: 'ok' }, { c: 0.170, l: '$ vitest run --coverage --reporter=dot', k: 'cmd' }, { c: 0.230, l: '· · · · · · · · · · · · · · · · · ·', k: 'mute' }, { c: 0.295, l: '✓ 412 tests passed · branch cov 96.2%', k: 'ok' }, { c: 0.340, l: '$ next build && docker buildx build --platform linux/arm64,linux/amd64 .', k: 'cmd' }, { c: 0.420, l: '○ Compiled successfully · 247 routes · 1.18 MB gzip', k: 'mute' }, { c: 0.495, l: 'Pushed → gcr.io/six6/web@sha256:a3f9b4c2…d7e1', k: 'mute' }, { c: 0.580, l: 'Image scan · 0 critical · 2 low · ok', k: 'ok' }, { c: 0.625, l: '$ kubectl rollout · canary 5% → 100% surge', k: 'cmd' }, { c: 0.665, l: '→ sin1 pulling image · 4/4 ready · healthy', k: 'deploy' }, { c: 0.720, l: '→ tyo1 pulling image · 4/4 ready · healthy', k: 'deploy' }, { c: 0.775, l: '→ hkg1 pulling image · 4/4 ready · healthy', k: 'deploy' }, { c: 0.830, l: '→ syd1 pulling image · 4/4 ready · healthy', k: 'deploy' }, { c: 0.875, l: '→ fra1 pulling image · 4/4 ready · healthy', k: 'deploy' }, { c: 0.920, l: '→ iad1 pulling image · 4/4 ready · healthy', k: 'deploy' }, { c: 0.955, l: '✓ shipped v2026.5.17 · 2m 31s · 0 downtime · 24/24 pods', k: 'ok' }, ], []); const shownLogs = allLogs.filter((L) => cycle >= L.c); const tailRef = React.useRef(null); React.useEffect(() => { if (tailRef.current) tailRef.current.scrollTop = tailRef.current.scrollHeight; }, [shownLogs.length]); return (
{/* Header — branch, commit, status */}
{done ? 'Deployed' : 'Deploying'} main fix/checkout-poll
8f3a2c1d · v2026.5.17
{/* Commit message */}
fix(checkout): debounce inventory polling on quantity step @nadia · 2 files · +47 −12
{/* Body — pipeline + terminal */}
{stages.map((s, i) => { const isAct = i === activeIdx && !done; const isDone = (i < activeIdx) || done; const p = stageProgress(i); const elapsed = isDone ? s.dur : isAct ? p * s.dur : 0; return (
{isDone ? ( ) : isAct ? ( ) : ( )} {s.l} {isDone ? `${s.dur.toFixed(1)}s` : isAct ? `${elapsed.toFixed(1)}s` : '—'} {isAct && ( )}
); })}
runner · ubuntu-22.04 · 8 cpu
{shownLogs.slice(-14).map((L, i) => (
{L.l}
))} {!done &&
}
{/* Overall progress */}
{Math.round(overall * 100)}%
{/* Region rollout */}
{regions.map((r, i) => { const rs = regionStatus(i); return (
{r.loc}
{r.city}
{rs.s === 'queued' && queued} {rs.s === 'rolling' && ( {Math.round(rs.p * 100)}% )} {rs.s === 'live' && v2026.5.17}
); })}
); } /* ============================================================ SECTION ============================================================ */ function SkillPanel({ n, label, titleKey, desc, flip, Comp }) { return (
{n}
{label}

{desc}

); } function Work() { const { t } = useLang(); const skills = [ { n: '01', label: t('work.1.label'), titleKey: 'work.1.title.html', desc: t('work.1.desc'), Comp: DemoAnalytics, flip: false }, { n: '02', label: t('work.2.label'), titleKey: 'work.2.title.html', desc: t('work.2.desc'), Comp: DemoMobile, flip: true }, { n: '03', label: t('work.3.label'), titleKey: 'work.3.title.html', desc: t('work.3.desc'), Comp: DemoCommerce, flip: false }, { n: '04', label: t('work.4.label'), titleKey: 'work.4.title.html', desc: t('work.4.desc'), Comp: DemoCalendar, flip: true }, { n: '05', label: t('work.5.label'), titleKey: 'work.5.title.html', desc: t('work.5.desc'), Comp: DemoCode, flip: false }, ]; return (
{t('work.kicker')}{t('work.kicker.right')}

{t('work.lead')}

{skills.map((s) => ())}
); } window.Work = Work;