Project-page template + convergence plan

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.


0. What the survey found

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:

Neither the brownvc site nor jamestompkin.com is matched by any of them.

The two reference design systems (what to match)

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.


1. Decisions (CONFIRMED by James, 2026-07-03)

  1. Target style → brownvc (Minion 3 / Freight Sans, #C00404). Tokenised so jamestompkin’s maroon/EB-Garamond is a variable swap.
  2. Framework → none. Self-contained CSS with custom properties; drops into any host.
  3. Shared CSS, hosted once → visual.cs.brown.edu/projects/shared/project.css. All pages <link> the same absolute URL; edit once, every page updates.
  4. Fonts → the existing lab Typekit kit diw5pgv (already loaded by sterkfontein).
  5. Dark mode → set both data-theme and data-bs-theme on <html> from one pre-paint script.
  6. Scope → the 14 brownvc submodules + criteriasliders and tupi from 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.

2. (a) The template

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.

Tokens (top of 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 */ } }

Skeleton (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.


3. (b) Convergence plan

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):

  1. Seed — turn sterkfontein into project.css + template.html. (0.5 day)
  2. Pilot (1 page per family) — convert one jht page (matryodshka) and one Bootstrap page (taxfreegan). Proves the template absorbs both a serif single-column and a grid layout before committing to batches. Adjust template from what breaks. (0.5 day)
  3. jht serif batch — articulations, decoupledstyledescriptors, gaussigan, shapefromtracing. Same transform ×4; do one carefully, replicate. Kill the http jQuery 1.9.1 and dead ga.js. (1 day)
  4. Bootstrap batch — diffdiffdepth, incompletedepth, lightfielddepth, social-video. Drop BS3/BS5 + jQuery; social-video keeps MathJax only where it has real math. (1 day)
  5. Heavy video batch — ftorf, gftorf, semantic-attention-flow-fields. Reskin the shell to the template; keep each page’s video-grid engine but point it at the shared videoGrid() helper. Most effort, least structural risk. (1–1.5 days)
  6. jamestompkin batch — criteriasliders, tupi (in 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):


4. Execution logistics (submodules)

Each *-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.


5. Linking back to the BVC main page — options

The link must be an absolute URL (https://visual.cs.brown.edu): submodule pages are also served standalone at `brownvc.github.io/

-webpage`, where a relative link would break. | Option | What it looks like | Pros | Cons | |---|---|---|---| | **A. Slim brand bar (recommended)** | A thin dark strip (`#212529`, matching the parent's `#header`/`#sticky-nav`) across the top: "Brown Visual Computing" wordmark in Minion 3 linking home, theme toggle on the right. ~40px tall. | Instantly reads as the lab site; gives the theme toggle a natural home; one shared component in `project.css`. | Takes vertical space; slight "chrome" on an otherwise minimal page. | | B. Text breadcrumb | `Brown Visual Computing / Projects` as a small muted line above the title. | Near-zero visual weight. | Weak brand signal; theme toggle needs a separate floating home. | | C. Footer-only | Lab wordmark/link in the `.logos` footer strip. | Zero header chrome. | Invisible until scroll-end; doesn't help orientation. | **CONFIRMED: A** (James, 2026-07-03), with C additionally for free (the Brown logo is in the footer strip anyway). The bar is one `
` element in the skeleton — trivially removable per page if ever needed. ## 6. Staging — review without breaking anything The deployment chain protects us: the live site only changes when the **parent repo's main** advances a submodule pointer. Work inside submodules is invisible until then. 1. **`shared/` lands first, on parent main.** Purely additive — nothing references it yet, so it can deploy immediately. This also gives every branch preview the real hosted CSS URL. 2. **Each submodule converts on a branch** (`template`), pushed to its own repo. Live site: untouched (parent still pins the old commit). 3. **Parent gets a `template-preview` branch** that bumps the pointers to the submodule `template` branches' commits. This branch is the reviewable, reproducible "staging state" — check it out, `git submodule update`, `bundle exec jekyll serve`, review everything at `localhost:4000/projects/...`. 4. **Rollout is per-page and per-page revertible:** merge one submodule's `template` → its main, bump that one pointer in parent main, deploy. A bad page = reset one pointer, no other page affected. 5. criteriasliders/tupi follow the same shape in the jamestompkin repo: a branch there, previewed with that site's local Jekyll. No staging server needed; local Jekyll + the preview branch covers review. (If a shareable URL is ever wanted, point a throwaway `brownvc/staging` Pages repo at the preview branch — decide later.) ## 7. Coverage review — proving the template supports everything Two artifacts, built in this order: 1. **Feature matrix** (`shared/COVERAGE.md`): rows = every content type found in the survey; columns = the 16 pages; cells = which page needs it. Rows so far: - teaser: static image / autoplay-loop mp4 / GIF - embeds: YouTube iframe, YouTube-nocookie, OneDrive (slides + video), Google Slides - local mp4 with poster + controls - JS video grids with playback-rate controls (ftorf/gftorf/saff engine) - image carousel (lightfielddepth — Bootstrap carousel; replace with CSS scroll-snap row, no JS) - inline math (social-video — MathJax; keep MathJax only on that page) - code blocks (sterkfontein CLI/SDK; social-video prettify → plain `
` + 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.