All routine content updates are made by editing JSON files in the content/ folder and running the build scripts. The site is rebuilt automatically by GitHub Actions every Sunday at 6 pm PT, or you can trigger it manually.
- Triggering a rebuild manually
- Site structure overview
- Content folder overview
- Adding a new group member
- Moving a group member to alumni
- Adding a news item
- Adding a project
- Adding a publication
- Modifying a research area
- Adding a course
- Adding a dissertation
- How the automation works
Option 1 — GitHub Actions: Go to Actions → Update Site → Run workflow in the GitHub repository.
Option 2 — Local: Run all build scripts from the repo root:
python3 scripts/build_home_page.py
python3 scripts/build_research_page.py
python3 scripts/build_research_subpages.py
python3 scripts/build_people_page.py| Page | URL | Description |
|---|---|---|
| Home | index.html |
Landing page with lab mission, research areas, and news strip |
| Who We Are | people.html |
Lab members grid; links to individual profile pages |
| Member profiles | people/{Name}.html |
Auto-generated profile pages |
| What We Do | work.html |
Landing page with Research and Teaching boxes |
| Research | research-areas.html |
Research areas, Previous Research, Dissertations strip |
| Research sub-pages | research/{area}.html |
Per-area page with overview, projects, publications |
| Teaching | teaching.html |
Course cards |
| Why We Do It | stories.html |
Lab stories page |
| Contact | contact.html |
Contact form and info |
All content you manually edit lives in content/:
| File | Controls |
|---|---|
content/members/members.json |
Active lab members (all roles except alumni) |
content/members/meagan.json |
PI profile — bio, education, title, links |
content/members/alumni.json |
Alumni |
content/members/images/ |
Member headshots |
content/news/news.json |
Front-page news strip |
content/projects/projects.json |
Lab projects |
content/publications/publications.json |
Lab publications |
content/research_areas/research_areas.json |
Research areas (name, description, overview, image) |
content/research_areas/ (images) |
Research area banner images |
content/teaching/teaching.json |
Courses taught by group |
content/dissertations/dissertations.json |
dissertation defenses |
-
Add a headshot to
content/members/images/named{FirstLast}.png(PascalCase, no spaces, no "Dr." — e.g.JaneSmith.png). Crop to a square; 400×400 px is ideal. -
Add an entry to
content/members/members.json:
{
"name": "Jane Smith",
"netID": "jsmith",
"email": "jsmith@stanford.edu",
"role": "phd student",
"bio": "One or two sentences about Jane's research focus.",
"research_areas": ["separations", "infrastructure planning"],
"scholar_url": "https://scholar.google.com/citations?user=XXXXXXXXX",
"linkedin": "https://www.linkedin.com/in/janesmith/",
"website": "",
"cv": ""
}Valid roles: postdoc · phd student · ms student · undergrad · staff · staff scientist · research engineer
The roles staff, staff scientist, and research engineer all appear under the Research Staff section. The card label will reflect the specific role (e.g. "Staff Scientist", "Research Engineer").
Valid research_areas IDs (must match id fields in research_areas.json):
separations · energy flexibility · infrastructure planning · water energy food policies
- Run
build_people_page.py. This regeneratespeople.htmland creates a profile page atpeople/JaneSmith.html.
- Remove the person's entry from
content/members/members.json. - Add an entry to
content/members/alumni.json:
{
"name": "Jane Smith",
"degree_year": "PhD 2025",
"placement": "Assistant Professor, MIT",
"scholar_url": "https://scholar.google.com/citations?user=XXXXXXXXX",
"linkedin": "https://www.linkedin.com/in/janesmith/"
}- Run
build_people_page.py. The person will move from the active members grid to the Alumni section, and their profile page will no longer be generated.
Edit content/news/news.json and prepend a new entry (most recent first):
{
"date": "June 2026",
"headline": "Paper accepted at Nature Water",
"organization": "Nature Portfolio",
"link": "https://doi.org/10.XXXX/XXXXX"
}Run build_home_page.py to update the front page news strip.
-
(Optional) Add a project image to
content/projects/images/. -
Add an entry to
content/projects/projects.json:
{
"id": "unique-project-id",
"title": "Project Title",
"team": ["netid1", "netid2"],
"description": "Long-form description of the project.",
"research_areas": ["separations", "infrastructure planning"],
"image": "content/projects/images/myproject.jpg",
"funding": ["NSF CBET Award #XXXXXXX"],
"links": [
{ "label": "Web Application", "url": "https://example.com" },
{ "label": "GitHub", "url": "https://github.com/we3lab/repo" }
]
}team: list ofnetIDvalues frommembers.json— headshots and profile links are resolved automatically.research_areas: list of areaidvalues fromresearch_areas.json— determines which research sub-pages show this project.funding: list of funding source strings displayed as a bulleted "Supported By" list.
- Run
build_research_subpages.pyandbuild_people_page.py.
Add an entry to content/publications/publications.json:
{
"title": "Full Publication Title",
"authors": "Smith, J., Adkins, C., & Mauter, M. S.",
"journal": "Environmental Science & Technology",
"year": 2025,
"doi": "10.1021/acs.est.5c00001",
"research_areas": ["separations"],
"team": ["cadkins"]
}doi: DOI without thehttps://doi.org/prefix. Used to build the clickable link on the card.research_areas: list of areaidvalues — determines which research sub-pages list this publication.team: list ofnetIDvalues — determines which member profile pages list this publication.
Run build_research_subpages.py and build_people_page.py.
Edit content/research_areas/research_areas.json. Each entry has:
{
"id": "separations",
"name": "Separations Process Modeling & Design",
"label": "Separations",
"file": "research/separations.html",
"active": true,
"image": "content/research_areas/reverse_osmosis.jpg",
"description": "Short description shown on cards.",
"overview": [
"First paragraph of the Research Overview section.",
"Second paragraph."
],
"archive_note": ""
}active: true— area appears in the main Research grid and the home page diamond.active: false— area appears in the "Previous Research" section with an archive note box.archive_note— message shown in the amber warning box on inactive area pages.label— short name used in the "What We Do" nav dropdown.
To add a new research area:
- Add an entry to
research_areas.jsonwith a uniqueidand afilepath (e.g.research/newarea.html). - Place a banner image in
content/research_areas/. - Run
build_research_page.py(updates the Research page) andbuild_research_subpages.py(creates the sub-page). - Add "What We Do" nav dropdown entries to all HTML files and build script templates — search for
research-areas.htmlto find all locations.
Run all build scripts after any change to research_areas.json.
Add an entry to content/teaching/teaching.json:
{
"course_code": "CEE 273X",
"name": "Course Title",
"quarters": ["Autumn 2026"],
"description": "Brief course description.",
"link": "https://explorecourses.stanford.edu/..."
}quarters: array of strings — each renders as a pill tag on the card.link: optional URL to the course listing or syllabus.
Run build_research_page.py to update the Teaching page.
Add an entry to content/dissertations/dissertations.json:
{
"title": "Full Dissertation Title",
"name": "Graduate Student Full Name",
"date": "May 26, 2026",
"link": "https://youtu.be/XXXXXXXXXXX"
}title: full dissertation title. Can be left empty ("") if not yet available.name: graduate's full name as it should appear on the card.date: defense date in any readable format —"May 26, 2026","June 2026", etc. Entries are sorted most-recent-first automatically.link: YouTube URL of the defense recording (upload as Unlisted). The video will be embedded directly on the page with a copy-link button. Leave empty ("") if no recording is available.
Run build_research_page.py to update the Dissertations strip on the Research page.
| Content file | Pages rebuilt | Script |
|---|---|---|
content/news/news.json |
index.html |
build_home_page.py |
content/research_areas/research_areas.json |
index.html, research-areas.html, teaching.html |
build_home_page.py, build_research_page.py |
content/teaching/teaching.json |
teaching.html |
build_research_page.py |
content/dissertations/dissertations.json |
research-areas.html |
build_research_page.py |
content/research_areas/research_areas.json |
research/*.html sub-pages |
build_research_subpages.py |
content/projects/projects.json |
research/*.html, people/*.html |
build_research_subpages.py, build_people_page.py |
content/publications/publications.json |
research/*.html, people/*.html |
build_research_subpages.py, build_people_page.py |
content/members/members.json |
people.html, people/*.html |
build_people_page.py |
content/members/alumni.json |
people.html |
build_people_page.py |
content/members/meagan.json |
people.html |
build_people_page.py |