Skip to content

brainsnorkel/eso-build-o-rama

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

340 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESOBuild.com

Automated analysis and visualization of top-performing Elder Scrolls Online trial builds from ESO Logs.

Live Site: esobuild.com

Overview

ESO Build-O-Rama scans the top-ranked ESO Logs trial reports, identifies common builds among elite players, and generates static web pages showcasing these builds. Each trial is scanned independently on a staggered schedule to manage API load and ensure fresh data.

Build Classification

A build is featured if it appears frequently in the top 10 ranked logs for a specific boss:

  • DPS Builds: 5 or more occurrences
  • Tank/Healer Builds: 3 or more occurrences

Build Definition

A "build" consists of:

  1. Three Subclasses: Skill lines identified from ability usage patterns
  2. Two 5-Piece Gear Sets: The dominant armor/weapon sets

Features

Data Collection

  • Analyzes top 10 ESO Logs reports per boss encounter
  • Consolidates identical builds across multiple reports
  • Deduplicates same character appearing in multiple reports
  • Applies role-based occurrence thresholds
  • Extracts per-player mundus stones via source-filtered buff queries

Captured Build Data

  • Gear (all equipment pieces with traits and enchantments)
  • Abilities (both skill bars including ultimates)
  • Subclasses (detected from skill usage patterns)
  • Gear Sets (5-piece, 2-piece, and arena weapons)
  • Mundus Stones (from buff uptime data)
  • Performance metrics (DPS, rankings, report links)
  • Occurrence frequency across top logs

User Interface

  • Desktop: Full-width tables with sortable columns
  • Mobile: Card-based layout for screens ≤768px width
  • Responsive design with proper touch targets
  • Ability icons and visual set indicators
  • Direct links to source ESO Logs reports
  • Interactive Gear Tooltips: Hover over gear sets and mundus stones for detailed information
    • Powered by ESO-Hub's external tooltip system
    • Shows set bonuses, stats, and acquisition info
    • Works on all gear set names, mundus stones
    • Links open detailed ESO-Hub pages

Accessibility

  • WCAG 2.1 Level AA compliant for screen reader users
  • Skip-to-main-content link for keyboard navigation
  • ARIA landmarks and semantic HTML throughout
  • Proper table headers, captions, and scope attributes
  • Meaningful alt text for all images
  • High-contrast focus indicators for keyboard navigation
  • Accessible breadcrumb navigation
  • Screen reader text for visual indicators (role emojis)
  • See docs/accessibility.md for full details

Performance

  • Advanced Caching System: 95% cache effectiveness reduces API calls by 97%
    • Organized cache structure with subdirectories (buffs, tables, rankings, reports)
    • Persistent cache across runs (46+ MB cache with 1,500+ files)
    • Cache performance monitoring with hit/miss tracking
    • See docs/cache_system.md for full documentation
  • Incremental data storage between scans
  • Staggered trial scanning (one trial every hour)
  • Rate limit compliance (2-second delays, automatic retry)
  • Static HTML generation for fast page loads

Search Engine Optimization (SEO)

  • Comprehensive SEO Implementation for better search engine discoverability
    • Automatically generated sitemap.xml with all pages
    • robots.txt for crawler guidance
    • Structured data (Schema.org JSON-LD) on all pages
    • Canonical URLs to prevent duplicate content issues
    • Keyword-rich meta descriptions tailored to each page
    • BreadcrumbList schema for navigation context
    • HowTo schema on build pages for rich results
    • WebSite schema with Elder Scrolls Online context

Deployment

  • GitHub Actions for automated scanning
  • Staggered schedule (each trial updated every 14 hours)
  • GitHub Pages hosting with CDN distribution
  • Branch isolation (develop for testing, main for production)

Installation

Prerequisites

Setup

# Clone repository
git clone https://github.com/brainsnorkel/eso-build-o-rama.git
cd eso-build-o-rama

# Install dependencies
pip install -r requirements.txt

# Configure API credentials (add to shell profile)
export ESOLOGS_ID="your_client_id"
export ESOLOGS_SECRET="your_client_secret"
source ~/.zshrc  # or ~/.bashrc

Branch Structure

Main Branch (main):

  • Production code
  • Outputs to output/ directory
  • Triggers GitHub Actions on push
  • Deploys to esobuild.com

