

Web Development
A dual-domain portfolio built on a Turborepo monorepo with Next.js, featuring a file-based CMS, an Obsidian-style knowledge graph, and shared UI components.
Year
2025
Role
Designer & Developer
Technologies
Next.js, React, TypeScript, TailwindCSS
This project is a modern, performant platform designed to serve two distinct domains—harrychang.me and lab.harrychang.me—from a single, unified codebase. Architected as a Turborepo monorepo, it manages multiple Next.js applications efficiently. This structure was adopted to streamline development and share code not only between my main portfolio and experimental lab but also to support the development of my sister's portfolio, emilychang.me.
The core of the main portfolio is a custom Markdown-based content system. This architecture parses Markdown files from a central content/ directory at build time to generate static pages, eliminating the need for a traditional database for the main site and resulting in a highly performant and easily maintainable website.
The front end is developed with React and TypeScript, ensuring a robust, type-safe codebase. The user interface is styled with TailwindCSS for rapid, utility-first development and features a responsive three-column layout inspired by the portfolio of Joseph Zhang.
The heart of this project is its flexible architecture. Next.js middleware dynamically rewrites requests based on the subdomain, directing users to either the main portfolio or the lab while using a single Next.js instance. Content for the main portfolio is stored in Markdown files, effectively creating a headless CMS. A custom script processes these files using several key libraries:
gray-matter parses YAML frontmatter from each file to provide metadata.remark and remark-html convert the Markdown content into HTML for rendering.This structure cleanly separates content from presentation and allows for simple, Git-based content updates.
Performance, scalability, and advanced features were primary goals during development.
Monorepo Efficiency: Using Turborepo, we share UI components, hooks, and utility functions across different applications from packages/ui and packages/lib. This drastically reduces code duplication and simplifies dependency management.
Static & Dynamic Rendering: The main portfolio uses Static Site Generation (SSG) for exceptional performance. All pages are pre-rendered at build time, and Next.js’s automatic code-splitting ensures minimal load times. The lab section is rendered dynamically to support its database-driven features.
Dynamic Media: A custom Remark plugin, transformMedia, was developed to intelligently handle various media types. It traverses the Markdown structure to embed YouTube and Google Drive videos with custom placeholders and replaces standard images with optimized figure elements that feature lazy loading and a shimmer effect.
Image Optimization: A custom script automates converting images to the modern WebP format. It also resizes them and generates low-quality image placeholders to create a "blur-up" effect while loading.
API Integration: The footer includes a real-time "Now Playing" component that fetches my current Spotify activity via the Spotify API, displayed with a custom animated progress card.
Internationalization (i18n): The site supports English and Traditional Chinese through a custom, client-side React Context. Content is localized based on filename suffixes (_zh-tw.md), and the site gracefully falls back to English if a translation is unavailable.
Inspired by Obsidian's graph view, the site features an interactive knowledge graph that visualizes the relationships between all content—projects, blog posts, gallery items, and papers. Built with D3.js force-directed simulation and rendered on an HTML5 Canvas, nodes are linked by shared tags, categories, and contextual similarity generated through an offline embedding pipeline.
The full graph is accessible at a dedicated /graph route with category filtering, a mobile-optimized node card, and cursor-following preview tooltips. A compact, embedded version also powers the "Next Up" card on every content page, showing a local neighborhood subgraph to surface related content and encourage exploration.
The portfolio is designed to showcase a variety of work and thought, with key sections including:
The source code for this site is available on GitHub under a CC BY-NC 4.0 license. All content, including text and images, is protected by copyright.