<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>cargo-coupling Visualization</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="stylesheet" href="/css/style.css">
<script src="https://unpkg.com/cytoscape@3.28.1/dist/cytoscape.min.js"></script>
<script src="https://unpkg.com/dagre@0.8.5/dist/dagre.min.js"></script>
<script src="https://unpkg.com/cytoscape-dagre@2.5.0/cytoscape-dagre.js"></script>
<script src="https://unpkg.com/3d-force-graph"></script>
<script src="https://unpkg.com/marked@12.0.2/marked.min.js"></script>
</head>
<body>
<div class="header-trigger" id="header-trigger"></div>
<div class="footer-trigger" id="footer-trigger"></div>
<button class="sidebar-toggle" id="sidebar-toggle" title="Toggle sidebar (s)" aria-label="Toggle sidebar">
<span class="icon">◀</span>
</button>
<div class="container">
<header class="header" id="header">
<div class="header-left">
<h1>🔗 cargo-coupling</h1>
</div>
<div class="header-stats" id="header-stats">
<span class="stat">Loading...</span>
</div>
<div class="header-right">
<button id="lang-toggle" class="btn btn-lang" title="Switch language" aria-label="Switch language">
<span id="lang-label">EN</span>
</button>
</div>
</header>
<main class="main">
<div class="canvas-toolbar" aria-label="Canvas view controls">
<div class="segmented-control">
<button id="canvas-view-2d" class="segment active" type="button" data-i18n="view_2d_graph">2D Graph</button>
<button id="canvas-view-3d" class="segment" type="button" data-i18n="view_3d_graph">3D Graph</button>
<button id="canvas-view-space" class="segment" type="button" data-i18n="view_dimension_space">Dimension-Space</button>
<button id="canvas-view-report" class="segment" type="button" data-i18n="view_report">Report</button>
</div>
<button id="canvas-legend-toggle" class="canvas-tool-btn" type="button" data-i18n="legend" aria-label="Open legend">Legend</button>
</div>
<div class="app-loading" id="app-loading" role="status" aria-live="polite" aria-label="Loading coupling graph">
<div class="loading-panel">
<span class="loading-spinner" aria-hidden="true"></span>
<div>
<strong>Loading analysis</strong>
<span>Preparing graph, history, and report data...</span>
</div>
</div>
<div class="loading-skeleton" aria-hidden="true">
<span></span>
<span></span>
<span></span>
</div>
</div>
<div class="graph-container" id="cy"></div>
<div class="graph-container graph-3d-container" id="graph-3d" style="display: none;"></div>
<div class="dimension-space-labels" id="dimension-space-labels" style="display: none;">
<span class="axis-label axis-x" data-i18n="axis_integration_strength">X: Integration Strength</span>
<span class="axis-label axis-y" data-i18n="axis_distance">Y: Distance</span>
<span class="axis-label axis-z" data-i18n="axis_volatility">Z: Volatility</span>
</div>
<div class="tree-container" id="tree-view" style="display: none;"></div>
<section class="report-view" id="report-view" style="display: none;" aria-label="Markdown report">
<div class="report-shell">
<nav class="report-toc" aria-label="Report sections">
<div class="report-toc-title" data-i18n="contents">Contents</div>
<div class="report-toc-list" id="report-toc-list"></div>
</nav>
<article class="report-panel">
<div class="report-meta">
<span id="report-status" data-i18n="report_not_loaded">Report not loaded</span>
</div>
<div class="report-content" id="report-content">
<p class="placeholder" data-i18n="loading_report">Loading report...</p>
</div>
</article>
</div>
</section>
</main>
<aside class="sidebar" id="sidebar">
<div id="sidebar-resizer" class="resize-handle"></div>
<section class="panel">
<h2>Jobs</h2>
<div class="job-buttons">
<button id="job-entry-points" class="btn btn-job" title="Where should I start reading?">
🚀 Entry Points
</button>
<button id="job-path-finder" class="btn btn-job" title="How does A connect to B?">
🔍 Find Path
</button>
<button id="job-simple-view" class="btn btn-job" title="Show simplified architecture">
📊 Simple View
</button>
<button id="job-what-breaks" class="btn btn-job" title="What might break if I change this?" disabled>
⚠️ What Breaks?
</button>
</div>
<div id="job-result" class="job-result"></div>
</section>
<section class="panel" id="path-finder-panel" style="display: none;">
<h2>Path Finder</h2>
<div class="path-finder-inputs">
<select id="path-from" class="select">
<option value="">From module...</option>
</select>
<span style="color: var(--text-secondary);">→</span>
<select id="path-to" class="select">
<option value="">To module...</option>
</select>
</div>
<button id="find-path-btn" class="btn" style="width: 100%; margin-top: 0.5rem;">
Find Dependency Path
</button>
<div id="path-result" class="path-result"></div>
</section>
<section class="panel">
<h2>Search</h2>
<input type="text" id="search-input" class="search-input" placeholder="Search modules... (press /)">
</section>
<section class="panel timeline-panel" id="timeline-panel">
<div class="timeline-header">
<h2>Timeline</h2>
<button id="timeline-play" class="btn timeline-play-btn" disabled>Play</button>
</div>
<div id="timeline-chart" class="timeline-chart">
<p class="placeholder">Loading history...</p>
</div>
<input type="range" id="timeline-scrubber" class="timeline-scrubber" min="0" max="0" value="0" disabled>
<div id="timeline-graph-status" class="timeline-graph-status">Scrub to load a revision graph</div>
<div class="timeline-stats" id="timeline-stats">
<div class="timeline-stat">
<span>Date</span>
<strong id="timeline-date">-</strong>
</div>
<div class="timeline-stat">
<span>Commit</span>
<strong id="timeline-commit">-</strong>
</div>
<div class="timeline-stat">
<span>Grade</span>
<strong id="timeline-grade" class="health-grade">-</strong>
</div>
<div class="timeline-stat">
<span>Avg Score</span>
<strong id="timeline-score">-</strong>
</div>
<div class="timeline-stat">
<span>Couplings</span>
<strong id="timeline-couplings">-</strong>
</div>
<div class="timeline-stat">
<span>Critical</span>
<strong id="timeline-critical">-</strong>
</div>
</div>
</section>
<section class="panel">
<h2>View</h2>
<div class="view-buttons">
<button id="view-graph" class="btn btn-view active">Graph</button>
<button id="view-tree" class="btn btn-view">Tree</button>
</div>
<div class="view-buttons projection-buttons" style="margin-top: 0.5rem;">
<button id="projection-2d" class="btn btn-view active">2D</button>
<button id="projection-3d" class="btn btn-view">3D</button>
</div>
<div class="view-buttons projection-buttons" id="graph-3d-mode-buttons" style="display: none; margin-top: 0.5rem;">
<button id="mode-3d-network" class="btn btn-view active">Network</button>
<button id="mode-3d-space" class="btn btn-view">Dimension Space</button>
</div>
<div class="filter-group" style="margin-top: 0.5rem;">
<label><input type="checkbox" id="center-mode-toggle"> Center on Click</label>
<p style="font-size: 0.6875rem; color: var(--text-secondary); margin-top: 0.25rem;">
Re-layout graph with selected node at center
</p>
</div>
<div class="filter-group" style="margin-top: 0.5rem;">
<label><input type="checkbox" id="show-items-toggle"> Show Items (fn/type)</label>
<p style="font-size: 0.6875rem; color: var(--text-secondary); margin-top: 0.25rem;">
Show function and type nodes in graph
</p>
</div>
</section>
<section class="panel" id="layout-panel">
<h2>Layout</h2>
<select id="layout-select" class="select">
<option value="cose">Force-directed</option>
<option value="dagre">Hierarchy</option>
<option value="concentric">Concentric</option>
<option value="grid">Grid</option>
</select>
</section>
<section class="panel">
<h2>Filters</h2>
<div class="filter-group">
<label>Strength</label>
<div class="checkbox-group" id="strength-filters">
<label><input type="checkbox" value="Intrusive" checked> Intrusive</label>
<label><input type="checkbox" value="Functional" checked> Functional</label>
<label><input type="checkbox" value="Model" checked> Model</label>
<label><input type="checkbox" value="Contract" checked> Contract</label>
</div>
</div>
<div class="filter-group">
<label>Distance</label>
<div class="checkbox-group" id="distance-filters">
<label><input type="checkbox" value="SameFunction" checked> Same Function</label>
<label><input type="checkbox" value="SameModule" checked> Same Module</label>
<label><input type="checkbox" value="DifferentModule" checked> Different Module</label>
<label><input type="checkbox" value="DifferentCrate"> External Crate</label>
</div>
</div>
<div class="filter-group">
<label>Volatility</label>
<div class="checkbox-group" id="volatility-filters">
<label><input type="checkbox" value="Low" checked> Low</label>
<label><input type="checkbox" value="Medium" checked> Medium</label>
<label><input type="checkbox" value="High" checked> High</label>
</div>
</div>
<div class="filter-group">
<label>Balance Score: <span id="balance-value">0.0 - 1.0</span></label>
<div class="range-slider">
<input type="range" id="balance-min" min="0" max="100" value="0">
<input type="range" id="balance-max" min="0" max="100" value="100">
</div>
</div>
<div class="filter-group">
<label><input type="checkbox" id="show-issues-only"> Show Issues Only</label>
<label><input type="checkbox" id="show-cycles-only"> Show Cycles Only</label>
<label><input type="checkbox" id="show-hidden-coupling" checked> Show Hidden Coupling</label>
<label><input type="checkbox" id="hide-external" checked> Hide External Crates</label>
</div>
<div class="filter-actions">
<button id="reset-filters" class="btn">Reset Filters</button>
<button id="fit-graph" class="btn">Fit to Screen</button>
</div>
</section>
<section class="panel legend-panel">
<h2><span data-i18n="legend">Legend</span> <button id="toggle-legend" class="btn-toggle">[?]</button></h2>
<div id="legend-content" style="display: none;">
<div class="legend-section">
<h4 data-i18n="legend_edge_colors">Edge Colors (Coupling Balance)</h4>
<div class="legend-items">
<div class="legend-item">
<span class="legend-color" style="background: var(--quadrant-high-cohesion);"></span>
<span class="legend-label" data-i18n="legend_good_detail">Good: cohesion / loose coupling</span>
</div>
<div class="legend-item">
<span class="legend-color" style="background: var(--quadrant-acceptable);"></span>
<span class="legend-label" data-i18n="legend_stable_detail">Stable: low volatility</span>
</div>
<div class="legend-item">
<span class="legend-color" style="background: var(--quadrant-local-complexity);"></span>
<span class="legend-label" data-i18n="legend_review_detail">Review: needs attention</span>
</div>
<div class="legend-item">
<span class="legend-color" style="background: var(--quadrant-global-complexity);"></span>
<span class="legend-label" data-i18n="legend_critical_detail">Critical: problematic</span>
</div>
</div>
</div>
<div class="legend-section">
<h4 data-i18n="legend_edge_style">Edge Style (Distance)</h4>
<div class="legend-items">
<div class="legend-item">
<span class="legend-line solid"></span>
<span class="legend-label" data-i18n="distance_same_module">Same Module</span>
</div>
<div class="legend-item">
<span class="legend-line dashed"></span>
<span class="legend-label" data-i18n="distance_different_module">Different Module</span>
</div>
<div class="legend-item">
<span class="legend-line dotted"></span>
<span class="legend-label" data-i18n="distance_different_crate">External Crate</span>
</div>
</div>
</div>
<div class="legend-section balance-rules">
<h4 data-i18n="legend_balance_equation">Balance Equation</h4>
<code>BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY</code>
<table class="balance-table">
<tr><td>強結合 + 近距離</td><td class="good">✅ OK</td></tr>
<tr><td>弱結合 + 遠距離</td><td class="good">✅ OK</td></tr>
<tr><td>強結合 + 遠距離</td><td class="bad">❌ 問題</td></tr>
<tr><td>強結合 + 高変動性</td><td class="bad">❌ 問題</td></tr>
</table>
</div>
</div>
</section>
<section class="panel">
<h2>Analysis</h2>
<div id="analysis-mode-indicator"></div>
<div class="analysis-buttons">
<button id="show-dependents" class="btn btn-analysis" disabled>
Show Dependents (→)
</button>
<button id="show-dependencies" class="btn btn-analysis" disabled>
Show Dependencies (←)
</button>
<button id="show-impact" class="btn btn-analysis" disabled>
Full Impact Analysis
</button>
</div>
<div id="blast-radius" style="display: none;"></div>
<p class="hint" id="analysis-hint">Select a node first</p>
</section>
<section class="panel" id="critical-issues-panel">
<h2>🔥 <span data-i18n="critical_issues">Critical Issues</span> <span id="critical-count" class="badge critical">0</span></h2>
<p style="font-size: 0.6875rem; color: var(--text-secondary); margin-bottom: 0.5rem;">
<span data-i18n="unbalanced_deps">Unbalanced coupling relationships</span>
</p>
<div id="critical-issues-list" class="critical-issues-list">
<p class="placeholder" data-i18n="analyzing">Analyzing...</p>
</div>
</section>
<section class="panel">
<h2>Hotspots</h2>
<p style="font-size: 0.75rem; color: var(--text-secondary); margin-bottom: 0.5rem;">
High-impact refactoring targets
</p>
<div id="hotspot-list" class="hotspot-list">
<p class="placeholder">Analyzing...</p>
</div>
</section>
<section class="panel" id="temporal-coupling-panel" style="display: none;">
<h2>Temporal Coupling</h2>
<p style="font-size: 0.75rem; color: var(--text-secondary); margin-bottom: 0.5rem;">
Files that frequently co-change in git commits
</p>
<div id="temporal-coupling-list" class="hotspot-list">
<p class="placeholder">No temporal coupling data</p>
</div>
</section>
<section class="panel">
<h2>Key Modules</h2>
<div class="quick-actions">
<button class="quick-action active" data-sort="connections">Connections</button>
<button class="quick-action" data-sort="issues">Issues</button>
<button class="quick-action" data-sort="health">Health</button>
</div>
<div id="module-rankings" class="module-rank-list">
<p class="placeholder">Loading...</p>
</div>
</section>
<section class="panel">
<h2>Cluster View</h2>
<div class="filter-actions">
<button id="detect-clusters" class="btn">Detect Clusters</button>
<button id="clear-clusters" class="btn">Clear Colors</button>
</div>
<div id="cluster-info" class="cluster-info"></div>
</section>
<section class="panel">
<h2>Issues <span id="issue-count" class="badge">0</span></h2>
<select id="issue-severity-filter" class="select issue-filter">
<option value="all">All severities</option>
<option value="Critical">Critical</option>
<option value="High">High</option>
<option value="Medium">Medium</option>
<option value="Low">Low</option>
</select>
<div id="issue-list" class="issue-list">
<p class="placeholder">No issues detected</p>
</div>
</section>
<section class="panel trust-panel" id="trust-panel">
<h2><span data-i18n="not_analyzed">Not Analyzed</span> <span id="blind-spot-count" class="badge">0</span></h2>
<button id="toggle-trust-panel" class="btn trust-toggle" data-i18n="show_blind_spots">Show blind spots</button>
<div id="trust-panel-content" class="trust-panel-content" style="display: none;"></div>
</section>
<section class="panel">
<h2>Export</h2>
<div class="filter-actions">
<button id="export-png" class="btn">PNG Image</button>
<button id="export-json" class="btn">JSON Data</button>
</div>
</section>
<section class="panel" id="details-panel">
<h2 data-i18n="details">Details</h2>
<div id="node-details">
<p class="placeholder" data-i18n="click_details">Click a node or edge to see details</p>
</div>
</section>
<section class="panel" id="item-graph-panel" style="display: none;">
<h2>📦 Item Dependencies <button id="close-item-graph" class="btn-close" aria-label="Close item dependencies">×</button></h2>
<p class="item-graph-hint">Dependencies within this module</p>
<div class="item-filter-group">
<label><input type="checkbox" id="item-filter-fn" checked> Functions</label>
<label><input type="checkbox" id="item-filter-type" checked> Types</label>
<label><input type="checkbox" id="item-filter-trait" checked> Traits</label>
</div>
<div id="item-graph-container" class="item-graph-container"></div>
<div id="item-graph-legend" class="item-graph-legend">
<span class="legend-item"><span class="dot fn"></span> fn</span>
<span class="legend-item"><span class="dot type"></span> type</span>
<span class="legend-item"><span class="dot trait"></span> trait</span>
<span class="legend-item" style="margin-left: auto;"><span id="item-count">0</span> items</span>
</div>
<div id="item-details" class="item-details"></div>
</section>
<section class="panel" id="legend-panel">
<h2 data-i18n="legend">Legend</h2>
<div class="legend">
<div class="legend-section">
<h4 data-i18n="legend_nodes">Nodes</h4>
<div class="legend-item"><span class="color-box" style="background: var(--subdomain-core);"></span> <span data-i18n="legend_core_subdomain">Core subdomain: high essential volatility</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--subdomain-supporting);"></span> <span data-i18n="legend_supporting_subdomain">Supporting subdomain: expected stable</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--subdomain-generic);"></span> <span data-i18n="legend_generic_subdomain">Generic subdomain or unknown</span></div>
<div class="legend-item"><span class="size-sample"></span> <span data-i18n="legend_larger_node">Larger node: more dependencies and/or churn</span></div>
</div>
<div class="legend-section">
<h4 data-i18n="legend_edges">Edges</h4>
<div class="legend-item"><span class="color-box" style="background: var(--strength-intrusive);"></span> <span data-i18n="legend_intrusive_strength">Intrusive / high-risk strength</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--strength-functional);"></span> <span data-i18n="legend_functional_strength">Functional strength</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--strength-model);"></span> <span data-i18n="legend_model_strength">Model strength</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--strength-contract);"></span> <span data-i18n="legend_contract_strength">Contract strength</span></div>
<div class="legend-item"><span class="line-style solid"></span> <span data-i18n="legend_close_distance">Close distance: same function/module</span></div>
<div class="legend-item"><span class="line-style dashed"></span> <span data-i18n="legend_far_distance">Far distance or hidden temporal coupling</span></div>
<div class="legend-item"><span class="line-style dotted"></span> <span data-i18n="legend_external_lifecycle">Different crate / external lifecycle</span></div>
<div class="legend-item" data-i18n="legend_wider_edge">Wider edge: stronger integration knowledge</div>
</div>
<div class="legend-section">
<h4 data-i18n="legend_balance_model">Balance Model</h4>
<div class="legend-item"><span class="color-box" style="background: var(--quadrant-high-cohesion);"></span> <span data-i18n="legend_high_cohesion_rule">High Cohesion: strong + close</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--quadrant-loose-coupling);"></span> <span data-i18n="legend_loose_coupling_rule">Loose Coupling: weak + far</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--quadrant-acceptable);"></span> <span data-i18n="legend_acceptable_rule">Acceptable: strong + far but stable</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--quadrant-local-complexity);"></span> <span data-i18n="legend_local_complexity_rule">Local Complexity: weak + close</span></div>
<div class="legend-item"><span class="color-box" style="background: var(--quadrant-global-complexity);"></span> <span data-i18n="legend_global_complexity_rule">Global Complexity: strong + far + volatile</span></div>
<code>BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY</code>
</div>
<div class="legend-section">
<h4 data-i18n="legend_dimension_space">Dimension-Space</h4>
<div class="legend-item" data-i18n="legend_x_axis">X axis: integration strength</div>
<div class="legend-item" data-i18n="legend_y_axis">Y axis: distance / cost of change</div>
<div class="legend-item" data-i18n="legend_z_axis">Z axis: volatility / probability of change</div>
<div class="legend-item" data-i18n="legend_point">Each point is a coupling relationship at those coordinates.</div>
</div>
</div>
</section>
<section class="panel">
<h2>Shortcuts <span style="opacity: 0.5;">(?)</span></h2>
<div class="shortcuts-list">
<div class="shortcut"><kbd>/</kbd> Search</div>
<div class="shortcut"><kbd>t</kbd> Toggle Tree/Graph</div>
<div class="shortcut"><kbd>s</kbd> Toggle sidebar</div>
<div class="shortcut"><kbd>f</kbd> Fit to screen</div>
<div class="shortcut"><kbd>r</kbd> Reset layout</div>
<div class="shortcut"><kbd>c</kbd> Toggle center mode</div>
<div class="shortcut"><kbd>e</kbd> Export PNG</div>
<div class="shortcut"><kbd>Esc</kbd> Clear selection</div>
</div>
</section>
</aside>
<footer class="footer" id="footer">
<div id="summary-stats"></div>
</footer>
</div>
<div id="help-modal" class="modal">
<div class="modal-content">
<h2>Keyboard Shortcuts</h2>
<table class="shortcuts-table">
<tr><td><kbd>/</kbd></td><td>Focus search</td></tr>
<tr><td><kbd>f</kbd></td><td>Fit graph to screen</td></tr>
<tr><td><kbd>r</kbd></td><td>Reset layout</td></tr>
<tr><td><kbd>c</kbd></td><td>Toggle center mode</td></tr>
<tr><td><kbd>t</kbd></td><td>Toggle Tree/Graph view</td></tr>
<tr><td><kbd>s</kbd></td><td>Toggle sidebar</td></tr>
<tr><td><kbd>e</kbd></td><td>Export as PNG</td></tr>
<tr><td><kbd>Esc</kbd></td><td>Clear selection</td></tr>
<tr><td><kbd>?</kbd></td><td>Toggle this help</td></tr>
</table>
<button onclick="toggleHelpModal()" class="btn">Close</button>
</div>
</div>
<div id="details-modal" class="details-modal hidden">
<div class="details-modal-backdrop"></div>
<div class="details-modal-content">
<div class="details-modal-header">
<h2 id="details-modal-title">Module Details</h2>
<button class="btn-close-modal" id="close-details-modal" aria-label="Close module details">×</button>
</div>
<div class="details-tabs">
<button class="tab active" data-tab="overview">Overview</button>
<button class="tab" data-tab="couplings">Couplings</button>
<button class="tab" data-tab="items">Items</button>
<button class="tab" data-tab="source">Source</button>
</div>
<div class="details-modal-body">
<div class="tab-content active" id="tab-overview"></div>
<div class="tab-content" id="tab-couplings"></div>
<div class="tab-content" id="tab-items"></div>
<div class="tab-content" id="tab-source"></div>
</div>
</div>
</div>
<script type="module" src="/js/main.js"></script>
<script>
function toggleHelpModal() {
const modal = document.getElementById('help-modal');
if (modal) modal.classList.toggle('visible');
}
</script>
</body>
</html>