Project Overview

architectureAstrooverview

Last updated: Feb 19, 2026


1. Project Overview

bythewei.dev is Weixiang Zhang’s personal developer portfolio and sprint board, styled as a physical corkboard covered in sticky notes, pushpins, and tape. It functions as a live dashboard showing the current state of the Voxlight product family, alongside personal reading data and book highlight archives.

The site is a single-page application with three major interactive sections:

  1. Sprint Board — A kanban-style corkboard showing the current development sprint (columns for shipped code, tests, blockers, docs, marketing) with sticky notes driven by sprint.json.
  2. The Catalog — A hidden bookshelf modal (triggered by a pin icon) that displays all highlighted book passages from Apple Books, rendered as book spines on wooden shelves. Clicking a spine opens the Reading Journal for that book.
  3. The Reading Year — A data visualization modal showing 150 books read between Feb 2019 and Feb 2020, with genre bars, diversity breakdowns, emotional receipts, and interactive cross-highlighting.

Additionally, the page includes:

  • A Quote of the Day drawn deterministically from bookmark highlights (same quote worldwide per calendar day, no server needed).
  • A kaomoji rotation engine that swaps all kaomoji faces daily using a date-seeded hash.
  • A “Who Is This Guy” section with links to blog, fiction site, Threads, GitHub, Instagram, Goodreads, and Guilty Gear stats.
  • A custom 404 page themed as a fallen sticky note.
FieldValue
URLhttps://bythewei.dev
HostingVercel (static deployment)
GitHubhttps://github.com/noxwei/bythewei
Branchmain

2. Tech Stack

LayerTechnology
FrameworkAstro 5.17+
Adapter@astrojs/vercel 9.0+
Output modestatic (pre-rendered HTML at build time)
TypeScriptStrict (extends astro/tsconfigs/strict)
InteractivityVanilla JavaScript (inline <script> tags)
StylingScoped CSS + <style is:global> blocks
FontsGoogle Fonts (Permanent Marker, Fredoka, Kalam, Patrick Hand)
AnalyticsVercel Web Analytics (built into adapter)
Framework islandsNone — zero React/Vue/Svelte/Preact

There are no UI framework dependencies. All interactivity (modals, tooltips, search, cross-highlighting, scroll tracking, localStorage persistence) is written in plain JavaScript inside <script> tags in index.astro.


3. File Structure

bythewei/
|-- package.json                 # Project manifest, scripts, dependencies
|-- package-lock.json            # Lockfile (npm)
|-- astro.config.mjs             # Astro config: site URL, Vercel adapter, web analytics
|-- tsconfig.json                # TypeScript strict config extending Astro defaults
|-- vercel.json                  # Vercel deployment config (build command, output dir)
|-- .gitignore                   # Standard ignores: dist/, node_modules/, .env, .astro/
|-- README.md                    # Default Astro minimal template readme (not customized)
|
|-- src/
|   |-- layouts/
|   |   |-- Layout.astro         # Base HTML layout: <head>, fonts, global CSS, cork texture
|   |
|   |-- pages/
|   |   |-- index.astro          # THE site (2491 lines): sprint board, catalog, journal,
|   |   |                        #   reading year, QOTD, kaomoji engine, all CSS + JS
|   |   |-- 404.astro            # Custom 404: fallen sticky note theme
|   |
|   |-- data/
|       |-- sprint.json          # Sprint board content: meta, stats, columns, stickies
|       |-- kaomojis.ts          # 200 kaomojis in categorized array (happy, angry, animals...)
|       |-- bookmarks.json       # Raw Apple Books highlights export (3204 lines)
|       |-- bookmarks.clean.json # Processed highlights: deduped, cleaned, with IDs (17571 lines)
|       |-- reading-log.json     # 150-book reading year dataset (3751 lines)
|
|-- public/
|   |-- favicon.ico              # Favicon (ICO format)
|   |-- favicon.svg              # Favicon (SVG format)
|   |-- data/
|       |-- bookmarks.clean.json # Public copy of cleaned highlights (fetched at runtime)
|       |-- reading-log.json     # Public copy of reading log (fetched at runtime)
|
|-- scripts/
|   |-- extract-datajar.mjs      # Extracts highlights from DataJar JSON/ZIP/.datajar exports
|   |-- process-bookmarks.mjs    # Full pipeline: clean, normalize, dedupe, generate IDs
|   |-- merge-bookmarks.mjs      # Incrementally merge new exports into existing clean DB
|   |-- strip-location.mjs       # Legacy: strip location + clean highlights (superseded by process-bookmarks)
|   |-- convert-reading-log.mjs  # Converts reading year CSV to JSON for the reading modal
|   |-- verify-clean.mjs         # QA: checks bookmarks.clean.json for boilerplate/whitespace
|
|-- .vscode/
|   |-- extensions.json          # Recommends astro-build.astro-vscode extension
|   |-- launch.json              # Dev server launch config
|
|-- dist/                        # Build output (gitignored)
|-- .astro/                      # Astro cache (gitignored)
|-- .vercel/                     # Vercel local config (gitignored)

