Lab website for the AI Verification & Validation Lab at ai-vnv.kfupm.io.
Built with Jekyll. Hosted on GitHub Pages.
bundle install
bundle exec jekyll serve
# Open http://localhost:4000_config.yml # Jekyll configuration
_data/ # YAML data files (publications, research areas, team, news)
_includes/ # HTML partials (head, nav, footer, seo)
_layouts/ # Page layouts (default, page)
_tikz/ # TikZ .tex source files for figures
_julia/ # Julia scripts for generated SVG/PDF figures
_scripts/ # Build scripts (build-tikz.sh, build-julia.sh)
assets/css/ # Stylesheets (main.css, apply.css, deadlines.css, review.css, post.css)
assets/js/ # JavaScript (main.js, apply.js, apply-i18n.js, deadlines.js, review.js)
assets/img/ # Images and generated SVG patterns
pdfs/ # Talk slides and paper PDFs
index.html # Home page
research.html # Research areas
team.html # Team members
publications.html # Publications
apply.html # Application form
deadlines.html # AI deadlines calendar with submission form
review.html # Candidate review dashboard (login-gated)
contact.html # Contact info
blog.html # Blog index
resources.html # Interactive notebooks and tools
CNAME # Custom domain
TikZ source files live in _tikz/. To compile them into PDF, PNG, and SVG:
# Build all figures
./_scripts/build-tikz.sh
# Build a specific figure (name without .tex extension)
./_scripts/build-tikz.sh research-overviewOutputs:
_tikz/<name>.pdf-- vector PDF (source of truth)assets/img/<name>.png-- 300 DPI raster for webassets/img/<name>.svg-- scalable vector for web
Requires: pdflatex, pdftoppm, pdftocairo (from poppler).
Julia scripts live in _julia/ (with its own Project.toml). Some use GMT.jl for map figures, others generate SVG directly.
# Build all Julia/GMT figures (PDF -> PNG/SVG pipeline)
./_scripts/build-julia.sh
# Build a specific GMT figure (name without .jl extension)
./_scripts/build-julia.sh supply_chain_networkScripts that output SVG directly (no PDF intermediate):
cd _julia && julia --project=. surface_terrain.jl
cp _julia/surface_terrain.svg assets/img/surface-terrain.svg
cd _julia && julia --project=. pattern_desert.jl
cp _julia/pattern_desert.svg assets/img/pattern-desert.svg
cd _julia && julia --project=. pattern_footer.jl
cp _julia/pattern_footer.svg assets/img/pattern-footer.svgCurrent Julia figures:
supply_chain_network.jl-- critical mineral supply chain map (GMT.jl)surface_terrain.jl-- 3D wireframe terrain with path selection and robot agentspattern_desert.jl-- desert terrain background pattern for hero sectionpattern_footer.jl-- terrain background pattern for footer
Requires: julia, and pdftoppm/pdftocairo (from poppler) for GMT figures.
Public deadline tracker at /deadlines showing upcoming AI conference, workshop, grant, and journal deadlines. Features:
- Card grid with countdown timers, category filters, and text search
- Calendar export: download
.icsfiles or add individual events to Google Calendar - Community submissions: anyone can submit a deadline via the form; submissions require admin email approval (click-to-approve/reject links)
- Backend: reuses the same FastAPI backend and Google Sheet (separate "Deadlines" tab) as the application form
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/api/deadlines |
Public | List all approved deadlines |
POST |
/api/deadlines/submit |
CAPTCHA | Submit a new deadline (pending approval) |
POST |
/api/deadlines/subscribe |
Public | Subscribe to email reminder for a deadline |
GET |
/api/deadlines/approve/{id}?token= |
HMAC | Approve via email link |
GET |
/api/deadlines/reject/{id}?token= |
HMAC | Reject via email link |
GET |
/api/deadlines/ics?id= |
Public | Download .ics (single or all) |
GET |
/api/deadlines/gcal?id= |
Public | Redirect to Google Calendar add-event |
POST |
/api/admin/deadlines/seed |
Admin | Bulk-seed deadlines (auto-approved) |
To refresh the static deadlines JSON with the latest approved entries from the Google Sheet:
cd apply-backend
python3 scripts/export_deadlines.pyThis reads all approved deadlines from the Google Sheet, matches DROC conference ratings, and exports to assets/data/deadlines.json. The frontend loads this file for instant rendering, falling back to the live API for real-time updates.
To also refresh the DROC cache:
cd apply-backend
./scripts/refresh_site_data.shAfter exporting, commit the updated JSON to publish the changes:
git add assets/data/deadlines.json assets/data/deadlines.pretty.json
git commit -m "Update deadlines.json from Google Spreadsheet"
git push- Create "Deadlines" and "Subscriptions" tabs in the existing Google Sheet
- Set
APPROVAL_SECRET_KEYenv var in Cloud Run (random 32+ char string) - Deploy backend; sheet header rows are auto-created on first use
- Seed initial data:
curl -X POST .../api/admin/deadlines/seed -H "x-admin-key: ..." -H "Content-Type: application/json" -d '[...]'
Secure, login-gated review interface at /review for admin, faculty, and reviewers to browse and annotate candidate applications. Not linked in the main nav — reviewers receive the URL via invitation email.
- Role-based access: Admin (full control + decisions), Faculty & Reviewer (view + annotate)
- JWT authentication with bcrypt-hashed passwords and magic link sign-in
- Candidate browsing with filters (position type, status) and search
- PDF.js document viewer with page navigation and page tracking
- Collaborative notes with three types: General (candidate-level), Document (per-document with page reference), Field (per-field annotations)
- Admin decision workflow: accept/reject/waitlist/interview with email notifications
- User management: admin can invite reviewers via email
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/review/login |
Public | Authenticate, returns JWT |
POST |
/api/review/magic-link |
Public | Send magic link email |
POST |
/api/review/magic-link/verify |
Token | Verify magic link |
POST |
/api/review/set-password |
Token | First-time password setup |
POST |
/api/review/invite |
Admin JWT | Invite new reviewer |
GET |
/api/review/users |
Admin JWT | List all reviewers |
GET |
/api/review/candidates |
JWT | List candidates (filterable) |
GET |
/api/review/candidates/{id} |
JWT | Full candidate detail |
GET |
/api/review/candidates/{id}/notes |
JWT | All notes for a candidate |
POST |
/api/review/candidates/{id}/notes |
JWT | Add a note |
PUT |
/api/review/notes/{id} |
JWT | Edit own note |
DELETE |
/api/review/notes/{id} |
JWT | Delete own note |
POST |
/api/review/candidates/{id}/decide |
Admin JWT | Set decision |
- Add
JWT_SECRET_KEYenv var in Cloud Run (random 32+ char string) - Deploy backend — on first startup, admin user auto-seeded from
ADMIN_EMAILand magic link sent - Click the magic link, set password, then invite other reviewers from the dashboard
Uses two new Google Sheet tabs in the existing spreadsheet:
- ReviewUsers: user accounts (email, name, role, bcrypt hash, verified status)
- Reviews: annotations (review ID, application ID, reviewer, type, target, content, page ref)
Interactive Leaflet.js map at /minerals-viz/ showing global critical mineral flows (lithium, copper, cobalt, nickel, rare earths) with:
- Maritime-routed arcs color-coded by supply chain stage (raw materials, processed metals, finished goods)
- Animated material flow icons (rocks, alloy ingots, boxes)
- Information and money flow overlays with animated dotted arcs
- Major port and strait/canal markers
- Mineral filter pills, speed slider, dark/light theme toggle
- All legend items are clickable toggles
Data sources: USGS Mineral Commodity Summaries 2025, IEA, company reports. Data files in _data/minerals/.
-
Create the post in
_posts/with the naming conventionYYYY-MM-DD-slug.md. -
Add frontmatter with required fields:
--- layout: post title: "Post Title" subtitle: "One-line description" author: "AI V&V Lab" date: YYYY-MM-DD reading_time: 10 category: "Talk Summary" # or "Deep Dive", "AI Safety", etc. tags: [tag1, tag2] excerpt: "Short excerpt for blog list and SEO." image: /assets/img/<name>-og.png # social preview (1200x630, white bg) thumbnail: /assets/img/<name>-thumb.png # blog list card (480px, transparent) hero_image: /assets/img/<name>.png # post header (full size, transparent) hero_alt: "Description of the image" math: true # optional, enables KaTeX youtube: VIDEO_ID # optional, adds video player ---
-
Prepare the feature image (transparent PNG recommended). Each source image produces three variants:
File Purpose Spec <name>.pngPost header ( hero_image)Full size, transparent <name>-thumb.pngBlog list card ( thumbnail)480px max, transparent <name>-og.pngSocial sharing ( image)1200x630, white background # Place full-size image cp my-illustration.png assets/img/<name>.png # Generate 480px thumbnail (preserves transparency) sips -Z 480 assets/img/<name>.png --out assets/img/<name>-thumb.png # Generate OG social preview (1200x630, white background, centered) python3 -c " from PIL import Image img = Image.open('assets/img/<name>.png').convert('RGBA') canvas = Image.new('RGBA', (1200, 630), (255, 255, 255, 255)) iw, ih = img.size scale = min(1000/iw, 500/ih) nw, nh = int(iw*scale), int(ih*scale) img = img.resize((nw, nh), Image.LANCZOS) x, y = (1200 - nw) // 2, (630 - nh) // 2 canvas.paste(img, (x, y), img) canvas.convert('RGB').save('assets/img/<name>-og.png', quality=90) "
-
To embed a PDF viewer with download button, use the include:
{% include pdf-viewer.html src="/pdfs/my-slides.pdf" %} {% include pdf-viewer.html src="/pdfs/my-slides.pdf" label="Download Paper (PDF)" %} -
Add a news entry in
_data/news.ymlif applicable. -
Build and verify:
bundle exec jekyll serve # Check http://localhost:4000/blog/
Content and data are copyright AI V&V Lab. The site template is open for reference.