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