feat(phase3): add data visualizations for context pressure and activity timeline

SUMMARY:
Implemented Phase 3 Tasks 3.3.1 and 3.3.2: Interactive data visualizations
showing Context Pressure Monitor metrics and Framework Activity Timeline.

CHANGES:

1. Created pressure-chart.js (new):
   - Interactive SVG gauge showing pressure levels (0-100%)
   - Color-coded status: Green (NORMAL), Amber (ELEVATED), Red (HIGH), Dark Red (CRITICAL)
   - Real-time metrics: Tokens Used, Complexity, Error Rate
   - Simulate button to demonstrate pressure increases
   - Reset button to return to normal state
   - Smooth animations with requestAnimationFrame
   - Respects prefers-reduced-motion

2. Created activity-timeline.js (new):
   - Visual timeline of 6 governance services coordinating
   - Shows request processing flow (0ms-250ms)
   - Service-specific color coding
   - Hover effects on timeline events
   - Total processing time displayed

3. Updated tractatus-theme.css:
   - Added data visualization CSS section
   - .gauge-fill-path transition styles
   - .timeline-event hover effects
   - Respects reduced motion preferences

4. Updated architecture.html:
   - Added "Framework in Action" section
   - Two-column grid layout for visualizations
   - Container divs: #pressure-chart and #activity-timeline
   - Script references for both components

FEATURES:

Context Pressure Visualization:
✓ Animated gauge (0-180 degree arc)
✓ Dynamic color changes based on pressure level
✓ Three metrics tracked (tokens, complexity, errors)
✓ Interactive simulation (30% → 50% → 70% → 85%)
✓ Reset functionality

Framework Activity Timeline:
✓ 6 governance services shown in sequence
✓ Service-specific colors match brand system
✓ Hover effects for interactivity
✓ Total processing time: 250ms

UI_TRANSFORMATION_PROJECT_PLAN.md:
✓ Phase 3 Task 3.3.1: Context Pressure Visualization (COMPLETED)
✓ Phase 3 Task 3.3.2: Framework Activity Timeline (COMPLETED)

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
TheFlow 2025-10-19 20:49:26 +13:00
parent b1ddb04576
commit c6ea87a6a0
5 changed files with 436 additions and 0 deletions

View file

@ -362,6 +362,28 @@
</div>
</section>
<!-- Data Visualizations -->
<section class="bg-white py-16">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h2 class="text-4xl font-bold text-gray-900 mb-6 text-center">Framework in Action</h2>
<p class="text-xl text-gray-600 mb-12 text-center max-w-3xl mx-auto">
Interactive visualizations demonstrating how Tractatus governance services monitor and coordinate AI operations.
</p>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Context Pressure Monitor Visualization -->
<div class="bg-gray-50 rounded-xl shadow-lg p-6 border border-gray-200">
<div id="pressure-chart"></div>
</div>
<!-- Framework Activity Timeline -->
<div class="bg-gray-50 rounded-xl shadow-lg p-6 border border-gray-200">
<div id="activity-timeline"></div>
</div>
</div>
</div>
</section>
<!-- Reference Implementation -->
<section class="bg-gray-50 py-16">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@ -526,6 +548,10 @@
<!-- Interactive Architecture Diagram (Phase 3) -->
<script src="/js/components/interactive-diagram.js?v=20251019170000"></script>
<!-- Data Visualizations (Phase 3) -->
<script src="/js/components/pressure-chart.js"></script>
<script src="/js/components/activity-timeline.js"></script>
<!-- Footer Component -->
<script src="/js/components/footer.js"></script>

View file

