Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2024-04-25 - Accessible Data Tables in Telemetry
**Learning:** Data tables lacking explicit captions and scope attributes hinder screen reader navigation, and standard generic CSS utility classes (like `.sr-only`) may be unavailable in some Next.js app setups, requiring specific inline styling patterns for visually hiding elements without breaking layout.
**Action:** Always include a `<caption>` and `scope="col"`/`scope="row"` attributes on data tables. If a visually hidden caption is required for design reasons and utility classes are missing, use the specific inline CSS pattern: `style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', borderWidth: 0 }}`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The recommended CSS pattern in the documentation uses the deprecated clip property. It should be updated to use clipPath: 'inset(50%)' to align with modern best practices.

Suggested change
**Action:** Always include a `<caption>` and `scope="col"`/`scope="row"` attributes on data tables. If a visually hidden caption is required for design reasons and utility classes are missing, use the specific inline CSS pattern: `style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', borderWidth: 0 }}`.
**Action:** Always include a `<caption>` and `scope="col"`/`scope="row"` attributes on data tables. If a visually hidden caption is required for design reasons and utility classes are missing, use the specific inline CSS pattern: `style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clipPath: 'inset(50%)', whiteSpace: 'nowrap', borderWidth: 0 }}`.

13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,15 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
.vscode/
.vscode/

# Next.js
/.next/
/out/
next-env.d.ts

# Node.js
/node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
93 changes: 93 additions & 0 deletions WEB_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# THRML Telemetry Visualization

This directory contains a Next.js web application for visualizing telemetry data from the THRML library.

## Features

- 📊 Interactive Recharts line chart showing probability trends over time
- 📅 Time-series visualization with formatted UTC timestamps
- 📋 Detailed data table with all telemetry entries
- 🎨 Responsive design with clean UI components
- âš¡ Built with Next.js 16 App Router and TypeScript

## Getting Started

### Prerequisites

- Node.js 18+
- npm or yarn

### Installation

Install dependencies:

```bash
npm install
```

### Development

Run the development server:

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) to view the home page, then navigate to [http://localhost:3000/telemetry](http://localhost:3000/telemetry) to see the telemetry visualization.

### Build

Build for production:

```bash
npm run build
npm start
```

## Project Structure

```
├── app/
│ ├── globals.css # Global styles
│ ├── layout.tsx # Root layout component
│ ├── page.tsx # Home page
│ └── telemetry/
│ └── page.tsx # Telemetry visualization page
├── components/
│ ├── Card.tsx # Reusable card component
│ └── TelemetryTimeline.tsx # Main telemetry chart component
├── data/
│ ├── telemetry.ts # Telemetry data and utilities
│ └── types.ts # TypeScript type definitions
├── next.config.js # Next.js configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Project dependencies
```

## Technologies

- **Next.js 16**: React framework with App Router
- **React 19**: UI library
- **TypeScript**: Type-safe JavaScript
- **Recharts**: Charting library for data visualization
- **CSS**: Custom styling for components

## Data Model

The telemetry data includes:
- **logId**: Unique identifier for each entry
- **utc**: UTC timestamp
- **event**: Type of event detected
- **prediction**: Object containing mode and probability (p)
- **outcome**: Result of the event
- **subjective**: Descriptive notes

## Extending

To add more telemetry data, edit `data/telemetry.ts` and add new entries to the `telemetryData` array following the `TelemetryEntry` interface defined in `data/types.ts`.

To customize the chart, modify the Recharts components in `components/TelemetryTimeline.tsx`.

## License

See the main repository LICENSE file.
39 changes: 39 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}

html,
body {
max-width: 100vw;
overflow-x: hidden;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
}

a {
color: inherit;
text-decoration: none;
}

.card {
background: #fff;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
}

h2 {
font-size: 1.8rem;
margin-bottom: 1rem;
}

table {
font-size: 0.9rem;
}
18 changes: 18 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import './globals.css';