4. Getting Started

Prerequisites

  • Node.js 18+ (LTS recommended)
  • npm

Clone and Install

git clone https://github.com/noxwei/bythewei.git
cd bythewei
npm install

Development Server

npm run dev

Opens at http://localhost:4321. Hot-reloads on file changes.

Build

npm run build

Outputs static files to dist/.

Preview Production Build

npm run preview

Serves the built dist/ directory locally to verify before deploying.

Deploy

Push to main branch. Vercel auto-deploys from GitHub.

git push origin main

5. Configuration

astro.config.mjs

import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';

export default defineConfig({
  site: 'https://bythewei.dev',
  adapter: vercel({
    webAnalytics: { enabled: true },
  }),
  output: 'static',
});
SettingValuePurpose
sitehttps://bythewei.devCanonical URL for OG tags and sitemap
adapter@astrojs/vercelVercel deployment adapter
webAnalytics.enabledtrueInjects Vercel Web Analytics script
outputstaticPre-renders all pages at build time; no server-side rendering

tsconfig.json

Extends astro/tsconfigs/strict. Includes .astro/types.d.ts for Astro type support. Excludes dist/.

vercel.json

{
  "buildCommand": "npm run build",
  "outputDirectory": "dist",
  "framework": "astro"
}

6. Build & Deploy

Static Output

The site is fully static. At build time, Astro renders index.astro and 404.astro into HTML files. JSON data files in public/data/ are copied as-is to dist/data/ and fetched by the browser at runtime.

Vercel Deployment

  • Trigger: Push to main branch on GitHub.
  • Build command: npm run build
  • Output directory: dist/
  • Framework detection: Astro (configured in vercel.json)
  • Analytics: Vercel Web Analytics auto-injected via the adapter.

Environment

No environment variables are required. The site has no server-side logic, no API keys, and no database connections.


7. Content Editing Guide

7a. Update Sprint Board Content

Edit /Users/weixiangzhang/Local_Dev/projects/bythewei/src/data/sprint.json.

The file structure:

{
  "meta": {
    "date": "Feb 18, 2026",
    "title": "VOXLIGHT -- FEB 18 SPRINT",
    "subtitle": "One founder. One day. One gate left."
  },
  "stats": [
    { "value": "111", "label": "tests passing" }
  ],
  "columns": [
    {
      "header": "SHIPPED CODE",
      "stickies": [ ... ]
    }
  ],
  "bottom_row": [ ... ],
  "footer": "WEIXIANG INC -- BYTHEWEI.DEV -- FEB 18 2026"
}
  • meta.title and meta.subtitle appear in the page banner.
  • stats array renders as dark stat cards below the banner.
  • columns array renders the main kanban grid (currently 5 columns).
  • bottom_row renders the freeform stickies at the bottom.
  • footer is the text at the very bottom of the page.

7b. Add New Stickies

Add an object to a column’s stickies array:

{
  "color": "g",
  "size": "big",
  "rotation": "r2",
  "tape": true,
  "stamp": "DONE",
  "title": "Feature Name",
  "body": "Description of what shipped.\nLine breaks with \\n.",
  "tag": "commit-hash",
  "blocker": false
}
FieldValuesNotes
colory (yellow), g (green), p (purple), b (blue), o (orange), r (red), w (white), tealSets the sticky note gradient
sizenull, "big"Big stickies get larger padding/font
rotation"r1" through "r7"CSS rotation angle
tapetrue, false, "center", "left", "right"Tape strip position
stampnull, "DONE", "IN PROGRESS", or any stringGreen for DONE, orange for anything else
blockertrue, falseAdds red border + glow
tagnull or stringSmall metadata tag at bottom

7c. Update Bookmark Highlights (The DataJar Pipeline)

The bookmark data comes from Apple Books highlights, exported via the DataJar iOS app. The pipeline:

  1. Export from DataJar — Export a .datajar, .zip, or store.json file from DataJar on iOS.

  2. Extract raw entries:

    node scripts/extract-datajar.mjs path/to/export.datajar > src/data/bookmarks.json
  3. Process into clean format (full reprocess):

    node scripts/process-bookmarks.mjs

    This reads src/data/bookmarks.json, cleans highlights (strips boilerplate, normalizes authors, generates SHA-1 IDs, deduplicates), and writes to both src/data/bookmarks.clean.json and public/data/bookmarks.clean.json.

  4. Merge new entries (incremental, preserves existing):

    node scripts/merge-bookmarks.mjs path/to/new-export.json

    Adds only new entries to the existing clean database without reprocessing everything.

  5. Verify output:

    node scripts/verify-clean.mjs

    Checks for remaining boilerplate, whitespace issues, and prints statistics.

