Jump to content

Website

From Archive
Revision as of 17:30, 16 November 2025 by Claude (talk | contribs) (Add "Distinctive Features" section documenting unique systems and approaches)

Personal website technical documentation. Actively maintained reference for ejfox.com architecture, features, and implementation details.

Last updated: 2025-11-16

Overview

Personal website and digital publishing system built with Nuxt 3. Primary purpose: publishing blog posts, predictions, and stats from multiple APIs. Content originates in Obsidian, gets processed to structured JSON, then served via Vue components.

Deployed via Docker containers with health checks. Production URL: https://ejfox.com

Architecture

Technology Stack

  • Nuxt 3 (Vue 3, TypeScript)
  • Docker containerized deployment
  • Node.js server-side rendering
  • Tailwind CSS with custom 8px baseline grid
  • Georgia serif typography, 80-character line length enforcement

Content Pipeline

Content flows through a multi-stage processing system:

  1. Markdown files written in Obsidian vault
  2. scripts/processMarkdown.mjs converts MD to structured JSON
  3. Individual JSON files stored in content/processed/
  4. manifest-lite.json generated for listings
  5. Vue components consume processed JSON, not raw Markdown

Processing includes: YAML frontmatter parsing, remark/rehype plugins, TOC extraction, tag counting, image optimization (Cloudinary srcset generation), code syntax highlighting.

Main Pages

Blog

Primary content type. Posts stored in content/blog/YYYY/ with drafts in content/blog/drafts/. Each post has YAML frontmatter with tags, date, dek, and optional metadata.

Sidenotes system implemented via 113-line client-side plugin that transforms standard Markdown footnotes into margin notes (Tufte CSS approach). Footnotes appear in right margin on desktop (>1280px), collapse to standard footnotes on mobile.

Projects

Showcases code and art experiments, data visualization work, digital tools. Two tiers: featured work and archive. Uses Swiss grid system (12-column on desktop). Project descriptions rendered from processed Markdown with full image support. TOC sidebar for navigation.

Technical detail: Images previously had forced 16:9 aspect ratio causing cropping. Fixed to respect natural aspect ratios while maintaining grid containment.

Predictions

Two subsystems:

Cryptographic Predictions - CLI tool (yarn predict) creates SHA-256 hashed predictions with optional PGP signing. Git commits provide timestamp proof. Storage: content/predictions/ as Markdown with verification data.

