Goal: (a) one reusable template for future project pages, and (b) a
staged plan to converge the 14 existing projects/*-webpage submodules
onto it. Target style = visual.cs.brown.edu (these pages are served
under /projects/), with a CSS-variable layer so a jamestompkin.com
skin is a token swap, not a rewrite.
14 pages, five disjoint template families, no shared base:
| Family | Pages | Stack | Notes |
|---|---|---|---|
| “jht” serif | articulations, decoupledstyledescriptors, gaussigan, matryodshka, shapefromtracing | local fonts/normalize/main/jht.css, EB Garamond, XHTML 1.0, .right-column |
Simple single-column. Dead ga.js/analytics.js snippets. decoupled pulls CDN jQuery 1.9.1 over http. |
| Bootstrap 3 “aaargh” | lightfielddepth, social-video-verification | BS 3.4.1 + jQuery 3.5.1, shared styles.css, self-hosted Aaargh.ttf |
social-video also loads MathJax 2.7.5 + code-prettify (rawgit). |
| Bootstrap 5 | diffdiffdepth, incompletedepth, taxfreegan | BS 5.1.0 / 5.2.3 (versions differ) | Only these + sterkfontein are responsive. diffdiffdepth uses BS grid but forgot the viewport meta. |
| Inline red ToF | ftorf, gftorf, semantic-attention-flow-fields | zero deps, all CSS+JS inline, system-ui, red rgb(213,28,37) |
Large bespoke video-grid engines (100+ <video> tags built in JS). |
| Bespoke modern | sterkfontein | CSS custom properties, Typekit diw5pgv, dark “cave” theme |
Already responsive, tokenized, dark-mode, right fonts. The proto-template. |
Consistent problems across the set:
<meta viewport> (sterkfontein, taxfreegan, incompletedepth). Rest are fixed-width desktop.#900020, rgb(250,20,30), rgb(213,28,37), darkred.<pre> vs <div class="citation"> vs <h2>BibTex</h2>).Neither the brownvc site nor jamestompkin.com is matched by any of them.
| Axis | visual.cs.brown.edu (primary target) | jamestompkin.com (secondary) |
|---|---|---|
| Framework | Bootstrap 5 + FontAwesome | none (hand-rolled SCSS) |
| Body font | freight-sans-pro (Typekit) |
EB Garamond (self-hosted) |
| Heading font | minion-3 (Typekit) |
EB Garamond |
| Accent (light/dark) | #C00404 / #ff6b6b |
#900020 / #d35a72 |
| Colour system | literal hex, no tokens | CSS custom properties |
| Dark mode | data-bs-theme + prefers-color-scheme |
data-theme + prefers-color-scheme |
| Content width | Bootstrap container ~1140px | 620px column |
localStorage key |
theme |
theme (same — toggle logic is portable) |
Both use the same localStorage['theme'] key and pre-paint pattern, so
dark-mode toggle logic ports cleanly. sterkfontein already uses the lab
Typekit kit, so the fonts are a solved problem.
#C00404). Tokenised so jamestompkin’s maroon/EB-Garamond is a variable swap.visual.cs.brown.edu/projects/shared/project.css. All pages <link> the same absolute URL; edit once, every page updates.diw5pgv (already loaded by sterkfontein).data-theme and data-bs-theme on <html> from one pre-paint script.jamestompkin/webpage/assets/projects/ (they link the shared CSS cross-origin by absolute URL). lightfieldpainting and table are explicitly out of scope. No page is preserved verbatim.Two hosted files + one skeleton. Everything self-contained.
projects/shared/
project.css # all styling, CSS custom properties, dark mode, responsive
project.js # injects the BVC brand bar, populates [data-logos] strips,
# loads the parent's live js/theme.js, videoGrid() helper
logos/ # canonical institution/funder logo files (one copy, all pages)
template.html # the skeleton authors copy into a new *-webpage repo
demo/index.html # kitchen-sink review page (one instance of every COVERAGE row)
COVERAGE.md # the feature matrix / done-definition
Auto-sync architecture (BUILT 2026-07-03): shared chrome lives in
hosted files, never in pages. The brand bar is injected by project.js
(one copy; edit once, all pages update on next load — no rebuilds); the
theme toggle loads the parent site’s own live js/theme.js so its
behaviour/icons cannot drift; institution logos are named via
data-logos="brown-cs nsf …" and resolved by a registry in project.js
against shared/logos/ (replace a file once → every page updates).
Per-logo dark-mode strategies: light pill (default), .dark-invert
(monochrome), or a .light-only/.dark-only variant pair. Residual
manual point, stated honestly: a parent-site nav redesign or a new
social network still needs one edit to project.js/css — one file, not
16 pages; full zero-touch would require the parent emitting a canonical
bar component, which static hosting doesn’t give us.
project.css):root{
--font-body: "freight-sans-pro", Arial, sans-serif;
--font-head: "minion-3", Georgia, serif;
--accent: #C00404; /* jamestompkin skin: #900020 */
--ink: #212529;
--ink-muted: #6c6c6c;
--bg: #ffffff;
--bg-soft: #f5f5f5; /* teaser/hero + code blocks */
--border: #e2e2e2;
--measure: 720px; /* readable content column */
}
:root[data-theme="dark"], [data-bs-theme="dark"]{
--accent:#ff6b6b; --ink:#e8e8e8; --ink-muted:#a0a0a0;
--bg:#1c1c1c; --bg-soft:#262626; --border:#383838;
}
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]){ /* same dark values */ } }
template.html) — the canonical section order<head>
<meta viewport> ← every page, no exceptions
Typekit diw5pgv + project.css
pre-paint theme script (inline, before body)
<body>
<main class="project">
<h1 class="project-title"> Title
<p class="project-venue"> Venue + year (+ Oral/Highlight)
<ul class="author-list"> Authors w/ <sup> affiliation markers
<p class="affiliations"> 1 Brown 2 Meta …
<nav class="resource-row"> Paper / arXiv / Code / Video / Data buttons (shared SVG/text, no per-page PNG icon-swaps)
<figure class="teaser"> img or autoplay-muted-loop mp4
<section class="abstract">
<section class="method"> figures
<section class="results"> video/gif grids (optional project.js helper)
<section class="video"> one embed convention (local mp4 preferred; iframe allowed)
<pre class="citation"> ONE BibTeX convention
<section class="acknowledgements">
<footer class="logos"> institution logo strip
<script src="project.js">
Components authors reuse instead of reinventing: .resource-row
buttons, .author-list/.affiliations, .teaser, .citation,
.logos. The heavy results video grids stay optional — pages that
need them include the project.js videoGrid() helper (extracted from
the ftorf/gftorf/saff engines, deduped to one copy).
Seed it from sterkfontein — it already has the tokens, responsive
layout, dark mode, viewport meta, and the right fonts. Strip its
bespoke “cave” colours back to the neutral token defaults and that is
project.css.
Per-page work = swap <head> to the shared CSS + pre-paint script, wrap
existing content in the standard sections, delete the old framework/CSS,
add viewport meta, normalise BibTeX + author markup, strip dead
analytics. Content and assets are kept; only the shell changes.
Batch order (easy → hard, validate the template early):
project.css + template.html. (0.5 day)ga.js. (1 day)videoGrid() helper. Most effort, least structural risk. (1–1.5 days)jamestompkin/webpage/assets/projects/). Profile these two first (not yet surveyed in depth; tupi still loads per-page Bootstrap), add any new content types to the coverage matrix (§7), then convert. They link the shared CSS by absolute URL. (0.5 day)Rough total: ~4.5–5.5 focused days, fully parallelisable across pages once step 2 locks the template.
Per-page checklist (same every page):
<head>: viewport meta, Typekit kit, <link> shared project.css, pre-paint theme script<pre class="citation">.author-list + .affiliations.logos footerEach *-webpage is its own repo; the parent vcwebpage.github.io
pins a commit. So each conversion is: edit inside the submodule →
commit + push the submodule → git add projects/<name> in the parent to
bump the pointer → commit parent. Do NOT edit submodule files and commit
only in the parent; the pointer would dangle.
shared/project.css|js in the parent repo (not a submodule) so it deploys at visual.cs.brown.edu/projects/shared/… and every submodule links the stable absolute URL.<style> block for genuinely page-specific figures.The link must be an absolute URL (https://visual.cs.brown.edu):
submodule pages are also served standalone at `brownvc.github.io/
` + tokens) - **two papers on one page** (gaussigan: 2 titles, 2 abstracts, 2 BibTeX) - multiple BibTeX blocks (lightfielddepth ×3) - resource-row buttons (replacing hover-swap PNG icon rows) - dataset download panel with option tabs (sterkfontein Globus) - related projects / presentations lists - notes/errata section - author superscript affiliations; venue badge incl. Oral/Highlight - logo strips up to 5 institutions - (+ any new types from profiling criteriasliders/tupi in batch 6) 2. **Kitchen-sink demo page** (`shared/demo/index.html`): one page containing **one instance of every matrix row**, built with the template. This is the review gate: sign off the demo in light + dark × mobile + desktop **before any batch conversion starts**. Anything the demo can't express = a template gap found before it costs 14 conversions. Then per converted page: before/after screenshots at the four combinations, checked against the matrix rows that page uses. The matrix doubles as the done-definition — a page is converged when every row it needs renders correctly under the template.