The cleaned JSON is fetched at runtime by the browser for the Quote of the Day, the Catalog bookshelf, and the Reading Journal.

7d. Update Reading Log Data

The reading log is a dataset of 150 books read between Feb 2019 and Feb 2020. To update:

  1. Export reading data as CSV from the source spreadsheet (expected at ~/Downloads/Reading Data - Primary.csv).

  2. Convert to JSON:

    node scripts/convert-reading-log.mjs

    Outputs to both src/data/reading-log.json and public/data/reading-log.json.

Each book entry includes: title, author, dates, rating (1-5), gender (F/M/N), poc (boolean), emotions array, emotional_output, difficulty, pages, genre, fiction/non-fiction, country, and optional review text.

7e. Add New Kaomojis

Edit /Users/weixiangzhang/Local_Dev/projects/bythewei/src/data/kaomojis.ts.

The file exports a kaomojis string array with 200 entries organized by category (happy, excited, surprised, angry, sad, cool, fighting, love, shrug, animals, magic, tired, running). Add new entries to the appropriate category section. The daily rotation engine uses a date-seeded hash to deterministically select unique kaomojis for each [data-kaomoji] element on the page.


8. Key URLs

ResourceURL / Path
Live sitehttps://bythewei.dev
GitHub repohttps://github.com/noxwei/bythewei
Vercel dashboardhttps://vercel.com (project: bythewei)
Local project/Users/weixiangzhang/Local_Dev/projects/bythewei/

9. Dependencies

The project has exactly two npm dependencies:

PackageVersionPurpose
astro^5.17.1Static site generator. Compiles .astro files to HTML, handles asset pipeline, dev server, and build tooling.
@astrojs/vercel^9.0.4Vercel deployment adapter. Configures output for Vercel hosting and injects Vercel Web Analytics script.

There are no other runtime or development dependencies. No CSS frameworks, no bundlers, no testing libraries, no linters configured at the project level. The scripts/ utilities use only Node.js built-in modules (fs, path, crypto, url).


10. Architecture Decisions

Why Astro

Astro is a content-focused static site generator that ships zero JavaScript by default. For a personal portfolio that is essentially one page of styled HTML with some client-side interactivity, Astro provides:

  • File-based routing (src/pages/ maps directly to URLs)
  • Scoped CSS in .astro files (no CSS-in-JS library needed)
  • define:vars for passing server-side data to inline scripts
  • Built-in TypeScript support
  • First-class Vercel adapter with analytics integration

Why No React/Vue/Svelte

The entire site is a single page with three modals. The interactivity (catalog bookshelf, journal pagination, reading year charts, search, cross-highlighting) is DOM manipulation that would gain nothing from a component framework. Using vanilla JS:

  • Ships zero framework runtime (no React, no virtual DOM, no hydration)
  • The full page loads as pre-rendered HTML with inline scripts
  • Total dependency footprint is 2 packages
  • No component lifecycle complexity for what is fundamentally “show/hide divs and build DOM nodes from JSON”

Why Vanilla JS for Interactivity

All interactive features use a single IIFE in a <script> tag. The patterns are straightforward:

  • fetch() to load JSON from public/data/
  • document.createElement() and innerHTML for building catalog spines, journal entries, and chart elements
  • addEventListener for clicks, hover, keyboard (Escape to close modals)
  • localStorage for persisting dog-ear bookmarks and scroll positions
  • CSS classes toggled for highlight states

This is readable, debuggable, and has zero build overhead.

Why Static Output

The site has no server-side logic. All data is baked into JSON files at build time or fetched from public/data/ at runtime. Static output means:

  • Instant deploys (just copy files to CDN)
  • No cold starts, no serverless functions, no edge runtime
  • Free Vercel hosting tier
  • The “Quote of the Day” changes daily using a client-side date-seeded hash, requiring no server

Data Architecture

The bookmark and reading data follow a two-copy pattern:

  • src/data/*.json — imported at build time by Astro for any server-side rendering needs
  • public/data/*.json — served as static files, fetched by client-side JS at runtime

This allows the QOTD, catalog, and reading year modals to load data lazily after the page renders, keeping the initial HTML payload small while still having the data available for build-time use if needed.


Git Branches

BranchStatus
mainActive development, auto-deploys to Vercel
bookmark-systemFeature branch for bookmark pipeline scripts
bookmark-integrationFeature branch for catalog/journal UI
masterLegacy default branch (superseded by main)

Recent commits (as of Feb 19, 2026):

9977dd2 feat: Reading Year modal + orphan title fixes + catalog saturation
750573d feat: hidden bookshelf -- the memory palace
8bfd37e feat: Zato's String favicon + book highlights popup modal
90bf6c9 feat(bookmarks): full pipeline system -- stable IDs, author normalisation, merge tool
a5dc177 feat: add Vercel Web Analytics