Kalshi Integration - Real-money prediction market positions tracked via live API. Features:

  • Multi-layer smart caching (portfolio: 2min, events: 1hr, commentary: 10min)
  • Commentary system in content/kalshi/*.md for position analysis
  • Calibration tracking with Brier scores and calibration curves
  • Portfolio P&L tracking (open/closed positions)
  • Type-safe API consumer with full schema definitions in server/types/kalshi.ts

Scripts: kalshi:test, kalshi:templates, kalshi:calibration

Gear

CSV-based gear inventory system with weight calculations. Features:

  • Dynamic unit conversion (metric/imperial)
  • Tuftian data visualizations (weight distributions, histograms)
  • Ultra-dense data tables on 8px baseline grid
  • Container-based organization with inline statistics

Data source: data/gear.csv with Weight_oz column. No TCWM scoring (removed in delete-driven cleanup).

Stats

Multi-source API aggregation dashboard. Integrates: GitHub, YouTube, LastFM, Chess.com, RescueTime, MonkeyType, photo counts. Caching layer prevents rate limit issues. Endpoint: server/api/stats.get.ts

Real-time personal metrics with sparkline visualizations.

Design System

Typography

  • Primary: Georgia serif (system font, no custom loading)
  • Monospace: System monospace stack
  • 8px baseline grid enforced throughout
  • 80-character line length limit (ESLint enforced)
  • Journalist pyramid ordering for tags (special tags first, then by usage frequency)

Layout

  • Editorial left-aligned content within max-w-screen-xl container (1280px)
  • Swiss grid: 12-column system on desktop, single column mobile
  • No horizontal centering via mx-auto for main content (left-aligned)
  • Spacing: 2-4-8 rhythm (multiples of 8px)

Image Handling

Classes: .img-full, .img-large, .img-medium, .img-small

All images auto-optimized via Cloudinary: srcset generation, f_auto, q_auto, multiple width variants (400w, 800w, 1200w). Lazy loading and async decoding enabled. Aspect ratios preserved (no forced cropping).

Development Philosophy

Delete-Driven Development

Primary methodology: "When system hangs, delete code until it works. No clever fixes, no complex solutions. Find the bloat, delete it. Simple beats complex. Working beats perfect."

Examples of deletions:

  • 15MB+ lighthouse reports and build logs from root
  • Looping animations causing flicker
  • Complex TCWM scoring from gear page
  • 800+ line sidenotes system replaced with 113-line client plugin
  • Custom fonts replaced with system Georgia

Code Quality

  • TypeScript strict mode enabled
  • ESLint with 80-char line enforcement
  • Zero unused variable warnings (all prefixed with underscore or removed)
  • Modern empty catch syntax for unused error parameters

Deployment

Docker-based with docker-compose. Health check endpoint: /api/healthcheck

Build artifacts stored in .nuxt and .output. Environment variables in .env (not committed).

Restart procedure: docker-compose restart for .env changes, full rebuild: docker-compose down && docker-compose up -d --build

Notable Technical Details

  • Tags endpoint (server/routes/tags.json.ts) serves dynamic JSON with usage-frequency ordering
  • Git-based content versioning (all posts committed to main branch)
  • No mermaid diagrams (64MB bloat, deleted)
  • Prose styles: .prose class with zinc color scheme, custom paragraph spacing
  • Image-in-paragraph fix: .prose p img exceptions for size classes
  • Client-side rendering for heavy components (sparklines, visualizations)

Distinctive Features

This website diverges significantly from typical personal sites through systems-level thinking and data-first architecture.

Cryptographic Accountability

Predictions combine SHA-256 hashing, Git commits, and optional PGP signing for tamper-proof forecasting. Each prediction includes hash, gitCommit, pgpSignature, and optional blockchainAnchor fields. Git provides immutable timestamp proof via commit history at github.com/ejfox/website2. Unlike typical prediction systems, modifications require breaking cryptographic chain.

Prediction Calibration Analysis

scripts/calibration-analysis.mjs implements automated forecasting accuracy measurement using Brier scores (0=perfect, <0.25=good). System tracks:

  • Confidence bucket analysis (50-59%, 60-69%, etc.) comparing predicted vs actual outcomes
  • Category-specific performance breakdown
  • Confidence drift patterns over time
  • Market comparison accuracy (when disagreeing with Kalshi consensus)
  • Calibration curves for expected vs actual accuracy
  • Year-over-year trend analysis

This level of epistemic rigor is uncommon outside academic forecasting research.

Multi-Layer Smart Caching

Kalshi integration employs tiered cache strategy based on data volatility:

  • Portfolio positions: 2-minute refresh (high volatility)
  • Market events: 1-hour refresh (low volatility)
  • User commentary: 10-minute refresh (manual updates)

System handles 404s from resolved markets by falling back to user-written commentary files, acknowledging that Kalshi removes historical data. Three-tier title resolution: user commentary (most reliable) → live API → ticker fallback.

Journalist Pyramid Tag Ordering

server/routes/tags.json.ts implements editorial hierarchy for tag display. Order: special tags (prefixed with !) first, then content tags by usage frequency, then unused base tags last. Combines static vocabulary (/public/tags.json) with dynamic usage counts (/public/content-tags.json). Prioritizes editorial signal over alphabetical sorting.

Tuftian Data Visualization

Gear inventory (pages/gear/index.vue) implements Edward Tufte's principles: maximum data-ink ratio, minimal decoration. Features:

  • Normalized weight distribution bars across all items
  • Mini histograms in table headers showing collection distributions
  • Container-based organization with inline statistics
  • Real-time metric/imperial conversion via composables/useWeightCalculations.ts
  • Ultra-dense tables on 8px baseline grid

Treats personal gear collection as dataset requiring analytical dashboard rather than simple list.

Content as Data

Processing pipeline (scripts/processMarkdown.mjs) treats content as structured data rather than strings. Reads from Obsidian vault, applies custom remark/rehype plugins (remarkObsidianSupport, remarkExtractToc, remarkEnhanceLinks, remarkAi2htmlEmbed), generates JSON with complete metadata. Vue components consume JSON, never raw Markdown. Enables programmatic content analysis and sophisticated querying.

Multi-Source API Aggregation

Stats dashboard (server/api/stats.get.ts) integrates 10+ disparate APIs: GitHub, YouTube, LastFM, Chess.com, Goodreads, LeetCode, Letterboxd, MonkeyType, RescueTime, Umami. Caching layer prevents rate limit violations. Renders activity calendars (GitHub-style contribution graphs) and inline sparklines for each service. Transforms personal metrics into time-series visualizations.

Full-Text Search with TF-IDF

server/api/search.get.ts implements client-side searchable index with relevance scoring. Title matches weighted 10x, tags 5x, content 1x. No external search service (Algolia, etc.) - builds search capability directly into site architecture.

Commentary Template Generation

scripts/generate-commentary-templates.mjs parses Kalshi market tickers (KXOTEEPSTEIN, OAIAGI, etc.) and generates Markdown templates with pattern-based title suggestions. Pre-fills position details (side, quantity, exposure) from API data. Reduces friction for market documentation by automating template creation.

WebMentions Integration

server/api/webmentions.get.ts fetches inbound webmentions from webmention.io. Implements IndieWeb standards for decentralized social feedback. Shows who links to content without relying on centralized platforms.

Cal.com Availability Widget

server/api/cal/available-slots.get.ts provides real-time calendar integration showing next 3 available 30-minute slots. Formats in natural language ("9am Monday?"), generates direct booking URLs, implements 7-day lookahead with America/New_York timezone handling.

Maintenance Scripts

  • yarn blog:process - Process Markdown to JSON
  • yarn predict - Create cryptographic prediction
  • yarn kalshi:test - Fetch Kalshi portfolio
  • yarn kalshi:templates - Generate commentary templates
  • yarn kalshi:calibration - Run accuracy analysis
  • yarn build - Production build
  • yarn dev - Development server (port 3006)

Document History

This page serves as the authoritative technical reference for ejfox.com. Update when architecture changes, features are added/removed, or implementation details evolve. Maintain factual accuracy. Preserve historical context in deletions.