Skip to content

Latest commit

 

History

History
278 lines (222 loc) · 16.8 KB

CLAUDE.md

File metadata and controls

278 lines (222 loc) · 16.8 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

Academic lab website for the Lee Optimization Group (LOG) at POSTECH, served by GitHub Pages at opt.postech.ac.kr. Content and design are separate: content is data in data/, design is Jinja templates in layout/, and tools/build.py renders them into _site/. .github/workflows/deploy.yml builds and deploys on every push to main (Pages source must be "GitHub Actions"). _site/ is output — never edit it, never commit it. The root README.md maps every kind of edit to its file.

python3 tools/build.py            # build into _site/
python3 tools/build.py --check    # validate data/ only (exit 1 on errors)
python3 tools/build.py --serve    # build and serve on http://localhost:8000

Pages

Template Purpose Data
layout/index.html Home — lab intro, recent news data/news/
layout/news.html News list (linked from the home page) data/news/
content/research.html Research areas —
layout/publications.html Paper list data/publications/
layout/group.html Members, gallery preview, alumni data/members/, data/gallery/
layout/gallery.html Lab photos data/gallery/
layout/photo.html Single-photo viewer (photo.html?image=stories/…) —
content/hiring.html Open positions —
content/contact.html Contact info —

Pages built from data have their own layout in layout/. Pages that are just text (content/*.html) are plain HTML for inside <main> — no template code — wrapped by layout/page.html; their CSS is layout/styles/<page>.css and any extra script layout/scripts/<page>.js (after the shared layout/scripts/drawer.js). Their title is their nav label in data/site.toml. Every page extends layout/base.html, which holds the head, header/nav, footer and mobile drawer. Nav items, footer logos and the lab name come from data/site.toml.

Content lives in data/ — never in templates

Each directory in data/ is one database: its entries, a config.toml of presentation settings, and a README.md on how to add an entry. Read that README before adding or changing content.

Database Entries Notes
data/news/ <year>.yaml: items keyed by idx (39:) with date, text (one paragraph of Markdown), optional paper Higher idx = newer, unique across years; a repeated key is an error. Home page shows the newest home.count.
data/publications/ one papers.bib; entry order = display order within a heading Headings: is_preprint, then year (newest first), then is_previous. News refers to entries as @key (@lee26fresco).
data/members/ members.yaml (members: and alumni:, each person keyed by tag) + photos/ The tag is the person's id everywhere (@tag).
data/gallery/ gallery.yaml (photos keyed by idx, highest first) + photos/ Thumbnails are generated by the build; never commit thumbnails.

The build validates all of it (file names, required fields, unknown fields, missing photos) and refuses to build on errors.

Numbers that used to be hard-coded in page scripts (news shown/added per click, home news count, gallery preview page size) come from the config.toml files — change them there, not in the template.

Rendering rules applied by the build:

  • Markdown links to http(s):// get target="_blank" rel="noopener"; relative links stay in the same tab. The same holds for paper links.
  • Text is HTML-escaped.

Published paths are stable public URLs and must not change: gallery photos are served at stories/, thumbnails at stories/thumbs/, member photos at group_profile/ (see PUBLISH in tools/build.py). static/ is copied to the site root as is, so static/research_focus/ is served at research_focus/.

People (@tags) and member faces

Every data file starts with a comment listing every field of an entry.

Every person in data/members/members.yaml (members and alumni) is keyed by their tag. News text and BibTeX author fields refer to lab people only by tag (@hyunjijung); plain names are plain text. In news a tag renders as the person's short name (default: first name), in author lists as the full name. Unknown tags fail the build.

tools/build.py renders small rounded-square faces of current members at build time (alumni tags give the name without a face):

  • News (news page, home page): under each item's date — the in-lab authors of the papers it refers to — its paper field, then links written [paper](@shin23closer), which the build points at the entry's paper URL — then members @tagged in the text; up to faces.max (3), then +N.
  • Publications: before each tagged current member in .paper-authors.

Nothing is inferred from names or links. Each face links to the member's url (new tab) if set, otherwise to group.html#<photo file name>; group.html assigns those ids at load time.

Architecture

CSS is inline in each page's <style>, assembled by base.html from:

  1. layout/partials/chassis.css — reset, layout tokens (:root), body, header, nav
  2. the page's {% block style_page %}
  3. layout/partials/footer.css — footer, footer logos, menu button
  4. the page's {% block style_after_footer %} (holds the page's @media (max-width: 900px))
  5. layout/partials/drawer.css — mobile drawer
  6. the page's {% block style_after_drawer %}

This order is the order the pages always had their rules in, so cascade behaviour is unchanged. A visual change that applies site-wide goes in a partial or in base.html, once. A change to one page goes in that page's template.

Asset directories:

  • static/logo/ — logos (PNG/SVG); footer logos are listed in data/site.toml
  • static/lab_photo/ — home page hero photo
  • data/gallery/photos/ — gallery photos, published at stories/
  • data/members/photos/ — member headshots (filename = person's name slug), published at group_profile/
  • static/research_focus/ — research topic icons, used by content/research.html

Images

Do not resize or compress images by hand. Drop the original in, commit, and the pre-commit hook does it — resizing, re-encoding, stripping EXIF (which also removes GPS coordinates from lab photos), and updating the data file that names the image if the extension changes. Gallery thumbnails are not stored: the build crops them from the photos (data/gallery/config.toml), with the same ImageMagick command the hook used to run.

tools/setup-hooks.sh              # once per clone — enables the hook
tools/optimize-images.sh          # optimize everything that needs it
tools/optimize-images.sh --check  # report only, change nothing

The hook also runs tools/build.py --check. Both scripts run on the bash 3.2 that ships with macOS. Requires ImageMagick (apt install imagemagick / brew install imagemagick); the hook refuses the commit if it is missing rather than letting a 10MB camera original into history; git commit --no-verify bypasses it.

Targets are ~3x the CSS display size, so images stay sharp on retina screens:

Directory Max long edge Format Displayed at
data/gallery/photos/ 2560px JPEG q82 click-through full view
thumbnails (build) 600px square JPEG q80 112–180px grid tiles
static/lab_photo/ 1600px JPEG q85 ≤800px hero
data/members/photos/ 512px JPEG q85 140px avatar
static/research_focus/ 500px keep (PNG stays PNG — line art) ~124px card
static/logo/ untouched — logos must stay crisp

Processed files carry a log-opt-v1 marker in their image comment, so re-running is safe — already-optimized files are skipped, never re-compressed. To force a full re-pass after changing the rules, bump MARKER in tools/optimize-images.sh.

Gallery photos are stored as lowercase .jpg; the optimizer normalizes .png/.jpeg/ .JPG and rewrites the reference in the data file for you.

Scratch files: static/index_v1.html is a redirect kept for old links — do not modify unless explicitly asked.

Layout Tokens (read this before changing any spacing)

layout/partials/chassis.css holds the :root block of CSS custom properties, shared by every page. This block is the single source of truth for spacing — all chassis rules (.inner, header, .lab-name, nav, footer, section headings, body text) reference it via var(...) instead of literal pixel values.

Token Value Controls
--content-max 800px .inner max width
--page-pad-top / --page-pad-x / --page-pad-bottom clamp() .inner padding
--header-pad-bottom / --header-gap 28px / 40px header padding + gap to <main>
--lab-name-gap 18px lab name → nav
--nav-gap clamp(10px, 3vw, 24px) space between nav links
--section-gap 40px space above a section heading
--heading-gap 14px space below a section heading
--para-gap 14px space between stacked paragraphs
--footer-gap / --footer-pad-top 52px / 20px footer offset + padding
--footer-logo-gap / --footer-logo-h 14px / 28px footer logo row
--text-body / --leading-body 0.93em / 1.85 body text size + line height
--rule-color #e2e6f0 header/footer hairlines

Rules for editing:

  • To change spacing site-wide, edit the token value in layout/partials/chassis.css.
  • Never reintroduce a literal px for anything a token already covers.
  • The @media (max-width: 900px) block redefines tokens on :root rather than re-declaring .inner / header / .footer-logos img. Add responsive spacing the same way.
  • Section headings (h2, h3, .year-divider, .news-year) all use margin-top: var(--section-gap) + margin-bottom: var(--heading-gap), paired with a :first-of-type { margin-top: 0 } rule so the first heading sits flush.

Design Conventions (must be preserved)

  • Background: #ffffff
  • Primary color: #1B3A8A (deep blue); hover/accent: #3B6FD4
  • No top rule — the 3px gradient bar was deliberately removed (6d008de, a3a85de); do not reintroduce it
  • Heading font: EB Garamond (serif), weight 500
  • Body font: Inter (sans-serif), weights 300/400/500/600
  • Max content width: 800px, centered via .inner (--content-max)
  • Padding: clamp() for responsive spacing (--page-pad-*)
  • Text color: #111 (headings), #374151 (body), #6b7280 (muted)
  • Links: #1B3A8A, underline on hover only

Should-Be-Satisfied Checklist

When adding or modifying any page, verify all of the following:

Consistency

  • Navigation comes from data/site.toml via base.html — never hand-write nav in a page template
  • Drawer nav has both nav a.active and .nav-drawer a.active styling
  • Lab name / logo links back to index.html on all inner pages
  • Favicon (logo/log_logo.png) is referenced in <head>
  • Google Fonts <link> for EB Garamond + Inter is present
  • Page <title> follows the pattern Page Name | Lee Optimization Group (set by {% block title %})
  • python3 tools/build.py --check passes, and the built page was checked in a browser (--serve)

Style

  • No inline styles that override the established color palette
  • No new fonts introduced without approval
  • New sections reuse existing CSS classes (.inner, .news-item, etc.) before adding new ones
  • Responsive: layout must not break on mobile (≤ 480px) or tablet (≤ 768px)
  • Font sizes must not shrink on small screens — never use body { font-size: 14px } or reduce font-size for text elements inside @media queries
  • Lab name font size is fixed at 2.8em — do not use clamp() with a viewport unit for .lab-name, and do not override it in media queries
  • Body text uses the tokens — p, .intro, .news-content, list items and equivalent paragraph elements must use font-size: var(--text-body) and line-height: var(--leading-body), never literal values
  • Spacing uses the tokens — no literal px for page padding, header/footer offsets, section-heading margins, or paragraph gaps; see the Layout Tokens section
  • Shared CSS stays in layout/partials/ — never copy a shared rule into a page template
  • Logo card containers use flex-wrap: wrap so logos reflow to multiple rows on narrow screens instead of shrinking — do not set flex-wrap: nowrap or force images to scale down inside logo cards (.sponsor-logos, .collab-logos)
  • Members grid keeps fixed avatar size — member photos must not shrink on small screens; reduce the number of columns instead (4 → 3 → 2 → 1) and keep visible spacing between cards
  • Gallery page uses dynamic grid — .gallery-grid should use repeat(auto-fit, minmax(..., 1fr)) with consistent gap, so tile count adapts smoothly to viewport width

Content

  • External links open in a new tab (target="_blank") and have rel="noopener"
  • Images have descriptive alt text
  • Large images use loading="lazy"
  • Images were never hand-resized — the pre-commit hook handles it; see Images above
  • No thumbnails committed — the build generates them from data/gallery/photos/
  • No content in layout/ — news, papers, members and photos are entries in data/; the text of research, hiring and contact is in content/
  • Dates are written consistently: MMM YYYY (e.g., Mar 2025)
  • Paper/thesis links use lowercase labels: [paper], [thesis], [code], [slides]

Code Quality

  • No JavaScript frameworks — plain HTML/CSS/JS; the only build step is tools/build.py (Python + Jinja)
  • No unused CSS rules left behind after edits
  • HTML is valid and properly nested
  • No hardcoded absolute URLs for internal pages (use relative paths)

Design Inspiration & Originality

The professor wants the site to have uniqueness and originality. The references below are all personal academic websites — we are a lab website, so we do not copy their structure directly. Instead, extract specific UI patterns and adapt them to a multi-person lab context.

Reference Sites

Site Owner What to borrow
arkitus.com/research Ali Eslami Research sections organized by topic/category with thumbnail images per paper; anchor-based in-page navigation
alnurali.com/publications Alnur Ali Representative publications panel (curated cards with image + abstract excerpt) before the full list; scroll progress indicator; dashed→solid border hover on nav links
theis.io Lucas Theis Ultra-minimal aesthetic — no decorative borders or chrome; content is the interface; publication entries as clean typographic blocks without explicit card boxes
pluskid.org Chiyuan Zhang Restrained, accessibility-first layout; understated horizontal nav; personality through simplicity

Key Patterns to Adopt (adapted for lab context)

  • Representative publications panel (publications.html): Show 3–5 highlighted papers as visual cards (thumbnail + title + one-line summary) at the top, before the full chronological list. Inspired by alnurali.com.
  • Research organized by topic (research.html): Each research area has a clear category label and an associated paper thumbnail. Already partially done — reinforce with stronger visual separation. Inspired by arkitus.com.
  • Scroll progress indicator: A thin bar at the top of the page (below the gradient rule) that fills as the user scrolls. Useful on long pages (publications.html, group.html). Inspired by alnurali.com.
  • Publication entries as typographic blocks: On the full publication list, avoid heavy box borders. Use whitespace and typographic weight to separate entries instead. Inspired by theis.io.
  • Nav hover treatment: Consider dashed underline → solid underline on hover for nav links (subtle, distinctive). Inspired by alnurali.com.

What NOT to import

  • Single-column personal bio layout — we need multi-section lab structure
  • Profile photo as hero — we use the lab group photo instead
  • No-navigation style (theis.io) — our site has 6 distinct pages that need nav
  • Heavy animations or JavaScript frameworks — keep plain HTML/CSS

Commit Style

Follow the existing prefix convention:

  • ADD: — new content (people, papers, news items, logos)
  • STYLE: — visual/CSS changes
  • PERF: — performance improvements
  • FIX: — bug fixes
  • REFACTOR: — structural changes with no visual effect

Do not add Co-Authored-By or any Claude attribution in commit messages.