Development Branch (develop):

  • Feature development and testing
  • Outputs to output-dev/ directory (gitignored)
  • Does not trigger GitHub Actions
  • Safe for local testing

Usage

Scan Commands

# Scan all trials
python -m src.eso_build_o_rama.main

# Scan specific trial by ID
python -m src.eso_build_o_rama.main --trial-id 15  # Rockgrove

# Scan specific trial by name
python -m src.eso_build_o_rama.main --trial "Dreadsail Reef"

# Test mode (first trial only)
python -m src.eso_build_o_rama.main --test

Cache Management

# View cache statistics
python -m src.eso_build_o_rama.main --cache-stats

# Clear cache before scan
python -m src.eso_build_o_rama.main --trial-id 17 --clear-cache

# Disable caching (force API calls)
python -m src.eso_build_o_rama.main --trial-id 17 --no-cache

# Migrate existing cache files to new structure
python utils/migrate_cache.py --dry-run  # Preview changes
python utils/migrate_cache.py            # Perform migration

Note: See docs/cache_system.md for comprehensive cache documentation.

Manual Workflow Triggers

# Trigger specific trial
gh workflow run "Generate ESO Builds (Staggered)" -f trial_id=15

# Check status
gh run list --workflow="Generate ESO Builds (Staggered)" --limit 5

# View logs
gh run view <run_id> --log

Local Testing

# On develop branch
git checkout develop
python -m src.eso_build_o_rama.main --trial-id 1

# Serve locally
cd output-dev
python3 -m http.server 8080 &
ngrok http 8080

Trial Reference

ID Trial Name Abbr
1 Aetherian Archive AA
2 Hel Ra Citadel HRC
3 Sanctum Ophidia SO
5 Maw of Lorkhaj MoL
6 The Halls of Fabrication HoF
7 Asylum Sanctorium AS
8 Cloudrest CR
12 Sunspire SS
14 Kyne's Aegis KA
15 Rockgrove RG
16 Dreadsail Reef DSR
17 Sanity's Edge SE
18 Lucent Citadel LC
19 Ossein Cage OC

Architecture

System Overview

GitHub Actions (Staggered Schedule)
    |
    v
ESO Build-O-Rama Application
    |
    +-- API Client (GraphQL)
    +-- Data Parser (Gear, Abilities)
    +-- Build Analyzer (Consolidation)
    +-- Trial Scanner (Orchestration)
    +-- Cache Manager (Response Cache)
    +-- Data Store (builds.json)
    +-- Page Generator (HTML Templates)
    |
    v
GitHub Pages Deployment (esobuild.com)

Data Flow

  1. Fetch rankings from ESO Logs API
  2. Download top 10 reports per boss
  3. Parse gear, abilities, and performance data
  4. Detect subclasses from ability usage
  5. Identify gear sets from equipped items
  6. Query buff table for per-player mundus stones
  7. Consolidate identical builds across reports
  8. Apply role-based occurrence thresholds
  9. Save trial data to builds.json
  10. Generate HTML from templates
  11. Deploy to GitHub Pages

Key Algorithms

Build Identification:

# Normalize build for comparison
slug = sorted(subclasses) + sorted(top_two_sets)
slug = slug.lower().replace(' ', '-').replace("'", "")

Build Consolidation:

  • Group by (trial, boss, build_slug)
  • Merge all players with matching build
  • Count unique reports (not total players)
  • Select highest DPS as representative player
  • Preserve mundus from any instance of same character

Subclass Detection:

  • Count ability casts per skill line
  • Weight ultimates more heavily
  • Select top 3 skill lines by usage
  • Normalize to abbreviated names

API Integration

ESO Logs GraphQL API

Authentication: OAuth 2.0
API Version: v2

Primary Queries:

  • worldData.zones - Trial and encounter IDs
  • characterRankings(leaderboard: LogsOnly) - Top-ranked players per boss
  • reportData.report - Full report data
  • reportData.report.table(dataType: Summary) - Player performance and gear
  • reportData.report.table(dataType: Buffs, sourceID: X) - Per-player buff uptime

