CV Hub
Resume as Code. Treat your professional identity as a reproducible, versioned system.
Overview
CV Hub is not a portfolio template. It is a system. The project redefines a resume as an engineering artifact — versioned, reproducible, and deployable. Instead of maintaining fragmented representations across LinkedIn, PDF, Notion, and portfolio sites, CV Hub introduces a single declarative source of truth — a YAML file — that drives the entire output pipeline. The result is a fully automated system where one change propagates consistently across every format and every role-specific variation. The very page you are reading is part of it: this case study is rendered from a block-based YAML document by the same engine that builds the CV.
Problem
Traditional resumes are fundamentally broken from a systems perspective. They are: - duplicated across platforms - manually synchronized - context-dependent (DevOps vs Backend vs GameDev) - not version-controlled - not reproducible This leads to drift, inconsistency, and significant maintenance overhead. From an engineering standpoint, this is equivalent to running multiple unsynchronized environments without a single source of truth.
Solution
CV Hub applies infrastructure principles to personal data. The core idea is simple: define once → generate everything → deploy automatically. A single YAML file becomes: - a live website - PDF, DOCX, and TXT artifacts - multiple role-specific CV versions - a versioned, Git-controlled professional profile The system eliminates duplication and enforces consistency by design.
Multi-profile system
Base + delta architecture
Role-specific resumes are generated using a two-layer model: a base CV plus per-profile delta overrides. This allows precise control over positioning without duplicating data.
How profiles work
Each profile is declared once in `profiles.yml` with an id, a URL slug, and a spec key. At build time `merge.mjs` walks every profile × language combination and produces a normalized artifact per pair. The merge is deliberately explicit rather than magical: - Scalar and list fields in a delta replace the base value outright. - Experience entries are matched by company name — a delta entry carrying just a company inherits the base entry and overrides only the fields it specifies. - A profile's experience list fully defines its own ordered set, so each role can curate exactly the history that is relevant to it. The output is deterministic: the same source always yields the same artifacts, and a build-time guard enforces that a profile's routing slug and its file-spec key stay in sync, so a profile's page can never silently desync from its CV and downloads.
Internationalization
Languages are a first-class axis, not an afterthought. The system renders an N profiles × N languages matrix from a single content base. - A `languages.yml` registry defines available languages and the default; the header language switcher is generated from it. - Every UI string lives in `translations.yaml` and is resolved through a small `makeT()` helper with a fallback chain: requested language → English → the key itself, so a missing translation degrades gracefully instead of breaking the page. - Routing is fully static. `[...slug].astro` emits one page per profile × language combination, and the default-language home stays at the clean root path. Chinese translations already ship in the content layer, ready to be switched on by adding a single line to the language registry.
What I built
- Static-first architecture with zero client-side JavaScript by default
- YAML-based Single Source of Truth for all resume data
- Multi-profile system (DevOps, GameDev, etc.) via a deterministic merge pipeline
- Multi-language support with a graceful fallback chain
- Automated document generation (PDF via Playwright, DOCX/TXT via docx.js)
- A block-based case-study engine powering these Deep Dive pages
- Four interchangeable animated background components (CSS and Canvas)
- URL-based theme switching with shareable state
- Fully automated CI/CD pipeline using GitHub Actions with Telegram alerts
- Dynamic environment-aware configuration (siteUrl from GITHUB_REPOSITORY)
Architecture
The system is built as a deterministic pipeline. Data layer: - YAML files (base CV + profile deltas, showcase projects, case studies, translations, changelog) Processing layer: - merge.mjs → produces normalized per-profile, per-language artifacts - document generators → create PDF / DOCX / TXT from those artifacts Presentation layer: - Astro static build → pre-rendered HTML, content validated by typed schemas Deployment: - GitHub Actions → immutable build → GitHub Pages No runtime server. No hidden state. No database. Every output is reproducible from source, and content shape is validated by Zod schemas before a single page is built.
Dynamic backgrounds
The atmosphere of the site is driven by a small library of interchangeable background components. Only one is active at a time — they are designed as a drop-in palette, each self-contained and configured through the same design-token system as the rest of the styling. There are two families: a CSS-only layer that costs almost nothing, and a set of Canvas renderers inspired by the PlayStation XMB interface. Each is shown below.
AnimatedBackground — the default
Pure CSS · zero JavaScript
Four large radial-gradient orbs drift behind the content with a fine noise overlay on top. It is entirely CSS — no JavaScript, no canvas, no main-thread work. It is also the most performance-tuned: the keyframes animate translation only (no scale), so the browser caches each blurred orb as a texture and simply moves it instead of re-rasterizing an 60px blur every frame. The whole layer is disabled below 768px and honors `prefers-reduced-motion`.
GalaxyBackground
Canvas · requestAnimationFrame
A canvas-rendered starfield with slow parallax drift, accent-tinted to the active theme. A heavier, more cinematic option for when atmosphere matters more than idle cost.
PlayStationWaves
Canvas · XMB-inspired filled waves
Filled sine waves layered like the PlayStation XMB menu, with a time-of-day hue shift and a non-deterministic start position (seeded from the timestamp) so no two loads look identical. Roughly 18 props expose wave count, speed, amplitude, color and draw quality.
WaveLines
Canvas · XMB-inspired glow lines
A stroke-based cousin of PlayStationWaves: glowing lines arranged symmetrically around a center axis. Each line's glow is composited on its own offscreen canvas to avoid a subtle bug where a shared `destination-in` mask was eating the background alpha at the edges.
Background performance engineering
Beautiful backgrounds are easy to make janky, so they are treated as a performance surface in their own right. - The CSS orbs avoid per-frame blur re-rasterization by animating transforms only. - The full-page gradient lives on a fixed pseudo-element layer instead of `background-attachment: fixed`, so it never repaints on scroll. - A fullscreen `mix-blend-mode` pass was removed once it proved invisible at its opacity but expensive every frame. - Every animated background is disabled on small screens and respects reduced-motion. The net effect: rich motion on capable desktops, and a calm, cheap render everywhere else.
Themes
Theming is a set of CSS custom properties layered over a token base. A theme is selected with a `?theme=` URL parameter and applied through a tiny inline script, which keeps the state shareable — send a link and the recipient sees exactly the palette you chose.
Document export pipeline
The same merged YAML that renders the site also generates downloadable documents, so the web and offline versions can never drift apart. - PDF is produced by rendering a print-tuned layout in headless Chromium via Playwright — pixel-faithful to the site. - DOCX is built programmatically with docx.js, producing a real editable Word document rather than a screenshot. - TXT is emitted as a clean plain-text fallback for ATS systems and copy-paste. Every profile × language pair gets its own set of files, generated in CI and linked directly from the matching page.
CI/CD & automation
Shipping is a single `git push`. - GitHub Actions runs the full pipeline on every push to main: merge → generate documents → render PDFs → static build → deploy to Pages. - The Playwright Chromium binary is cached by lockfile hash, shaving roughly two minutes off a cold deploy. - A Telegram bot reports the result — success, build failure, or deploy failure — with branch and short commit SHA, degrading silently if no secrets are configured. - `siteUrl` and base path are derived from `GITHUB_REPOSITORY`, so a fork builds and deploys correctly with zero configuration. - A sitemap covering every profile × language route is generated at build time, with a matching robots.txt.
Performance engineering
Performance is measured, not assumed. - Static, pre-rendered HTML with no hydration cost by default. - The first Showcase cover with a real image is loaded eagerly with high fetch priority; everything else stays lazy — a deliberate LCP optimization. - Scroll-time compositing was profiled and the expensive layers (fixed gradient repaints, a fullscreen blend pass) were removed. - Result: Lighthouse 100 Performance / 100 Accessibility / 100 SEO, with motion that stays smooth on low-end hardware.
The Showcase system
The portfolio half of the site is the same idea applied recursively. Projects are declared in a YAML list, and each can carry a full Deep Dive case study — like this one — assembled from a small set of content blocks: text, image, divider and links. The blocks are validated by a typed schema and rendered by dedicated components, which means a long-form, editorial case study is authored entirely in data, with no bespoke page code. It behaves like a controlled, static alternative to a Notion page: portable, versioned, and fast.
Engineering Decisions
- Astro over SPA frameworks to eliminate unnecessary runtime and hydration cost
- Static generation to guarantee performance and predictability
- YAML over a CMS to retain full control and Git-native versioning
- URL-driven state instead of localStorage for shareability and transparency
- Explicit delta files instead of implicit overrides to keep changes observable
- Typed content schemas so malformed data fails the build instead of the browser
DevOps Approach
The project treats a resume as a build artifact. Key principles: - Git-based versioning - Immutable builds - CI/CD automation - Environment-independent deployment - Zero runtime dependencies Every commit produces a fully consistent, deployable state of the system.
Trade-offs
- No CMS — intentional trade-off for control and transparency
- No backend — static-only architecture
- Manual delta creation for profiles — explicit over implicit complexity
- Canvas backgrounds cost more than the CSS default — hence one default, the rest opt-in
- Limited runtime flexibility in favor of determinism
Result
- One edit regenerates all formats across all profiles and languages
- Fully static deployment with zero infrastructure cost
- Fork-ready system with zero configuration required
- Lighthouse: 100 Performance / 100 Accessibility / 100 SEO
- Predictable, reproducible output across environments
Takeaways
CV Hub demonstrates that even non-traditional domains like resumes benefit from engineering rigor. By applying system design principles — single source of truth, deterministic pipelines, and automation — the project transforms a static document into a scalable, maintainable system. This approach generalizes beyond resumes to any domain where data consistency, reproducibility, and multi-target output matter.