@ -952,6 +952,33 @@ body.page-fade-out {
}
}
/* ========================================
* DATA VISUALIZATIONS
* Pressure chart and timeline components
* ======================================== */
.gauge-fill-path {
transition: stroke 0.3s ease;
}
.timeline-event {
transition: all 0.3s ease;
}
.timeline-event:hover {
transform: scale(1.05);
}
@media (prefers-reduced-motion: reduce) {
.gauge-fill-path,
.timeline-event {
transition: none !important;
}
.timeline-event:hover {
transform: none !important;
}
}
/* ========================================
* DARK MODE SUPPORT (Future)
* Placeholder for dark mode implementation

View file

@ -732,6 +732,28 @@ body.page-fade-out {
transition: none !important;
}
}
/* ========================================
* DATA VISUALIZATIONS
* Pressure chart and timeline components
* ======================================== */
.gauge-fill-path {
transition: stroke 0.3s ease;
}
.timeline-event {
transition: all 0.3s ease;
}
.timeline-event:hover {
transform: scale(1.05);
}
@media (prefers-reduced-motion: reduce) {
.gauge-fill-path,
.timeline-event {
transition: none !important;
}
.timeline-event:hover {
transform: none !important;
}
}
/* ========================================
* DARK MODE SUPPORT (Future)
* Placeholder for dark mode implementation

View file

@ -0,0 +1,136 @@
/**
* Framework Activity Timeline
* Tractatus Framework - Phase 3: Data Visualization
*
* Visual timeline showing framework component interactions
* Color-coded by service
*/
class ActivityTimeline {
constructor(containerId) {
this.container = document.getElementById(containerId);
if (!this.container) {
console.error(`[ActivityTimeline] Container #${containerId} not found`);
return;
}
this.events = [
{
time: '0ms',
service: 'instruction',
name: 'InstructionPersistence',
action: 'Load HIGH persistence instructions',
color: '#6366f1'
},
{
time: '50ms',
service: 'validator',
name: 'CrossReferenceValidator',
action: 'Verify request against instruction history',
color: '#8b5cf6'
},
{
time: '100ms',
service: 'boundary',
name: 'BoundaryEnforcer',
action: 'Check if request requires human approval',
color: '#10b981'
},
{
time: '150ms',
service: 'pressure',
name: 'ContextPressureMonitor',
action: 'Calculate current pressure level',
color: '#f59e0b'
},
{
time: '200ms',
service: 'metacognitive',
name: 'MetacognitiveVerifier',
action: 'Verify operation alignment',
color: '#ec4899'
},
{
time: '250ms',
service: 'deliberation',
name: 'PluralisticDeliberation',
action: 'Coordinate stakeholder perspectives',
color: '#14b8a6'
}
];
this.init();
}
init() {
this.render();
console.log('[ActivityTimeline] Initialized');
}
render() {
const eventsHTML = this.events.map((event, index) => `
<div class="timeline-event flex items-start space-x-4 p-4 bg-white rounded-lg border-2 border-gray-200 hover:shadow-md cursor-pointer"
data-service="${event.service}">
<div class="flex-shrink-0 w-16 text-right">
<span class="text-sm font-semibold text-gray-600">${event.time}</span>
</div>
<div class="flex-shrink-0">
<div class="w-3 h-3 rounded-full service-dot" data-color="${event.color}"></div>
</div>
<div class="flex-1">
<div class="text-sm font-semibold text-gray-900 service-name" data-color="${event.color}">
${event.name}
</div>
<div class="text-xs text-gray-600 mt-1">${event.action}</div>
</div>
</div>
`).join('');
this.container.innerHTML = `
<div class="activity-timeline-container">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900">Governance Flow</h3>
<span class="text-xs font-medium text-gray-600 uppercase">Request Processing</span>
</div>
<div class="space-y-3">
${eventsHTML}
</div>
<div class="mt-6 text-xs text-gray-500 text-center">
Total processing time: 250ms | All services coordinated
</div>
</div>
`;
// Apply colors via JavaScript (CSP-compliant)
this.applyColors();
}
applyColors() {
document.querySelectorAll('.service-dot').forEach(dot => {
const color = dot.getAttribute('data-color');
dot.style.backgroundColor = color;
});
document.querySelectorAll('.service-name').forEach(name => {
const color = name.getAttribute('data-color');
name.style.color = color;
});
}
}
// Auto-initialize if container exists
if (typeof window !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('activity-timeline');
if (container) {
window.activityTimeline = new ActivityTimeline('activity-timeline');
}
});
}
// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
module.exports = ActivityTimeline;
}

View file

