From e6089a2b63fbf5fb73be3a17e65dcf8be25232c8 Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Mon, 11 May 2026 12:47:41 +0530
Subject: [PATCH 1/8] #25 fix accessibility issue
---
index.html | 1 +
style.css | 17 ++++++++++++-----
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/index.html b/index.html
index c3e8c99..32519c2 100644
--- a/index.html
+++ b/index.html
@@ -108,6 +108,7 @@ The Ship of Theseus
+ Insights
How much has changed?
diff --git a/style.css b/style.css
index a2999ea..87fb96b 100644
--- a/style.css
+++ b/style.css
@@ -10,6 +10,18 @@
--font-mono: 'JetBrains Mono', monospace;
}
+.visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
* {
margin: 0;
padding: 0;
@@ -69,7 +81,6 @@ body {
text-transform: uppercase;
letter-spacing: 0.15em;
color: var(--text-secondary);
- opacity: 0.6;
transition: all 0.3s ease;
cursor: default;
}
@@ -160,7 +171,6 @@ body {
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
- opacity: 0.6;
}
.mode-btn,
@@ -192,7 +202,6 @@ body {
font-style: italic;
font-size: 0.9rem;
color: var(--text-secondary);
- opacity: 0.7;
margin-top: 0.5rem;
}
@@ -671,7 +680,6 @@ svg#main-chart {
.footer-text {
font-size: 0.8rem;
color: var(--text-secondary);
- opacity: 0.5;
}
/* Personal Narrative Section */
@@ -732,7 +740,6 @@ svg#main-chart {
font-style: normal;
font-size: 0.85rem;
color: var(--text-secondary);
- opacity: 0.7;
display: block;
margin-top: 0.5rem;
letter-spacing: 0.05em;
From feacbf016961922784bc61cb3a48efdafcd036cf Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Mon, 11 May 2026 13:08:48 +0530
Subject: [PATCH 2/8] #25 removed some cards
---
app.js | 122 +++++++++++++++--------------------------------------
index.html | 24 -----------
style.css | 3 +-
3 files changed, 35 insertions(+), 114 deletions(-)
diff --git a/app.js b/app.js
index 3c58519..5f1dd23 100644
--- a/app.js
+++ b/app.js
@@ -211,8 +211,8 @@ class TheseusVisualizer {
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "0%").attr("y2", "100%");
- grad.append("stop").attr("offset", "0%").attr("stop-color", color).attr("stop-opacity", 0.6);
- grad.append("stop").attr("offset", "100%").attr("stop-color", color).attr("stop-opacity", 0.05);
+ grad.append("stop").attr("offset", "0%").attr("stop-color", color).attr("stop-opacity", 0.9);
+ grad.append("stop").attr("offset", "100%").attr("stop-color", color).attr("stop-opacity", 0.4);
});
// Specialized gradients for Identity mode if needed
@@ -223,8 +223,8 @@ class TheseusVisualizer {
.attr("id", `grad-id-${id}`)
.attr("x1", "0%").attr("y1", "0%")
.attr("x2", "0%").attr("y2", "100%");
- grad.append("stop").attr("offset", "0%").attr("stop-color", color).attr("stop-opacity", 0.6);
- grad.append("stop").attr("offset", "100%").attr("stop-color", color).attr("stop-opacity", 0.05);
+ grad.append("stop").attr("offset", "0%").attr("stop-color", color).attr("stop-opacity", 0.9);
+ grad.append("stop").attr("offset", "100%").attr("stop-color", color).attr("stop-opacity", 0.4);
});
}
@@ -434,54 +434,31 @@ class TheseusVisualizer {
? point.date.toISOString().split('T')[0]
: point.date;
- const oldestYear = this.years[0];
- const originalVal = point[oldestYear] || 0;
-
- // Find previous point to detect refactor
- const idx = this.points.indexOf(point);
- const prev = idx > 0 ? this.points[idx - 1] : null;
- const prevOldVal = prev ? (prev[oldestYear] || 0) : null;
- const isRefactor = prevOldVal && originalVal < prevOldVal * 0.85;
-
- const evolutionVal = point.total - originalVal;
-
- let refactorHTML = '';
- if (originalVal === 0) {
- refactorHTML = `
-
- Ship of Theseus: The Great Rebirth
- The original source code is now entirely gone.
Is this still the same codebase?
-
- `;
- } else if (isRefactor) {
- refactorHTML = `
-
- Ship of Theseus: Major Refactor
- A significant part of the original source was refactored here.
How much can you change before the identity shifts?
-
- `;
- }
+ const foundationYear = this.years[0];
+ const foundationVal = point[foundationYear] || 0;
+
+ const existingYears = Object.keys(point).filter(k => k !== 'date' && k !== 'total').sort();
+ const oldestSurvivingYear = existingYears[0];
+ const oldestSurvivingVal = point[oldestSurvivingYear] || 0;
+
+ const isFoundationAlive = foundationVal > 0;
+ const refactoredVal = point.total - foundationVal;
this.tooltip.innerHTML = `
- ${refactorHTML}
Total Project Size
- ${point.total.toLocaleString()} lines
+ ${point.total.toLocaleString()} lines
@@ -490,10 +467,22 @@ class TheseusVisualizer {
Refactored
- ${evolutionVal.toLocaleString()}
- ${point.total > 0 ? ((evolutionVal / point.total) * 100).toFixed(1) : '0.0'}%
+ ${refactoredVal.toLocaleString()}
+ ${point.total > 0 ? ((refactoredVal / point.total) * 100).toFixed(1) : '0.0'}%
+
+
+ ${!isFoundationAlive && oldestSurvivingYear !== foundationYear ? `
+
+ ` : ''}
`;
// Positioning AFTER content injection
@@ -552,54 +541,9 @@ class TheseusVisualizer {
document.getElementById('percent-replaced').textContent = '--';
}
- // Death counter: count times when original code dropped to 0
- let deathCount = 0;
- let wasDead = false;
- for (const point of this.points) {
- const origLines = point[birthYear] || 0;
- if (origLines === 0 && !wasDead) {
- deathCount++;
- wasDead = true;
- } else if (origLines > 0) {
- wasDead = false;
- }
- }
- document.getElementById('death-count').textContent = deathCount;
-
- // 4. Modernization Velocity (Δ Old Code / Δ Time)
+ // Mean Code Age (Weighted average)
const lastDate = new Date(last.date);
const currentYear = lastDate.getFullYear();
- const oldThreshold = currentYear - 3;
-
- // Find snapshot approx 6 months ago (180 days)
- const targetMs = lastDate.getTime() - (180 * 24 * 60 * 60 * 1000);
- let prevSnapshot = this.points[0];
- for (let i = this.points.length - 1; i >= 0; i--) {
- if (new Date(this.points[i].date).getTime() <= targetMs) {
- prevSnapshot = this.points[i];
- break;
- }
- }
-
- const getOldLines = (snap) => {
- return this.years
- .filter(y => y <= oldThreshold)
- .reduce((sum, y) => sum + (snap[y] || 0), 0);
- };
-
- const oldNow = getOldLines(last);
- const oldThen = getOldLines(prevSnapshot);
- const months = Math.max(1, (lastDate - new Date(prevSnapshot.date)) / (30 * 24 * 60 * 60 * 1000));
- const velocity = (oldThen - oldNow) / months;
-
- const velEl = document.getElementById('modernization-velocity');
- if (this.points.length < 2 || oldThen === 0) {
- velEl.textContent = 'Stable';
- } else {
- velEl.textContent = `${Math.max(0, Math.round(velocity)).toLocaleString()}`;
- }
-
- // 5. Mean Code Age (Weighted average)
const totalLines = last.total;
if (totalLines > 0) {
let totalAge = 0;
@@ -614,7 +558,7 @@ class TheseusVisualizer {
document.getElementById('mean-code-age').textContent = '0.0 yrs';
}
- // 6. Peak Preservation (Largest legacy year)
+ // Peak Preservation (Largest legacy year)
let peakYear = '--';
let peakVal = 0;
this.years.forEach(y => {
diff --git a/index.html b/index.html
index 32519c2..84de155 100644
--- a/index.html
+++ b/index.html
@@ -163,30 +163,6 @@
-
-
- How fast is code being replaced?
- ?
-
-
-
- --
-
-
Lines replaced per month
-
-
-
-
- How many times did the original codebase die?
- ?
-
-
-
--
-
Complete rebuilds
-
-
What's the average code age?
diff --git a/style.css b/style.css
index 87fb96b..1605a5d 100644
--- a/style.css
+++ b/style.css
@@ -426,6 +426,7 @@ svg#main-chart {
align-items: center;
font-size: 0.95rem;
padding: 0.35rem 0;
+ gap: 1rem;
}
.label-group {
@@ -443,7 +444,7 @@ svg#main-chart {
.value-group {
display: flex;
align-items: center;
- gap: 0.75rem;
+ gap: 1rem;
}
.percent-tag {
From 054bcaff4bc0c53d3d2aa806f1e724db95134da0 Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Mon, 11 May 2026 13:12:23 +0530
Subject: [PATCH 3/8] #25 improve fossil section
---
app.js | 7 +-----
index.html | 7 +++---
style.css | 63 +++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 62 insertions(+), 15 deletions(-)
diff --git a/app.js b/app.js
index 5f1dd23..01bfc73 100644
--- a/app.js
+++ b/app.js
@@ -618,12 +618,7 @@ class TheseusVisualizer {
a.target = '_blank';
a.rel = 'noopener noreferrer';
a.textContent = display;
- a.style.color = 'inherit';
- a.style.textDecoration = 'underline';
- a.style.textDecorationColor = 'rgba(255,255,255,0.2)';
- a.style.transition = 'color 0.3s ease';
- a.addEventListener('mouseover', () => { a.style.color = 'var(--accent-cyan)'; });
- a.addEventListener('mouseout', () => { a.style.color = 'inherit'; });
+ a.className = 'fossil-link';
return a;
};
diff --git a/index.html b/index.html
index 84de155..069a834 100644
--- a/index.html
+++ b/index.html
@@ -197,6 +197,7 @@ How the data is collected
Ancient Code Fragments
+ Click the file path below to view on GitHub
diff --git a/style.css b/style.css
index 1605a5d..ce799c9 100644
--- a/style.css
+++ b/style.css
@@ -772,15 +772,24 @@ svg#main-chart {
.section-title {
font-family: var(--font-serif);
font-size: 2rem;
- margin-bottom: 2rem;
+ margin-bottom: 0.5rem;
color: var(--text-primary);
text-align: center;
}
+.fossil-hint {
+ text-align: center;
+ font-size: 0.8rem;
+ color: var(--text-secondary);
+ opacity: 0.6;
+ margin-bottom: 2.5rem;
+ font-style: italic;
+}
+
.fossil-grid {
display: grid;
grid-template-columns: 1fr;
- gap: 2rem;
+ gap: 2.5rem;
}
@media (min-width: 768px) {
@@ -793,10 +802,12 @@ svg#main-chart {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 1.5rem;
- padding: 1.25rem 1.5rem;
+ padding: 1.5rem 2rem;
position: relative;
overflow: hidden;
text-align: left;
+ cursor: pointer;
+ transition: all 0.3s ease;
}
.fossil-card::before {
@@ -815,6 +826,7 @@ svg#main-chart {
.fossil-card:hover {
border-color: rgba(59, 199, 199, 0.3);
box-shadow: 0 0 40px rgba(59, 199, 199, 0.1);
+ transform: translateY(-4px);
}
.fossil-header {
@@ -829,6 +841,20 @@ svg#main-chart {
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--accent-cyan);
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.fossil-label::after {
+ content: '↗';
+ font-size: 0.7rem;
+ opacity: 0;
+ transition: opacity 0.3s ease;
+}
+
+.fossil-card:hover .fossil-label::after {
+ opacity: 0.6;
}
.fossil-year {
@@ -842,14 +868,32 @@ svg#main-chart {
.fossil-meta {
font-size: 0.8rem;
color: var(--text-secondary);
- margin-bottom: 1rem;
+ margin-bottom: 1.25rem;
opacity: 0.6;
display: flex;
- gap: 0.5rem;
+ gap: 0.75rem;
align-items: center;
flex-wrap: wrap;
}
+.fossil-link {
+ color: var(--accent-cyan);
+ text-decoration: underline;
+ text-underline-offset: 3px;
+ text-decoration-color: rgba(59, 199, 199, 0.4);
+ cursor: pointer;
+ transition: all 0.2s ease;
+ padding: 0.25rem 0.5rem;
+ border-radius: 0.25rem;
+ background: rgba(59, 199, 199, 0.05);
+ display: inline-block;
+}
+
+.fossil-link:hover {
+ background: rgba(59, 199, 199, 0.15);
+ text-decoration-color: rgba(59, 199, 199, 0.8);
+}
+
.fossil-commit {
font-family: var(--font-mono);
font-size: 0.7rem;
@@ -884,3 +928,12 @@ svg#main-chart {
flex-shrink: 0;
display: inline;
}
+
+.fossil-description {
+ font-size: 0.75rem;
+ font-style: italic;
+ color: var(--text-secondary);
+ opacity: 0.5;
+ margin-top: 1.25rem;
+ line-height: 1.5;
+}
From 3a070edb069a35eebac83b65322dae50803f6255 Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Mon, 11 May 2026 13:26:09 +0530
Subject: [PATCH 4/8] #25 fix data issue
---
app.js | 17 +++++++----------
index.html | 6 +++---
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/app.js b/app.js
index 01bfc73..606d5af 100644
--- a/app.js
+++ b/app.js
@@ -528,15 +528,13 @@ class TheseusVisualizer {
}
document.getElementById('oldest-line').textContent = oldestSurviving;
- if (birthYear && first.total > 0) {
- const originalLinesInFirst = first[birthYear] || 0;
- if (originalLinesInFirst > 0) {
- const originalLinesInLast = last[birthYear] || 0;
- const replaced = ((originalLinesInFirst - originalLinesInLast) / originalLinesInFirst) * 100;
- document.getElementById('percent-replaced').textContent = `${Math.min(100, Math.max(0, replaced)).toFixed(1)}%`;
- } else {
- document.getElementById('percent-replaced').textContent = '0.0%';
- }
+ const foundationLines = last[birthYear] || 0;
+ const totalLines = last.total || 0;
+ if (birthYear && totalLines > 0) {
+ const foundationPercent = (foundationLines / totalLines) * 100;
+ document.getElementById('percent-replaced').textContent = `${foundationPercent.toFixed(1)}%`;
+ } else if (totalLines > 0) {
+ document.getElementById('percent-replaced').textContent = '0.0%';
} else {
document.getElementById('percent-replaced').textContent = '--';
}
@@ -544,7 +542,6 @@ class TheseusVisualizer {
// Mean Code Age (Weighted average)
const lastDate = new Date(last.date);
const currentYear = lastDate.getFullYear();
- const totalLines = last.total;
if (totalLines > 0) {
let totalAge = 0;
this.years.forEach(y => {
diff --git a/index.html b/index.html
index 069a834..1324b90 100644
--- a/index.html
+++ b/index.html
@@ -111,13 +111,13 @@ The Ship of Theseus
Insights
- How much has changed?
+ How much foundation remains?
?
+ data-tooltip="Percentage of the current codebase that originated in the foundation year">?
--
-
of original code replaced
+
of current codebase is foundation code
From 91db3d55e3f8998f8705d6c8e41b4f08916c6745 Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Tue, 12 May 2026 12:15:29 +0530
Subject: [PATCH 5/8] #25 added stars in the sky
---
app.js | 73 +++++++++++++++++++++++++++++++++++++++++++++
style.css | 43 ++++++++++++++++++++++++++
theseus.config.json | 63 ++++++++++++++++++++++++++++++++++++--
3 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/app.js b/app.js
index 606d5af..0e0e46d 100644
--- a/app.js
+++ b/app.js
@@ -272,9 +272,58 @@ class TheseusVisualizer {
// Interaction Components (Legend, Axes, Scrubber)
this.renderLegend();
this.renderAxes(g, chartWidth, chartHeight, xScale, yScale);
+ this.renderMilestoneMarkers(g, chartWidth, chartHeight, xScale);
this.setupInteractivity(g, chartWidth, chartHeight, xScale, yScale);
}
+ renderMilestoneMarkers(g, chartWidth, chartHeight, xScale) {
+ const repoInfo = this.manifest.find(r => r.name === this.currentRepo);
+ if (!repoInfo || !repoInfo.milestones) return;
+
+ const tooltip = this;
+
+ repoInfo.milestones.forEach(m => {
+ const milestoneDate = new Date(m.date + '-01');
+ const xPos = xScale(milestoneDate);
+
+ if (xPos >= 0 && xPos <= chartWidth) {
+ const marker = g.append('g')
+ .attr('class', 'milestone-marker')
+ .attr('transform', `translate(${xPos}, 0)`)
+ .style('cursor', 'pointer');
+
+ marker.append('text')
+ .attr('x', 0)
+ .attr('y', 18)
+ .attr('text-anchor', 'middle')
+ .attr('font-size', '14px')
+ .attr('fill', '#8b5cf6')
+ .text('★')
+ .style('opacity', 0.8)
+ .style('filter', 'drop-shadow(0 0 4px rgba(139, 92, 246, 0.6))');
+
+ marker.append('title')
+ .text(m.title + ': ' + m.description);
+
+ marker.on('mouseenter', function() {
+ d3.select(this).select('text')
+ .transition()
+ .duration(200)
+ .attr('font-size', '18px')
+ .style('opacity', 1);
+ });
+
+ marker.on('mouseleave', function() {
+ d3.select(this).select('text')
+ .transition()
+ .duration(200)
+ .attr('font-size', '14px')
+ .style('opacity', 0.8);
+ });
+ }
+ });
+ }
+
renderLegend() {
this.legend.innerHTML = '';
const items = this.vizMode === 'identity'
@@ -444,7 +493,31 @@ class TheseusVisualizer {
const isFoundationAlive = foundationVal > 0;
const refactoredVal = point.total - foundationVal;
+ // Find milestone if close to current date
+ let milestoneHTML = '';
+ const repoInfo = this.manifest.find(r => r.name === this.currentRepo);
+ if (repoInfo && repoInfo.milestones) {
+ const pointDate = new Date(point.date);
+ for (const m of repoInfo.milestones) {
+ const milestoneDate = new Date(m.date + '-01');
+ const monthsDiff = Math.abs((pointDate - milestoneDate) / (1000 * 60 * 60 * 24 * 30));
+ if (monthsDiff <= 3) { // Within 3 months
+ milestoneHTML = `
+
+
🏛️
+
+
${m.title}
+
${m.description}
+
+
+ `;
+ break;
+ }
+ }
+ }
+
this.tooltip.innerHTML = `
+ ${milestoneHTML}
Total Project Size
diff --git a/style.css b/style.css
index ce799c9..31a91f2 100644
--- a/style.css
+++ b/style.css
@@ -407,6 +407,49 @@ svg#main-chart {
z-index: 100;
min-width: 340px;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.8);
+}
+
+.milestone-banner {
+ display: flex;
+ gap: 0.75rem;
+ align-items: flex-start;
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(59, 199, 199, 0.1));
+ border: 1px solid rgba(139, 92, 246, 0.3);
+ border-radius: 0.75rem;
+ padding: 1rem;
+ margin-bottom: 1.25rem;
+}
+
+.milestone-icon {
+ font-size: 1.5rem;
+ flex-shrink: 0;
+}
+
+.milestone-content {
+ flex: 1;
+}
+
+.milestone-title {
+ font-weight: 600;
+ font-size: 0.9rem;
+ color: var(--text-primary);
+ margin-bottom: 0.35rem;
+}
+
+.milestone-desc {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ line-height: 1.4;
+ opacity: 0.9;
+}
+
+.milestone-marker text {
+ transition: all 0.2s ease;
+}
+
+.milestone-marker:hover text {
+ filter: drop-shadow(0 0 8px rgba(139, 92, 246, 0.8));
+}
transition: opacity 0.2s ease;
}
diff --git a/theseus.config.json b/theseus.config.json
index ec4968d..60a52fc 100644
--- a/theseus.config.json
+++ b/theseus.config.json
@@ -11,13 +11,72 @@
"name": "react",
"file": "react_data.json",
"description": "Component-based JavaScript library for building user interfaces.",
- "repo": "facebook/react"
+ "repo": "facebook/react",
+ "milestones": [
+ {
+ "date": "2013-05",
+ "title": "React open sourced",
+ "description": "React was released as open source at JSConf 2013. Facebook engineers shared their internal tool with the world."
+ },
+ {
+ "date": "2017-09",
+ "title": "React rebuilt from scratch",
+ "description": "React 16 launched with a complete internal rewrite. Same API for users, but the engine was entirely rebuilt to be faster and more flexible."
+ },
+ {
+ "date": "2019-02",
+ "title": "Hooks changed everything",
+ "description": "React 16.8 introduced Hooks - a new way to use state and features without writing classes. This became the standard way to write React."
+ },
+ {
+ "date": "2024-04",
+ "title": "React 19 major update",
+ "description": "React 19 brought Server Components and new ways to handle forms and data. Check the next two milestones for data quirks."
+ },
+ {
+ "date": "2019-06",
+ "title": "Data quirk: code looks different",
+ "description": "The data shows weird patterns here because Facebook reorganized their code internally. Old code got re-attributed to new files."
+ },
+ {
+ "date": "2023-06",
+ "title": "Data quirk: lots missing",
+ "description": "This is a data quirk - many years of code seem to vanish. It's just how the data was collected at this point."
+ }
+ ]
},
{
"name": "numpy",
"file": "numpy_data.json",
"description": "The fundamental package for scientific computing in Python.",
- "repo": "numpy/numpy"
+ "repo": "numpy/numpy",
+ "milestones": [
+ {
+ "date": "2005-09",
+ "title": "NumPy is born",
+ "description": "Travis Oliphant merges Numeric and Numarray to create NumPy - the foundation of Python's scientific computing ecosystem."
+ },
+ {
+ "date": "2006-03",
+ "title": "NumPy 1.0 released",
+ "description": "NumPy 1.0 launches as a standalone package, separated from SciPy. This marks the official birth of NumPy as its own library."
+ },
+ {
+ "date": "2013-04",
+ "title": "Python 2 & 3 unified",
+ "description": "Major refactoring to create a unified codebase supporting both Python 2 and Python 3 without 2to3 conversion. Shipped in NumPy 1.8.0 (Oct 2013)."
+ },
+ {
+ "date": "2017-06",
+ "title": "Major features added",
+ "description": "NumPy 1.13 brings groundbreaking features: __array_ufunc__, np.block, and 50+ new functions transform the library."
+ },
+ {
+ "date": "2024-06",
+ "title": "NumPy 2.0 released",
+ "description": "First major release since 2006. Massive breaking changes with ABI break, new dtype system, and 10% fewer namespace objects."
+ }
+ ]
},
{
"name": "zed",
From 9ec3b9957cff459f06c9e8242eef926e3fad013f Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Thu, 14 May 2026 12:26:52 +0530
Subject: [PATCH 6/8] #25 starry night for each opensource repo
---
app.js | 4 +--
style.css | 6 ++--
theseus.config.json | 86 +++++++++++++++++++++++++++++++++++++--------
3 files changed, 76 insertions(+), 20 deletions(-)
diff --git a/app.js b/app.js
index 0e0e46d..811a92b 100644
--- a/app.js
+++ b/app.js
@@ -297,10 +297,10 @@ class TheseusVisualizer {
.attr('y', 18)
.attr('text-anchor', 'middle')
.attr('font-size', '14px')
- .attr('fill', '#8b5cf6')
+ .attr('fill', '#3bc7c7')
.text('★')
.style('opacity', 0.8)
- .style('filter', 'drop-shadow(0 0 4px rgba(139, 92, 246, 0.6))');
+ .style('filter', 'drop-shadow(0 0 4px rgba(59, 199, 199, 0.6))');
marker.append('title')
.text(m.title + ': ' + m.description);
diff --git a/style.css b/style.css
index 31a91f2..83c7c39 100644
--- a/style.css
+++ b/style.css
@@ -407,6 +407,7 @@ svg#main-chart {
z-index: 100;
min-width: 340px;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.8);
+ transition: opacity 0.2s ease;
}
.milestone-banner {
@@ -448,11 +449,10 @@ svg#main-chart {
}
.milestone-marker:hover text {
- filter: drop-shadow(0 0 8px rgba(139, 92, 246, 0.8));
-}
- transition: opacity 0.2s ease;
+ filter: drop-shadow(0 0 8px rgba(59, 199, 199, 0.8));
}
+
.tooltip-header {
font-size: 0.75rem;
text-transform: uppercase;
diff --git a/theseus.config.json b/theseus.config.json
index 60a52fc..d9345ec 100644
--- a/theseus.config.json
+++ b/theseus.config.json
@@ -5,7 +5,24 @@
"name": "langchain",
"file": "langchain_data.json",
"description": "Framework for developing LLM-driven applications and agents.",
- "repo": "langchain-ai/langchain"
+ "repo": "langchain-ai/langchain",
+ "milestones": [
+ {
+ "date": "2023-12",
+ "title": "LangChain v0.1",
+ "description": "First stable architecture release with standardized core components."
+ },
+ {
+ "date": "2024-06",
+ "title": "Monorepo & LangGraph Cloud",
+ "description": "Massive expansion with LangGraph Cloud and integration packages."
+ },
+ {
+ "date": "2025-10",
+ "title": "LangChain v1.0 (The Pruning)",
+ "description": "Legacy code moved to langchain-classic for a leaner, faster core."
+ }
+ ]
},
{
"name": "react",
@@ -16,32 +33,32 @@
{
"date": "2013-05",
"title": "React open sourced",
- "description": "React was released as open source at JSConf 2013. Facebook engineers shared their internal tool with the world."
+ "description": "Public release of React at JSConf 2013."
},
{
"date": "2017-09",
"title": "React rebuilt from scratch",
- "description": "React 16 launched with a complete internal rewrite. Same API for users, but the engine was entirely rebuilt to be faster and more flexible."
+ "description": "React 16 rewrite for better performance."
},
{
"date": "2019-02",
"title": "Hooks changed everything",
- "description": "React 16.8 introduced Hooks - a new way to use state and features without writing classes. This became the standard way to write React."
+ "description": "Introduced Hooks for state management without classes."
},
{
"date": "2024-04",
"title": "React 19 major update",
- "description": "React 19 brought Server Components and new ways to handle forms and data. Check the next two milestones for data quirks."
+ "description": "Added Server Components and new form handling."
},
{
"date": "2019-06",
"title": "Data quirk: code looks different",
- "description": "The data shows weird patterns here because Facebook reorganized their code internally. Old code got re-attributed to new files."
+ "description": "Data quirk: Internal code reorganization."
},
{
"date": "2023-06",
"title": "Data quirk: lots missing",
- "description": "This is a data quirk - many years of code seem to vanish. It's just how the data was collected at this point."
+ "description": "Data quirk: Missing historical data."
}
]
},
@@ -54,27 +71,27 @@
{
"date": "2005-09",
"title": "NumPy is born",
- "description": "Travis Oliphant merges Numeric and Numarray to create NumPy - the foundation of Python's scientific computing ecosystem."
+ "description": "Created by merging Numeric and Numarray."
},
{
"date": "2006-03",
"title": "NumPy 1.0 released",
- "description": "NumPy 1.0 launches as a standalone package, separated from SciPy. This marks the official birth of NumPy as its own library."
+ "description": "Official 1.0 release as a standalone library."
},
{
"date": "2013-04",
"title": "Python 2 & 3 unified",
- "description": "Major refactoring to create a unified codebase supporting both Python 2 and Python 3 without 2to3 conversion. Shipped in NumPy 1.8.0 (Oct 2013)."
+ "description": "Unified support for Python 2 and 3."
},
{
"date": "2017-06",
"title": "Major features added",
- "description": "NumPy 1.13 brings groundbreaking features: __array_ufunc__, np.block, and 50+ new functions transform the library."
+ "description": "Major update with 50+ new functions."
},
{
"date": "2024-06",
"title": "NumPy 2.0 released",
- "description": "First major release since 2006. Massive breaking changes with ABI break, new dtype system, and 10% fewer namespace objects."
+ "description": "NumPy 2.0: Major update with new dtype system."
}
]
},
@@ -82,13 +99,52 @@
"name": "zed",
"file": "zed_data.json",
"description": "High-performance, GPU-accelerated code editor for teamwork.",
- "repo": "zed-industries/zed"
+ "repo": "zed-industries/zed",
+ "milestones": [
+ {
+ "date": "2023-03",
+ "title": "Zed Beta Launch",
+ "description": "High-performance code editor enters public beta on macOS."
+ },
+ {
+ "date": "2023-12",
+ "title": "GPUI2 Transition and Open Sourced",
+ "description": "Major rewrite of the UI framework for 120 FPS performance and The Zed source code is made available to the public."
+ },
+ {
+ "date": "2024-06",
+ "title": "Linux Release",
+ "description": "Official launch of Zed for Linux after months of development."
+ },
+ {
+ "date": "2024-09",
+ "title": "Zed AI Launch",
+ "description": "Introduction of native AI features and the Zed AI ecosystem."
+ }
+ ]
},
{
"name": "claude-code",
"file": "claude-code_data.json",
"description": "Claude's agentic CLI tool for local coding tasks.",
- "repo": "anthropics/claude-code"
+ "repo": "anthropics/claude-code",
+ "milestones": [
+ {
+ "date": "2025-05",
+ "title": "Official v1.0 Launch",
+ "description": "General availability alongside the Claude 4 model family."
+ },
+ {
+ "date": "2025-09",
+ "title": "v2.0 Major Overhaul",
+ "description": "Foundational rewrite with terminal-first architecture."
+ },
+ {
+ "date": "2026-03",
+ "title": "Source Code Leak (v2.1.88)",
+ "description": "Accidental exposure of source code via npm map files."
+ }
+ ]
}
]
-}
+}
\ No newline at end of file
From 77721944f7a71fe123d39ee36a00055ff8e585f5 Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Thu, 14 May 2026 12:30:45 +0530
Subject: [PATCH 7/8] #25 docs: updated the config doc
---
docs/CONFIGURATION.md | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md
index 0a506fa..f3949ed 100644
--- a/docs/CONFIGURATION.md
+++ b/docs/CONFIGURATION.md
@@ -13,7 +13,10 @@ The Ship of Theseus engine operates centrally off a single file: `theseus.config
"name": "react",
"repo": "facebook/react",
"displayName": "React",
- "description": "A JavaScript library for building user interfaces"
+ "description": "A JavaScript library for building user interfaces",
+ "milestones": [
+ { "date": "2013-05", "title": "Open Source", "description": "React is released." }
+ ]
}
]
}
@@ -33,6 +36,20 @@ The `repositories` array takes objects consisting of the following key attribute
| `repo` | *String* | The GitHub repository namespace (the URL ending). The engine automatically strips trailing slashes and resolves this to `https://github.com/namespace/repo.git`. | `"django/django"` |
| `displayName` | *String* | The aesthetic name rendered on UI Cards. | `"Django"` |
| `description` | *String* | A short UI subheading clarifying what the project is. | `"The web framework for perfectionists with deadlines."` |
+| `milestones` | *Array* | An optional list of significant events to display on the timeline. | `[{"date": "2024-01", "title": "Launch"}]` |
+
+---
+
+## Milestone Structure
+
+The `milestones` array contains objects with the following properties:
+
+| Key | Type | Description | Example |
+| :--- | :---: | :--- | :--- |
+| `date` | *String* | The date of the milestone in `YYYY-MM` format. | `"2024-06"` |
+| `title` | *String* | A short, catchy name for the event shown in tooltips. | `"Monorepo Migration"` |
+| `description` | *String* | A concise explanation of the event. | `"Unified all integrations into a single repository."` |
+
---
From 9db29b403a74cf40c416665866571c4a3e9facfe Mon Sep 17 00:00:00 2001
From: Asif Sayyed
Date: Thu, 14 May 2026 13:08:35 +0530
Subject: [PATCH 8/8] #25 bux: fixes from the review
---
app.js | 8 ++++----
style.css | 2 ++
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/app.js b/app.js
index 811a92b..e44244e 100644
--- a/app.js
+++ b/app.js
@@ -305,7 +305,7 @@ class TheseusVisualizer {
marker.append('title')
.text(m.title + ': ' + m.description);
- marker.on('mouseenter', function() {
+ marker.on('mouseenter', function () {
d3.select(this).select('text')
.transition()
.duration(200)
@@ -313,7 +313,7 @@ class TheseusVisualizer {
.style('opacity', 1);
});
- marker.on('mouseleave', function() {
+ marker.on('mouseleave', function () {
d3.select(this).select('text')
.transition()
.duration(200)
@@ -486,7 +486,7 @@ class TheseusVisualizer {
const foundationYear = this.years[0];
const foundationVal = point[foundationYear] || 0;
- const existingYears = Object.keys(point).filter(k => k !== 'date' && k !== 'total').sort();
+ const existingYears = Object.keys(point).filter(k => k !== 'date' && k !== 'total' && point[k] > 0).sort();
const oldestSurvivingYear = existingYears[0];
const oldestSurvivingVal = point[oldestSurvivingYear] || 0;
@@ -544,7 +544,7 @@ class TheseusVisualizer {
${point.total > 0 ? ((refactoredVal / point.total) * 100).toFixed(1) : '0.0'}%
- ${!isFoundationAlive && oldestSurvivingYear !== foundationYear ? `
+ ${!isFoundationAlive && oldestSurvivingYear && oldestSurvivingYear !== foundationYear ? `