Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Ready, Xet, Go!</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<div class="hero-band"> | |
<div class="hero-content"> | |
<img src="huggie.png" alt="Huggie" class="hero-logo hero-logo-left"> | |
<div class="hero-text"> | |
<h1 class="hero-title">Ready, Xet, Go!</h1> | |
<p class="hero-subtitle">At the speed of chunks</p> | |
</div> | |
<img src="rockxet.png" alt="RockXet" class="hero-logo hero-logo-right"> | |
</div> | |
</div> | |
<div class="container"> | |
<div class="stats-card"> | |
<div class="card"> | |
<h2>Xet Migration Progress</h2> | |
<div class="progress-container"> | |
<div class="progress-bar" id="progressBar">0%</div> | |
</div> | |
</div> | |
</div> | |
<div class="container"> | |
<div class="counter-wrapper"> | |
<div class="counter-container" id="counter"></div> | |
<div class="counter-text" id="counterText" style="opacity: 0; transition: opacity 1s ease-in;"> | |
in <img src="xet.png" alt="Xet" class="xet-logo"> | |
</div> | |
</div> | |
</div> | |
<div class="charts-container"> | |
<div class="chart-card"> | |
<div class="card"> | |
<h2>Repos Migrated to Xet</h2> | |
<div class="chart-container"> | |
<canvas id="progressChart"></canvas> | |
</div> | |
</div> | |
</div> | |
<div class="chart-card"> | |
<div class="card"> | |
<h2>LFS vs. Xet Files</h2> | |
<div class="chart-container"> | |
<canvas id="largeFilesChart"></canvas> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
const REPO_CSV_URL = 'https://huggingface.co/datasets/jsulz/ready-xet-go/resolve/main/repo-progress.csv'; | |
const FILE_CSV_URL = 'https://huggingface.co/datasets/jsulz/ready-xet-go/resolve/main/file-progress.csv'; | |
const BYTES_CSV_URL = 'https://huggingface.co/datasets/jsulz/ready-xet-go/resolve/main/bytes-progress.csv'; | |
(async () => { | |
/* | |
* Data fetching and parsing | |
*/ | |
const repo_rows = []; | |
const file_rows = []; | |
const bytes_rows = []; | |
const repo_csv = await new Promise((resolve, reject) => { | |
Papa.parse(REPO_CSV_URL, { | |
download: true, | |
header : true, | |
complete: resolve, | |
error : reject | |
}); | |
}); | |
repo_csv.data.forEach(row => { | |
if (row.date && row.xet_repos && row.hub_repos) { | |
repo_rows.push({ | |
date: new Date(row.date), | |
xet_repos: parseInt(row.xet_repos, 10), | |
hub_repos: parseInt(row.hub_repos, 10) | |
}); | |
} | |
}); | |
const file_csv = await new Promise((resolve, reject) => { | |
Papa.parse(FILE_CSV_URL, { | |
download: true, | |
header : true, | |
complete: resolve, | |
error : reject | |
}); | |
}); | |
file_csv.data.forEach(row => { | |
if (row.date && row.lfs_files && row.xet_files) { | |
file_rows.push({ | |
date: new Date(row.date), | |
lfs_files: parseInt(row.lfs_files, 10), | |
xet_files: parseInt(row.xet_files, 10) | |
}); | |
} | |
}); | |
const bytes_csv = await new Promise((resolve, reject) => { | |
Papa.parse(BYTES_CSV_URL, { | |
download: true, | |
header : true, | |
complete: resolve, | |
error : reject | |
}); | |
}); | |
bytes_csv.data.forEach(row => { | |
if (row.date && row.bytes) { | |
bytes_rows.push({ | |
date: new Date(row.date), | |
bytes: parseInt(row.bytes, 10) | |
}); | |
} | |
}); | |
/* | |
* Progress Bar | |
*/ | |
// Progress Bar Constants | |
const max_value = 100; | |
const current_status = Math.round((repo_rows[repo_rows.length - 1].xet_repos / repo_rows[repo_rows.length - 1].hub_repos) * max_value); | |
// Animate Progress Bar - increments smoothly every 50ms | |
const progressBar = document.getElementById('progressBar'); | |
let currentProgress = 0; | |
function animateProgressBar() { | |
if (currentProgress < current_status) { | |
currentProgress++; | |
progressBar.style.width = `${currentProgress}%`; | |
progressBar.textContent = `${currentProgress}%`; | |
setTimeout(animateProgressBar, 75); | |
} | |
} | |
animateProgressBar(); | |
/* | |
* Charts | |
*/ | |
// | |
// Line chart for repo migration progress | |
// | |
// Set up chart data | |
const maxCount = Math.max( | |
...repo_rows.map(row => row.xet_repos), | |
); | |
const dataPoints = repo_rows.map(row => ({ | |
date: row.date, | |
value: row.xet_repos | |
})); | |
// Format date for display (MMM D YYYY) | |
function formatDate(dateStr) { | |
return new Date(dateStr).toLocaleDateString('en-US', { | |
year: 'numeric', month: 'short', day: 'numeric' | |
}); | |
} | |
// Initialize line chart | |
const lineChartCtx = document.getElementById('progressChart').getContext('2d'); | |
let lineChart = new Chart(lineChartCtx, { | |
type: 'line', | |
data: { | |
labels: dataPoints.map(point => formatDate(point.date)), | |
datasets: [{ | |
label: 'Repos Migrated', | |
data: dataPoints.map(point => point.value), | |
borderColor: '#7875FF', | |
backgroundColor: 'rgba(255, 127, 65, 1)', | |
tension: 0.4 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
animation: { duration: 2000 }, | |
scales: { | |
y: { | |
min: 0, | |
ticks: { stepSize: 100000 } | |
}, | |
x: { | |
ticks: { | |
maxTicksLimit: 20 | |
} | |
}, | |
}, | |
plugins: { | |
tooltip: { | |
callbacks: { | |
label: function(context) { | |
return `Repos Migrated: ${context.parsed.y.toLocaleString()}`; | |
} | |
} | |
} | |
} | |
} | |
}); | |
// | |
// Donut chart for large files | |
// | |
// Set up donut chart data | |
const lfs_file_count = file_rows[file_rows.length - 1].lfs_files; | |
const xet_file_count = file_rows[file_rows.length - 1].xet_files; | |
// Initialize donut chart | |
const donutChartCtx = document.getElementById('largeFilesChart').getContext('2d'); | |
let donutChart = new Chart(donutChartCtx, { | |
type: 'doughnut', | |
data: { | |
labels: [ | |
'LFS Files', | |
'Xet Files', | |
], | |
datasets: [{ | |
label: 'My First Dataset', | |
data: [lfs_file_count, xet_file_count], | |
backgroundColor: [ | |
'oklch(0.577 0.245 27.325 / 75.56%)', | |
'oklch(0.6361 0.1994 280.07 / 71.37%)', | |
], | |
hoverOffset: 4 | |
}] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
animation: { duration: 2000 }, | |
plugins: { | |
legend: { | |
position: 'top', | |
}, | |
} | |
} | |
}); | |
/* | |
* Counter | |
*/ | |
// 5x7 pixel patterns for each character (1=pixel on, 0=pixel off) | |
const patterns = { | |
'1': [ | |
'00100', | |
'01100', | |
'00100', | |
'00100', | |
'00100', | |
'00100', | |
'01110' | |
], | |
'2': [ | |
'01110', | |
'10001', | |
'00001', | |
'00010', | |
'00100', | |
'01000', | |
'11111' | |
], | |
'3': [ | |
'01110', | |
'10001', | |
'00001', | |
'00110', | |
'00001', | |
'10001', | |
'01110' | |
], | |
'4': [ | |
'00010', | |
'00110', | |
'01010', | |
'10010', | |
'11111', | |
'00010', | |
'00010' | |
], | |
'5': [ | |
'11111', | |
'10000', | |
'10000', | |
'11110', | |
'00001', | |
'10001', | |
'01110' | |
], | |
'6': [ | |
'01110', | |
'10001', | |
'10000', | |
'11110', | |
'10001', | |
'10001', | |
'01110' | |
], | |
'7': [ | |
'11111', | |
'00001', | |
'00010', | |
'00100', | |
'01000', | |
'01000', | |
'01000' | |
], | |
'8': [ | |
'01110', | |
'10001', | |
'10001', | |
'01110', | |
'10001', | |
'10001', | |
'01110' | |
], | |
'9': [ | |
'01110', | |
'10001', | |
'10001', | |
'01111', | |
'00001', | |
'10001', | |
'01110' | |
], | |
'0': [ | |
'01110', | |
'10001', | |
'10001', | |
'10001', | |
'10001', | |
'10001', | |
'01110' | |
], | |
'.': [ | |
'00000', | |
'00000', | |
'00000', | |
'00000', | |
'00000', | |
'00100', | |
'01110' | |
], | |
'P': [ | |
'11110', | |
'10001', | |
'10001', | |
'11110', | |
'10000', | |
'10000', | |
'10000' | |
], | |
'B': [ | |
'11110', | |
'10001', | |
'10001', | |
'11110', | |
'10001', | |
'10001', | |
'11110' | |
] | |
}; | |
console.log(bytes_rows[bytes_rows.length - 1].bytes) | |
// Convert bytes to PB and format as string | |
const bytesInPB = 1024 ** 5; | |
// Calculate the number of PBs and round to 2 decimal places | |
const text = (bytes_rows[bytes_rows.length - 1].bytes / bytesInPB).toFixed(2) + 'PB'; | |
console.log(text) | |
const container = document.getElementById('counter'); | |
const pixelSize = 5; // Match CSS variable | |
const pixelGap = 1; | |
let allPixels = []; | |
// Create characters and their pixels | |
text.split('').forEach((char, charIndex) => { | |
const charDiv = document.createElement('div'); | |
charDiv.className = 'character'; | |
const pattern = patterns[char]; | |
if (!pattern) return; | |
// Generate pixels based on pattern | |
pattern.forEach((row, rowIndex) => { | |
row.split('').forEach((cell, colIndex) => { | |
if (cell === '1') { | |
const pixel = document.createElement('div'); | |
pixel.className = 'pixel'; | |
// Calculate final position within character grid | |
const finalX = colIndex * (pixelSize + pixelGap); | |
const finalY = rowIndex * (pixelSize + pixelGap); | |
pixel.style.left = `${finalX}px`; | |
pixel.style.top = `${finalY}px`; | |
charDiv.appendChild(pixel); | |
allPixels.push(pixel); | |
} | |
}); | |
}); | |
container.appendChild(charDiv); | |
}); | |
console.log(allPixels) | |
// Animate pixels falling into their final positions | |
allPixels.forEach((pixel, index) => { | |
// Stagger the landing times for a cascading effect | |
const delay = Math.random() * 50 + (index * 50); | |
setTimeout(() => { | |
pixel.classList.add('landed'); | |
}, delay); | |
}); | |
const maxDelay = Math.max(...allPixels.map((_, index) => Math.random() * 50 + (index * 50))); | |
setTimeout(() => { | |
const textDiv = document.getElementById('counterText'); | |
textDiv.style.opacity = '1'; | |
}, maxDelay + 500); | |
})(); | |
</script> | |
</body> | |
</html> |