Website
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:
- Markdown files written in Obsidian vault
scripts/processMarkdown.mjsconverts MD to structured JSON- Individual JSON files stored in
content/processed/ manifest-lite.jsongenerated for listings- 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/*.mdfor 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:
.proseclass with zinc color scheme, custom paragraph spacing - Image-in-paragraph fix:
.prose p imgexceptions 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 JSONyarn predict- Create cryptographic predictionyarn kalshi:test- Fetch Kalshi portfolioyarn kalshi:templates- Generate commentary templatesyarn kalshi:calibration- Run accuracy analysisyarn build- Production buildyarn 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.