Rate Limiting:

  • API limit: 18,000 points/hour
  • Report queries: 5-10 points each
  • Request delay: 2 seconds minimum
  • Retry attempts: 3 with exponential backoff (120s, 240s, 360s)
  • Typical scan: ~200 points (well under limit)

Caching

  • Location: cache/ directory (gitignored, persistent)
  • Duration: Indefinite (manual clear only)
  • Effectiveness: 95-97% cache hit rate
  • Key Format: {type}_{parameters_hash}

Cache Types:

  • Zone/encounter data
  • Rankings
  • Report data
  • Player buffs

SEO Features

Sitemap Generation

Every build generation automatically creates sitemap.xml with:

  • All build pages, trial pages, and home page
  • Last modified dates
  • Change frequency hints for crawlers
  • Priority values (1.0 for home, 0.8 for trials, 0.6 for builds)

Robots.txt

Automatically generated robots.txt file:

  • Allows all search engine crawlers
  • Points to sitemap.xml location
  • Disallows crawling of cache directory

Structured Data

JSON-LD structured data on all pages:

  • Home page: WebSite schema with Elder Scrolls Online context
  • Trial pages: BreadcrumbList for navigation hierarchy
  • Build pages: HowTo schema with gear supplies and ability steps, plus BreadcrumbList

Meta Tags

Comprehensive meta tags on every page:

  • Unique, keyword-rich meta descriptions
  • Keywords meta tag with relevant ESO search terms
  • Canonical URLs to prevent duplicate content
  • Open Graph and Twitter Card tags for social sharing

Submitting to Search Engines

After deploying to production:

Google Search Console:

  1. Visit Google Search Console
  2. Add property: esobuild.com
  3. Verify ownership (DNS TXT record or HTML file)
  4. Submit sitemap: https://esobuild.com/sitemap.xml
  5. Monitor index coverage and search performance

Bing Webmaster Tools:

  1. Visit Bing Webmaster Tools
  2. Add site: esobuild.com
  3. Verify ownership
  4. Submit sitemap: https://esobuild.com/sitemap.xml

Validation Tools:

Page Generation

Templates (Jinja2)

  • base.html - Base template with header, footer, responsive CSS, structured data
  • index_page.html - Home page listing all trials and builds
  • trial.html - Per-trial page with boss-grouped builds
  • build_page.html - Detailed build page

Responsive Breakpoints

  • Desktop (≥1024px): Full tables, all columns visible
  • Tablet (769-1023px): Tables with reduced padding
  • Mobile (≤768px): Card-based layout with labeled fields

Mobile Table Transformation

Tables convert to vertical cards on mobile:

  • Each row becomes a standalone card
  • Labels appear on left (40% width)
  • Data appears on right (60% width)
  • Touch-friendly links with padding
  • No horizontal scrolling required

GitHub Actions

Schedule

Workflow runs every hour, cycling through 14 trials. Each trial updates approximately every 14 hours.

Reference time: 20:00 UTC (8:00 PM UTC)

Index 0  (20:00 UTC) → Aetherian Archive
Index 1  (21:00 UTC) → Hel Ra Citadel
Index 2  (22:00 UTC) → Sanctum Ophidia
Index 3  (23:00 UTC) → Maw of Lorkhaj
Index 4  (00:00 UTC) → Halls of Fabrication
Index 5  (01:00 UTC) → Asylum Sanctorium
Index 6  (02:00 UTC) → Cloudrest
Index 7  (03:00 UTC) → Sunspire
Index 8  (04:00 UTC) → Kyne's Aegis
Index 9  (05:00 UTC) → Rockgrove
Index 10 (06:00 UTC) → Dreadsail Reef
Index 11 (07:00 UTC) → Sanity's Edge
Index 12 (08:00 UTC) → Lucent Citadel
Index 13 (09:00 UTC) → Ossein Cage

Triggers

  1. Schedule: 0 * * * * (every hour at :00)
  2. Manual: Workflow dispatch with optional trial_id parameter
  3. Push: Main branch only (develop branch excluded)

Workflow Steps

  1. Determine which trial to scan based on current time
  2. Checkout latest code from main branch
  3. Install Python 3.9 and dependencies
  4. Download existing builds.json from live site
  5. Run scan for determined trial
  6. Copy static assets
  7. Upload artifact to GitHub Pages
  8. Deploy

Branch Protection

