Skip to content
View DROOdotFOO's full-sized avatar
🏗️
Building
🏗️
Building

Organizations

@axol-io

Block or report DROOdotFOO

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
droodotfoo/README.md

DROO.FOO

Personal website built with LiveView, generative art patterns and monospace web aesthetics.

Test Coverage Tests Elixir Phoenix

Live: DROO.FOO

Features

Core Portfolio & Blog

  • Monospace Web Design: Character-perfect grid using 1ch units and rem-based line-height
  • Blog System: File-based markdown posts with YAML frontmatter and series support
  • Generative Patterns: Unique SVG patterns per post with 8 animation styles
  • Real-time Updates: Phoenix LiveView for instant page updates
  • Projects Showcase: GitHub integration with stats and contribution visualization
  • Resume System: Structured JSON-based resume with filtering and search
  • SEO Optimized: JSON-LD structured data for enhanced search engine visibility

Integrations

  • Web3 Wallet: Connect MetaMask for wallet authentication, ENS resolution, NFT/token viewing
  • Spotify Player: OAuth integration with playback controls, playlist browsing, and real-time progress
  • GitHub Stats: Repository visualization and contribution graphs
  • STL Viewer: 3D model viewer with Three.js integration

Quick Start

Local Development with 1Password CLI

# Install dependencies
mix setup

# Install 1Password CLI
# Install the desktop app
# https://1password.com/downloads
# https://developer.1password.com/docs/cli/app-integration/
brew install --cask 1password-cli

# Sign in to 1Password
op signin

# Create secrets in 1Password.
op item create --category=login --title="droodotfoo-dev" \
  SPOTIFY_CLIENT_ID="your_client_id" \
  SPOTIFY_CLIENT_SECRET="your_client_secret"

# Start server with secrets loaded from 1Password
./bin/dev

# After changes re-deploy with:
# 1. Deploy updated assets to CDN
./scripts/deploy-cdn.sh
# 2. Deploy Phoenix app to Fly.io
fly deploy

Alternative: Manual Environment Variables

# Set Spotify credentials (optional)
export SPOTIFY_CLIENT_ID="your_client_id"
export SPOTIFY_CLIENT_SECRET="your_client_secret"

# Start server
mix phx.server

Visit localhost:4000

Monospace Web Design

The site implements Wickström's monospace web technique for character-perfect grid alignment:

Horizontal Grid (1ch units):

  • Each character occupies exactly 1ch width
  • Container widths snap to character boundaries: calc(round(down, 80ch, 1ch))
  • Table columns use character-based widths (8ch, 12ch, 20ch, etc.)

Vertical Grid (rem-based line-height):

  • Fixed --line-height: 1.5rem for predictable calculations
  • Prevents line-height compounding in nested elements
  • Scales proportionally: 24px at 16px base, 21px at 14px mobile

Visual Refinements:

  • Double-line horizontal rules with layered pseudo-elements
  • Precision table padding compensates for border thickness
  • Media element grid alignment (images/videos snap to line-height)
  • All spacing uses multiples of 1ch or line-height

Benefits:

  • Zero layout shift (every character positioned exactly)
  • Maintainable vertical rhythm throughout content
  • Professional terminal-inspired aesthetic
  • Consistent across all themes and screen sizes

See wickstrom.tech for the original technique.

Architecture

Built with modular Phoenix LiveView architecture:

Monospace Web Design: Character-perfect grid using Wickstrom's monospace web technique with 1ch horizontal units and rem-based line-height for predictable vertical rhythm. Double-line dividers, precision table padding, and media element grid alignment maintain visual consistency.

Rendering: Phoenix LiveView handles real-time updates over WebSockets.

State Management: GenServers orchestrate content loading and GitHub API integration. Functional patterns with immutable state throughout.

Performance: ETS caching for GitHub API data, blog post metadata, and SVG patterns. Pattern cache provides 568x speedup (26ms -> 47us). Brotli compression for static assets. Page loads under 200ms.

Content System: File-based blog posts with markdown + YAML frontmatter. Deterministic SVG pattern generation per post with 8 animation styles. PostgreSQL with pgvector for wiki subsystem.

Test Coverage: 667 tests passing (22.7% code coverage)

Tech Stack

  • Backend: Elixir 1.17+, Phoenix 1.8.1, LiveView 1.1.12, Bandit web server
  • Styling: Tailwind CSS v4, Monaspace fonts (woff2 format with preload optimization)
  • Monospace Grid: 1ch units + rem-based line-height for character-perfect alignment
  • Frontend: TypeScript, esbuild for bundling, lazy-loaded hooks
  • Content: MDEx for markdown parsing with syntax highlighting
  • Caching: ETS for GitHub API, posts, patterns (568x speedup for patterns)
  • Compression: Brotli for static assets (JS, CSS, SVG, fonts)
  • SEO: JSON-LD structured data for enhanced search visibility
  • Rust NIFs: ex_keccak, ex_secp256k1 (Web3 crypto), autumn, mdex (compiled from source)
  • Optional: ethers.js (Web3), Three.js (STL viewer)
  • Testing: ExUnit with 667 tests passing