@ -0,0 +1,225 @@
/**
* Context Pressure Visualization
* Tractatus Framework - Phase 3: Data Visualization
*
* Visual representation of Context Pressure Monitor metrics
* Uses amber color scheme matching the ContextPressureMonitor service
*/
class PressureChart {
constructor(containerId) {
this.container = document.getElementById(containerId);
if (!this.container) {
console.error(`[PressureChart] Container #${containerId} not found`);
return;
}
this.currentLevel = 0; // 0-100
this.targetLevel = 0;
this.animating = false;
this.colors = {
low: '#10b981', // Green - NORMAL
moderate: '#f59e0b', // Amber - ELEVATED
high: '#ef4444', // Red - HIGH
critical: '#991b1b' // Dark Red - CRITICAL
};
this.init();
}
init() {
this.render();
this.attachEventListeners();
console.log('[PressureChart] Initialized');
}
render() {
this.container.innerHTML = `
<div class="pressure-chart-container">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900">Context Pressure Monitor</h3>
<span class="text-xs font-medium text-gray-600 uppercase" id="pressure-status">NORMAL</span>
</div>
<!-- Gauge -->
<div class="relative w-full h-32">
<svg class="w-full h-full" viewBox="0 0 300 150" preserveAspectRatio="xMidYMid meet">
<!-- Background arc -->
<path id="gauge-bg" d="M 30 120 A 120 120 0 0 1 270 120"
stroke="#e5e7eb" stroke-width="20" fill="none" stroke-linecap="round"/>
<!-- Pressure level arc -->
<path id="gauge-fill" d="M 30 120 A 120 120 0 0 1 30 120"
stroke="#f59e0b" stroke-width="20" fill="none" stroke-linecap="round"
class="gauge-fill-path"/>
<!-- Center text -->
<text x="150" y="100" text-anchor="middle" font-size="32" font-weight="bold" fill="#1f2937" id="gauge-value">0%</text>
<text x="150" y="125" text-anchor="middle" font-size="14" fill="#6b7280">Pressure Level</text>
</svg>
</div>
<!-- Metrics -->
<div class="grid grid-cols-3 gap-4 mt-6">
<div class="text-center">
<div class="text-2xl font-bold text-gray-900" id="metric-tokens">0</div>
<div class="text-xs text-gray-600 mt-1">Tokens Used</div>
</div>
<div class="text-center">
<div class="text-2xl font-bold text-gray-900" id="metric-complexity">Low</div>
<div class="text-xs text-gray-600 mt-1">Complexity</div>
</div>
<div class="text-center">
<div class="text-2xl font-bold text-gray-900" id="metric-errors">0</div>
<div class="text-xs text-gray-600 mt-1">Error Rate</div>
</div>
</div>
<!-- Controls -->
<div class="mt-6 space-y-3">
<button id="pressure-simulate-btn"
class="w-full bg-amber-500 hover:bg-amber-600 text-white px-4 py-2 rounded-lg text-sm font-semibold transition">
Simulate Pressure Increase
</button>
<button id="pressure-reset-btn"
class="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg text-sm font-semibold transition">
Reset to Normal
</button>
</div>
</div>
`;
// Store references
this.elements = {
gaugeFill: document.getElementById('gauge-fill'),
gaugeValue: document.getElementById('gauge-value'),
status: document.getElementById('pressure-status'),
tokens: document.getElementById('metric-tokens'),
complexity: document.getElementById('metric-complexity'),
errors: document.getElementById('metric-errors'),
simulateBtn: document.getElementById('pressure-simulate-btn'),
resetBtn: document.getElementById('pressure-reset-btn')
};
}
attachEventListeners() {
this.elements.simulateBtn.addEventListener('click', () => this.simulate());
this.elements.resetBtn.addEventListener('click', () => this.reset());
}
setLevel(level) {
this.targetLevel = Math.max(0, Math.min(100, level));
this.animateToTarget();
}
animateToTarget() {
if (this.animating) return;
this.animating = true;
const animate = () => {
const diff = this.targetLevel - this.currentLevel;
if (Math.abs(diff) < 0.5) {
this.currentLevel = this.targetLevel;
this.animating = false;
this.updateGauge();
return;
}
this.currentLevel += diff * 0.1;
this.updateGauge();
requestAnimationFrame(animate);
};
animate();
}
updateGauge() {
const level = this.currentLevel;
const angle = (level / 100) * 180; // 0-180 degrees
const radians = (angle * Math.PI) / 180;
// Calculate arc endpoint
const centerX = 150;
const centerY = 120;
const radius = 120;
const startX = 30;
const startY = 120;
const endX = centerX + radius * Math.cos(Math.PI - radians);
const endY = centerY - radius * Math.sin(Math.PI - radians);
const largeArcFlag = angle > 180 ? 1 : 0;
const path = `M ${startX} ${startY} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${endX} ${endY}`;
this.elements.gaugeFill.setAttribute('d', path);
this.elements.gaugeValue.textContent = `${Math.round(level)}%`;
// Update color based on level
let color, status;
if (level < 25) {
color = this.colors.low;
status = 'NORMAL';
} else if (level < 50) {
color = this.colors.moderate;
status = 'ELEVATED';
} else if (level < 75) {
color = this.colors.high;
status = 'HIGH';
} else {
color = this.colors.critical;
status = 'CRITICAL';
}
this.elements.gaugeFill.setAttribute('stroke', color);
this.elements.status.textContent = status;
const statusClasses = 'text-xs font-medium uppercase';
const colorClass = level < 25 ? 'text-green-600' :
level < 50 ? 'text-amber-600' :
level < 75 ? 'text-red-600' : 'text-red-800';
this.elements.status.className = `${statusClasses} ${colorClass}`;
// Update metrics based on pressure level
const tokens = Math.round(level * 2000); // 0-200k tokens
const complexityLevels = ['Low', 'Moderate', 'High', 'Extreme'];
const complexityIndex = Math.min(3, Math.floor(level / 25));
const errorRate = Math.round(level / 5); // 0-20%
this.elements.tokens.textContent = tokens.toLocaleString();
this.elements.complexity.textContent = complexityLevels[complexityIndex];
this.elements.errors.textContent = `${errorRate}%`;
}
simulate() {
// Simulate pressure increasing from current to 85%
const targetLevels = [30, 50, 70, 85];
let index = 0;
const step = () => {
if (index >= targetLevels.length) return;
this.setLevel(targetLevels[index]);
index++;
setTimeout(step, 1500);
};
step();
}
reset() {
this.setLevel(0);
}
}
// Auto-initialize if container exists
if (typeof window !== 'undefined') {
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('pressure-chart');
if (container) {
window.pressureChart = new PressureChart('pressure-chart');
}
});
}
// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
module.exports = PressureChart;
}