Develop branch is prevented from deploying:

  • Workflow triggers only on main branch
  • Code checks for develop branch in GitHub Actions environment
  • Exits with error if develop detected in CI/CD

Data Models

PlayerBuild

Individual player's build in a specific fight.

Fields:

  • Character and account names
  • Player ID (API source ID)
  • Class and role
  • DPS and performance metrics
  • Gear with traits and enchantments
  • Abilities (two skill bars)
  • Subclasses (detected from abilities)
  • Equipped sets
  • Mundus stone
  • Report and fight references

CommonBuild

Build appearing multiple times across reports.

Fields:

  • Build slug (normalized identifier)
  • Subclasses and gear sets
  • Count (total players)
  • Report count (unique reports)
  • Best player (highest DPS)
  • All players list
  • Trial and boss information

Methods:

  • get_display_name() - Human-readable name with sorted subclasses
  • get_sorted_sets() - Alphabetically sorted set list
  • meets_threshold() - Role-based occurrence check

GearPiece

Individual equipment piece.

Fields:

  • Slot identifier
  • Set name
  • Item name
  • Armor weight (L/M/H)
  • Trait and trait ID
  • Enchantment and enchant ID
  • Item ID and quality

Mundus Stone Detection

Mundus stones are identified through buff analysis:

  1. Query Buffs table filtered by player's source_id
  2. Match buff ability IDs against known mundus IDs (13940-13985)
  3. Verify high uptime (mundus buffs persist throughout fight)
  4. Map ability ID to mundus name

Mundus Ability IDs:

13940: The Warrior
13943: The Mage
13974: The Serpent
13975: The Thief
13976: The Lady
13977: The Steed
13978: The Lord
13979: The Apprentice
13980: The Ritual
13981: The Lover
13982: The Atronach
13984: The Shadow
13985: The Tower

Project Structure

eso-build-o-rama/
├── .github/workflows/
│   └── generate-builds.yml          # CI/CD workflow
├── cache/                            # API response cache (gitignored)
├── data/
│   ├── trials.json                   # Trial definitions
│   └── trial_bosses.json             # Boss lists per trial
├── docs/                             # Additional documentation
├── output/                           # Production output (main)
│   └── builds.json                   # Persistent data (tracked)
├── output-dev/                       # Development output (gitignored)
├── src/eso_build_o_rama/
│   ├── main.py                       # Application orchestrator
│   ├── api_client.py                 # ESO Logs API client
│   ├── trial_scanner.py              # Scan orchestration
│   ├── data_parser.py                # Parse API responses
│   ├── build_analyzer.py             # Build identification
│   ├── subclass_analyzer.py          # Skill line detection
│   ├── page_generator.py             # HTML generation
│   ├── data_store.py                 # JSON persistence
│   ├── cache_manager.py              # Response caching
│   └── models.py                     # Data structures
├── static/icons/                     # Ability icons
├── templates/                        # Jinja2 templates
├── tests/                            # Test suite
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
└── requirements.txt

Configuration

Environment Variables

Required for API access:

export ESOLOGS_ID="your_client_id"
export ESOLOGS_SECRET="your_client_secret"

Configuration Files

data/trials.json
List of trials with IDs, names, and abbreviations.

data/trial_bosses.json
Maps trial names to boss encounters in encounter order.

.github/workflows/generate-builds.yml
GitHub Actions workflow configuration with scheduling, triggers, and deployment steps.

Development Workflow

Making Changes

# Switch to develop branch
git checkout develop

# Make changes and test locally
python -m src.eso_build_o_rama.main --trial-id 1

# Verify output in output-dev/
ls output-dev/

# Commit changes
git add .
git commit -m "description"
git push origin develop

# Test with local server
cd output-dev
python3 -m http.server 8080 &

# When ready, merge to main
git checkout main
git merge develop
git push origin main

Output Directories

Branch Output Dir Git Tracked Deployed
main output/ builds.json only Yes (GitHub Pages)
develop output-dev/ No (gitignored) No

Testing Checklist

  • Test on develop branch first
  • Verify correct output directory
  • Check logs for errors
  • Test responsive layout (browser dev tools)
  • Verify desktop layout unchanged
  • Confirm data accuracy
  • Review builds.json structure
  • Merge to main when stable