Development

# Run tests
mix test

# Run specific test file
mix test test/droodotfoo/raxol_app_test.exs

# Format code
mix format

# Compile with warnings
mix compile --warning-as-errors

# Full precommit check (compile, deps, format, test)
mix precommit

# Generate ExDoc documentation
mix docs

Deployment

Fly.io Production Deployment

# Install Fly CLI
brew install flyctl

# Login to Fly.io
fly auth login

# Create fly.toml and guides through setup
# Fly.io will handle the routing from external ports (80/443) to your app's internal port 8080 (default)
# Even though our config/runtime.exs specifies port 4000
fly launch
# Or if you want to create the app manually:
fly apps create droodotfoo

# Set production secrets (required)
# once successfully set with fly secrets set, they're stored encrypted in Fly.io's infra
# and injected into your app as environment variables at runtime
fly secrets set \
  SECRET_KEY_BASE=$(mix phx.gen.secret) \
  PHX_HOST="droodotfoo.fly.dev"

# Set blog API token (required for Obsidian publishing)
fly secrets set BLOG_API_TOKEN=$(mix phx.gen.secret)

# Optional: Spotify integration
# obtain secrets from https://developer.spotify.com/dashboard
fly secrets set \
  SPOTIFY_CLIENT_ID="prod_client_id" \
  SPOTIFY_CLIENT_SECRET="prod_client_secret"

# Then register https://droo.foo/auth/spotify/callback in Spotify Dashboard
# https://developer.spotify.com/dashboard
# add redirect URI and the website link (i.e. `PHX_HOST`)
SPOTIFY_REDIRECT_URI="https://your-app.fly.dev/auth/spotify/callback"

# Optional: GitHub API token for higher rate limits (5000/hr vs 60/hr)
fly secrets set GITHUB_TOKEN="ghp_xxxxx"

# Optional: Configure Cloudflare Pages CDN for static assets
fly secrets set CDN_HOST="your-project.pages.dev"

# Deploy
fly deploy

Rust NIF Compilation

The Dockerfile compiles Rust NIFs from source because GitHub release assets are often blocked from CI builders. If deployment fails with NIF download errors, ensure these env vars are set in the Dockerfile:

ENV EX_KECCAK_BUILD="1"
ENV RUSTLER_BUILD="1"
ENV AUTUMN_BUILD="1"
ENV MDEX_BUILD="1"

Environment Variables

See docs/guides/deployment.md for complete environment variable reference.

Required: SECRET_KEY_BASE, PHX_HOST, BLOG_API_TOKEN

Optional: SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, GITHUB_TOKEN, CDN_HOST

Security

See docs/guides/security.md for comprehensive security documentation.

Key Features:

  • OAuth 2.0 for Spotify, Bearer token for Blog API
  • Rate limiting on all public endpoints
  • Input validation with path traversal prevention
  • HTTPS enforcement, CSP headers, secure cookies

Documentation

Project Documentation

  • CLAUDE.md - Project overview, patterns, and AI assistant context
  • AGENTS.md - Phoenix/Elixir development guidelines

Guides (docs/)

API Documentation (ExDoc)

Generate comprehensive documentation with typespecs:

# Generate HTML documentation
mix docs

# View in browser
open doc/index.html

Includes:

  • Module documentation with examples
  • Function signatures with @spec annotations
  • Type definitions and behaviors
  • Searchable interface

Pinned Loading

  1. awesome-web3-data awesome-web3-data Public

    Awesome lists of web3 data resources

    INI 17 12

  2. raxol raxol Public

    Terminal built for your Gundam. OTP-native TUI framework for Elixir - same app in terminal, browser (LiveView), or SSH. AI agents, distributed swarm, time-travel debugging.

    Elixir 39 3

  3. mona.nvim mona.nvim Public

    Complete Monaspace font toolkit for Neovim - install, configure, and mix fonts with ease

    Lua 9

  4. libsignal-protocol-nif libsignal-protocol-nif Public

    Cross-platform BEAM (Erlang/Elixir/Gleam) implementations of the Signal Protocol

    C 12 3

  5. dotfiles dotfiles Public template

    Managed with chezmoi - cross-platform dotfiles with conditional tool lazy loading

    Shell 3

  6. phos phos Public

    Light for your logs. GRC replacement written in Rust.

    Rust 4