commit 3d52164e9d12fde30413fa1250caeaecb3f678cd
parent bdd13e9d815e0e04aaa193ea80a794d756b99f8f
Author: Brian Graham <brian@buildingbetterteams.de>
Date: Mon, 23 Mar 2026 19:53:31 +0100
Add engagement factor strip to papers table
V3 papers show a second DNA strip (purple tones) next to the
methodology strip (red-yellow-blue-green). 6 cells for practical,
surprise, fear, drama, demo, brand. Hover shows dimension name
and score. Blank for v2-only papers.
53 papers currently have both strips.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/explorer/src/data.ts b/explorer/src/data.ts
@@ -29,6 +29,7 @@ export interface PaperIndex {
doi: string;
code_url: string | null;
dna: (number | null)[] | null;
+ engagement: (number | null)[] | null;
}
export interface PaperDetail extends PaperIndex {
diff --git a/explorer/src/views/papers.ts b/explorer/src/views/papers.ts
@@ -10,6 +10,10 @@ const DNA_CATS = [
'human', 'cost',
];
+const ENG_DIMS = [
+ 'practical', 'surprise', 'fear', 'drama', 'demo', 'brand',
+];
+
function scoreColor(s: number): string {
if (s < 30) return 'var(--red)';
if (s < 50) return 'var(--yellow)';
@@ -25,12 +29,23 @@ function dnaCellColor(v: number | null): string {
return '#20a060';
}
-function renderDna(dna: (number | null)[] | null): string {
+function engCellColor(v: number | null): string {
+ if (v === null) return 'var(--border)';
+ if (v === 0) return '#555';
+ if (v === 1) return '#7060a0';
+ if (v === 2) return '#9070d0';
+ return '#b080ff';
+}
+
+function renderDna(dna: (number | null)[] | null, engagement: (number | null)[] | null): string {
if (!dna) return '';
- const cells = dna.map((v, i) =>
+ const methodCells = dna.map((v, i) =>
`<span class="dna-cell" style="background:${dnaCellColor(v)}" title="${DNA_CATS[i]}: ${v !== null ? v + '%' : 'N/A'}"></span>`
).join('');
- return `<span class="dna-strip">${cells}</span>`;
+ const engCells = engagement ? engagement.map((v, i) =>
+ `<span class="dna-cell" style="background:${engCellColor(v)}" title="${ENG_DIMS[i]}: ${v !== null ? v + '/3' : '?'}"></span>`
+ ).join('') : '';
+ return `<span class="dna-strip">${methodCells}</span>${engCells ? `<span class="dna-strip" style="margin-left:3px">${engCells}</span>` : ''}`;
}
export async function renderPapers(app: HTMLElement) {
@@ -67,7 +82,7 @@ export async function renderPapers(app: HTMLElement) {
{ key: 'title', label: 'Title', render: p => p.title.length > 60 ? p.title.slice(0, 57) + '...' : p.title, sortValue: p => p.title },
{ key: 'year', label: 'Year', render: p => String(p.year || ''), sortValue: p => p.year || 0 },
{ key: 'score', label: 'Score', render: p => p.score != null ? `<span style="color:${scoreColor(p.score)}">${p.score}%</span>` : '<span style="color:var(--gray)">--</span>', sortValue: p => p.score ?? -1 },
- { key: 'dna', label: 'Profile', render: p => renderDna(p.dna), sortValue: p => p.score ?? -1 },
+ { key: 'dna', label: 'Profile', render: p => renderDna(p.dna, p.engagement), sortValue: p => p.score ?? -1 },
{ key: 'archetype', label: 'Type', render: p => p.archetype ? `<span class="archetype ${p.archetype}">${p.archetype}</span>` : '<span style="color:var(--gray)">--</span>', sortValue: p => p.archetype || '' },
];
diff --git a/scripts/build-explorer-data.py b/scripts/build-explorer-data.py
@@ -404,6 +404,10 @@ def build():
"code_url": code_url,
"dna": dna,
"hn_points": hn_data.get("top_points", 0),
+ "engagement": [scan.get("engagement_factors", {}).get(d, {}).get("score") for d in
+ ["practical_relevance", "surprise_contrarian", "fear_safety",
+ "drama_conflict", "demo_ability", "brand_recognition"]
+ ] if scan.get("engagement_factors") else None,
}
papers_index.append(index_entry)
@@ -1121,6 +1125,7 @@ def build():
"code_url": None,
"dna": None,
"hn_points": 0,
+ "engagement": None,
})
write_json(OUTPUT_DIR / "dashboard.json", dashboard)