Troubleshooting

No Publishable Builds Found

This is expected for older trials with diverse meta. Top players in trials like Sanctum Ophidia or Hel Ra Citadel may use varied builds that don't meet the 5+/3+ threshold. These trials won't appear on the index page.

Mundus Showing Unknown

Indicates player had no mundus active during the fight or data parsing issue. Verify on ESO Logs directly and check application logs.

Rate Limit Errors

Solutions:

  • Increase min_request_delay in APIClient (default: 2.0s)
  • Avoid --clear-cache unless necessary
  • Wait 2-3 minutes between manual workflow triggers
  • Automated schedule handles this automatically

GitHub Actions Race Conditions

When triggering multiple workflows manually, wait 2-3 minutes between them. Each workflow downloads builds.json from the live site. If workflows overlap, the later one may download stale data before the earlier deployment completes.

Template Changes Not Appearing

CDN caching on esobuild.com has 10-minute TTL (max-age=600). To see changes immediately:

  • Hard refresh browser (Cmd/Ctrl + Shift + R)
  • Wait 10 minutes for cache expiration
  • Check deployment completed successfully

Performance Metrics

Typical Trial Scan:

  • API calls: 10-15 new requests, 300+ cached
  • Duration: 5-12 minutes per trial
  • Data volume: 100-500KB per trial
  • Page generation: Under 1 second

Resource Usage:

  • API points: ~200 per scan (1% of hourly limit)
  • Storage: ~5MB per trial in builds.json
  • Cache size: Varies, typically 50-200MB

API Details

Request Rate Limiting

async def _retry_on_rate_limit(self, func, *args, **kwargs):
    for attempt in range(self.max_retries):
        await self._wait_for_rate_limit()  # 2s minimum
        try:
            return await func(*args, **kwargs)
        except RateLimitError:
            delay = self.retry_delay * (2 ** attempt)  # 120s, 240s, 360s
            await asyncio.sleep(delay)

GraphQL Query Examples

Fetch Top Rankings:

query GetRankings($zoneID: Int!, $encounterID: Int!) {
  characterRankings(
    zoneID: $zoneID
    encounterID: $encounterID
    leaderboard: LogsOnly
  )
}

Fetch Player Buffs:

query GetBuffs($code: String!, $startTime: Float!, $endTime: Float!, $sourceID: Int!) {
  reportData {
    report(code: $code) {
      table(
        startTime: $startTime
        endTime: $endTime
        dataType: Buffs
        sourceID: $sourceID
      )
    }
  }
}

Contributing

Code Standards

  • Type hints on all function signatures
  • Docstrings for all public methods
  • Logging at appropriate levels (INFO, WARNING, ERROR, DEBUG)
  • Specific exception handling (KeyError, ValueError, TypeError)
  • Async/await for all API operations

Commit Message Format

type: Brief description

Longer explanation if needed.

CHANGES:
- Specific change 1
- Specific change 2

RESULT:
- Outcome or effect

Types: feat, fix, docs, refactor, test, chore

Recent Updates

2025-10-06

Per-Player Mundus Detection
Fixed incorrect mundus stones by implementing source_id filtering in Buffs table queries.

Mobile Responsiveness
Added responsive CSS that converts tables to card layout on screens ≤768px.

UI Improvements

  • Sorted subclasses alphabetically
  • Updated page title to "BS ESO Meta Build Explorer"
  • Accurate "About This Data" section
  • Static generation timestamps
  • Improved terminology

Development Environment

  • Branch-based output directories
  • GitHub Actions filtering (main only)
  • Safety checks for develop branch
  • output-dev/ gitignored

Build Consolidation

  • Merge identical builds across reports
  • Count unique reports
  • Prevent duplicate players

See CHANGELOG.md for complete history.

Credits

This project uses data and resources from:

License

MIT License - see LICENSE file for details.

Copyright 2025 Chris Gentle (@brainsnorkel)

This is a fan-made tool for the Elder Scrolls Online community. The Elder Scrolls Online and all related content are Copyright ZeniMax Media Inc. This project is not affiliated with or endorsed by ZeniMax Media Inc.

Support

Report issues or request features: GitHub Issues

About

A weekly scan of ESOLogs to publish new top-performing trial builds

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages