Skip to content

Architecture.md

RoTSL edited this page Feb 14, 2026 · 1 revision

Architecture

Technical deep-dive into Wisp's design and implementation.

🏛️ System Overview

┌─────────────────────────────────────┐
│           Input Sources             │
│  (Files, URLs, Raw HTML)            │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│    Wisp Scanner (Python/JS)         │
│    • Content Density Analysis       │
│    • Pattern Recognition            │
│    • Context Classification         │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│    CSS Generator                    │
│    • Design Token Generation        │
│    • Variable Injection             │
└──────────────┬──────────────────────┘
               │
┌──────────────▼──────────────────────┐
│    Output (CSS/HTML)                │
│    • Static Files                   │
│    • Runtime Enhanced               │
└─────────────────────────────────────┘

🔍 Content Analysis Algorithm

Density Calculation (ρ)

Measures text-to-element ratio:

ρ = min((text_length / element_count) / 500, 1.0)

Where:

  • text_length: Total characters of text content
  • element_count: Number of DOM elements
  • 500: Calibrated maximum density constant

Interpretation:

  • ρ > 0.7: High density (compact content)
  • 0.3 < ρ ≤ 0.7: Medium density (balanced)
  • ρ ≤ 0.3: Low density (sparse content)

Pattern Recognition (π)

Classifies content by element distribution:

ratios = {
    'prose': paragraphs / total,
    'navigational': headings / total,
    'structured': lists / total,
    'technical': code_blocks / total
}
π = max(ratios, key=ratios.get)

Context Detection

Determines presentation archetype:

if tables or cards > 3:
    context = 'dashboard'
elif form_inputs >= 2:
    context = 'form'
elif pattern == 'prose':
    context = 'narrative'
else:
    context = 'minimal'

🎨 Styling System

CSS Custom Properties

Wisp generates design tokens as CSS variables:

:root {
  --wisp-context: narrative;
  --wisp-density: 0.45;
  --wisp-spacing-unit: 1rem;
  --wisp-line-height: 1.7;
  --wisp-max-width: 65ch;
  --wisp-base-font: 1.125rem;
  --wisp-motion: 200ms;
}

Context-Specific Values

Context Line Height Max Width Font Size Spacing
narrative 1.7 65ch 1.125rem 1.0rem
dashboard 1.4 100% 0.875rem 0.5rem
form 1.5 60ch 1.0rem 1.0rem
minimal 1.6 70ch 1.0rem 1.0rem

🗂️ Module Structure

Python Modules

src/core/scanner.py

  • WispScanner: Main analysis class
  • ContentAnalysis: Named tuple for results
  • analyze_content_density(): Density calculation
  • detect_reading_pattern(): Pattern classification
  • detect_context(): Context determination

src/core/fetcher.py

  • WispFetcher: URL fetching and processing
  • fetch(): HTTP retrieval with sanitization
  • extract_content(): Main content extraction
  • generate_html(): Standalone HTML output

src/cli/bake.py

  • CLI entry point for static generation
  • Arguments: input, output, forced_context

scripts/build.py

  • Build automation
  • Minification (optional)
  • Size reporting

scripts/generate_dashboard.py

  • HTML dashboard generation
  • Visualization of analysis results

JavaScript Runtime

src/core/wisp.js

  • Browser-side analysis
  • DOM API integration
  • Dynamic style injection
  • Accessibility enhancements

🔐 Security Architecture

HTML Sanitization

The fetcher removes potentially dangerous content:

removable_tags = ['script', 'iframe', 'nav', 'footer', 'header', 
                  'aside', 'noscript', 'svg']
removable_attrs = ['onclick', 'onload', 'onerror', 'style']

Content Security Policy

Generated HTML includes:

<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               style-src 'unsafe-inline';">

⚡ Performance Optimization

Algorithm Complexity

  • Time Complexity: O(n) where n = DOM node count
  • Space Complexity: O(1) for analysis, O(k) for CSS generation (k = constant)

Caching Strategy

No caching required due to speed:

  • Single analysis: <1ms
  • CSS generation: <0.5ms
  • Total overhead: <2ms per page

Bundle Size Budget

Component Size Gzipped
wisp.css 2.4KB ~1.0KB
wisp.js 4.3KB ~1.8KB
Total 6.7KB ~2.8KB
wisp.min.css 1.9KB ~0.8KB
wisp.min.js 2.4KB ~1.0KB
Total Min 4.3KB ~1.8KB

🌐 Browser Compatibility

Feature Detection

if (matchMedia('(prefers-reduced-motion: reduce)').matches) {
    // Disable animations
}

if (matchMedia('(prefers-color-scheme: dark)').matches) {
    // Use dark theme
}

Fallback Strategy

No JavaScript: Base CSS provides full styling No CSS Variables: Graceful degradation to defaults Old Browsers: Semantic HTML remains accessible

🔄 Data Flow

Static Generation (Python)

  1. Parse HTML with BeautifulSoup
  2. Calculate metrics (density, pattern, depth)
  3. Determine context
  4. Generate CSS variables
  5. Inject into template
  6. Write output file

Runtime Enhancement (JS)

  1. Wait for DOMContentLoaded
  2. Scan body element
  3. Calculate metrics
  4. Inject CSS variables
  5. Add accessibility enhancements
  6. Set data-wisp-active attribute

🧪 Testing Architecture

Unit Tests

  • test_narrative_detection: Verifies prose classification
  • test_dashboard_detection: Tests card/table detection
  • test_form_detection: Validates input counting
  • test_css_generation: Checks output format
  • test_density_calculation: Mathematical accuracy

Integration Tests

  • Fixture-based HTML testing
  • Live URL fetching (network)
  • End-to-end CLI testing

📊 Monitoring & Observability

Analysis Output

Every run produces:

  • Context classification
  • Confidence metrics
  • Performance timing
  • Generated CSS variables

Dashboard Visualization

Interactive charts showing:

  • Context distribution
  • Density histograms
  • Performance benchmarks
  • File size metrics