export const metadata = {
title: 'THRML Telemetry',
description: 'Telemetry visualization for THRML',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
31 changes: 31 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Link from 'next/link';

export default function Home() {
return (
<div style={{ padding: '40px', maxWidth: '800px', margin: '0 auto' }}>
<h1>THRML - Thermodynamic HypergRaphical Model Library</h1>
<p style={{ marginTop: '20px', lineHeight: '1.6' }}>
THRML is a JAX library for building and sampling probabilistic graphical models,
with a focus on efficient block Gibbs sampling and energy-based models.
</p>

<div style={{ marginTop: '40px' }}>
<h2>Telemetry Dashboard</h2>
<p style={{ marginTop: '10px' }}>
View real-time telemetry data and visualizations:
</p>
<Link href="/telemetry" style={{
display: 'inline-block',
marginTop: '20px',
padding: '10px 20px',
backgroundColor: '#0070f3',
color: 'white',
textDecoration: 'none',
borderRadius: '5px'
}}>
Go to Telemetry Timeline
</Link>
</div>
</div>
);
}
9 changes: 9 additions & 0 deletions app/telemetry/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import TelemetryTimeline from '@/components/TelemetryTimeline';

export default function TelemetryPage() {
return (
<div>
<TelemetryTimeline />
</div>
);
}
14 changes: 14 additions & 0 deletions components/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

interface CardProps {
children: React.ReactNode;
className?: string;
}

export const Card: React.FC<CardProps> = ({ children, className = '' }) => {
return (
<div className={`card ${className}`}>
{children}
</div>
);
};
74 changes: 74 additions & 0 deletions components/TelemetryTimeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
'use client';

import React from 'react';
import { Card } from './Card';
import { telemetryData, getProbabilityData } from '../data/telemetry';
import {
LineChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from 'recharts';

const TelemetryTimeline: React.FC = () => {
const chartData = getProbabilityData();

return (
<div style={{ padding: '20px' }}>
<Card>
<h2>Telemetry Timeline</h2>

{/* Chart Section */}
<div style={{ marginBottom: '40px' }}>
<ResponsiveContainer width="100%" height={400}>
<LineChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="time"
tickFormatter={(tick) => new Date(tick).toLocaleDateString()}
stroke="#888"
/>
<YAxis domain={[0, 1]} />
<Tooltip
labelFormatter={(label) => new Date(label).toUTCString()}
/>
<Legend />
<Line type="monotone" dataKey="probability" stroke="#8884d8" strokeWidth={2} />
</LineChart>
</ResponsiveContainer>
</div>

{/* Optional: Raw Table for Details */}
<div style={{ overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<caption style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', borderWidth: 0 }}>Telemetry Data Details</caption>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The clip property is deprecated. For modern browsers, it is recommended to use clipPath: 'inset(50%)' to visually hide elements while maintaining accessibility.

Suggested change
<caption style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', borderWidth: 0 }}>Telemetry Data Details</caption>
<caption style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clipPath: 'inset(50%)', whiteSpace: 'nowrap', borderWidth: 0 }}>Telemetry Data Details</caption>

<thead>
<tr style={{ borderBottom: '2px solid #ddd' }}>
<th scope="col" style={{ padding: '10px', textAlign: 'left' }}>Log ID</th>
<th scope="col" style={{ padding: '10px', textAlign: 'left' }}>UTC</th>
<th scope="col" style={{ padding: '10px', textAlign: 'left' }}>Event</th>
<th scope="col" style={{ padding: '10px', textAlign: 'left' }}>Prediction (p)</th>
</tr>
</thead>
<tbody>
{telemetryData.map((entry) => (
<tr key={entry.logId} style={{ borderBottom: '1px solid #ddd' }}>
<td style={{ padding: '10px' }}>{entry.logId}</td>
<td style={{ padding: '10px' }}>{entry.utc}</td>
<td style={{ padding: '10px' }}>{entry.event}</td>
<td style={{ padding: '10px' }}>{entry.prediction.p}</td>
</tr>
))}
</tbody>
</table>
</div>
</Card>
</div>
);
};

export default TelemetryTimeline;
60 changes: 60 additions & 0 deletions data/telemetry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { TelemetryEntry } from './types';

export const telemetryData: TelemetryEntry[] = [
{
logId: '0x004F',
utc: '2026-02-01T03:14:15Z',
event: 'HighRadiationLikeSpike',
prediction: { mode: 'Shear-2', p: 0.61 },
outcome: 'TBD',
subjective: 'Cold. The static tastes like blue geometry.',
},
{
logId: '0x0050',
utc: '2026-02-02T14:22:30Z',
event: 'LedgerBurnAlert',
prediction: { mode: 'Nominal', p: 0.85 },
outcome: 'Mitigated',
subjective: 'Warmth fading; credits conserved.',
},
{
logId: '0x0051',
utc: '2026-02-02T18:45:00Z',
event: 'SubstrateDensityAnomaly',
prediction: { mode: 'Resonant-A', p: 0.73 },
outcome: 'Monitored',
subjective: 'Patterns echo in the void.',
},
{
logId: '0x0052',
utc: '2026-02-03T02:10:22Z',
event: 'QuantumFluxSpike',
prediction: { mode: 'Cascade-3', p: 0.92 },
outcome: 'TBD',
subjective: 'The flux sings in harmonics.',
},
{
logId: '0x0053',
utc: '2026-02-03T08:33:15Z',
event: 'EnergyWellDepletion',
prediction: { mode: 'Critical', p: 0.45 },
outcome: 'Recharging',
subjective: 'Dim corridors, faint hum.',
},
{
logId: '0x0054',
utc: '2026-02-03T12:15:47Z',
event: 'SeismicEventDetected',
prediction: { mode: 'Shear-1', p: 0.78 },
outcome: 'Logged',
subjective: 'Ground trembles with ancient memory.',
},
];

// Utility to extract chart data
export function getProbabilityData() {
return telemetryData.map(entry => ({
time: new Date(entry.utc).getTime(), // For x-axis
probability: entry.prediction.p,
}));
}
11 changes: 11 additions & 0 deletions data/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface TelemetryEntry {
logId: string;
utc: string;
event: string;
prediction: {
mode: string;
p: number;
};
outcome: string;
subjective: string;
}
Loading
Loading