Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/readme-screenshots.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Refresh README screenshots

# Commit curated browser-test images only for documentation updates.
on:
push:
branches:
- docs/project-readme
paths:
- README.md
workflow_dispatch:
inputs:
run_id:
description: Successful Interface browser preview run ID (optional)
required: false
type: string

permissions:
actions: read
contents: write

jobs:
curate:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
persist-credentials: true
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install image tools
run: python -m pip install --quiet pillow
- name: Retrieve real browser captures
env:
GH_TOKEN: ${{ github.token }}
GIVEN_RUN: ${{ inputs.run_id }}
shell: bash
run: |
set -euo pipefail
run_id="$GIVEN_RUN"
if [[ -z "$run_id" ]]; then
run_id="$(gh run list --workflow ui-preview.yml --status success --limit 1 --json databaseId --jq '.[0].databaseId')"
fi
[[ "$run_id" =~ ^[0-9]+$ ]] || { echo "No successful browser run found"; exit 1; }
echo "Source run: $run_id"
mkdir -p benchmarks/output/ui-preview
gh run download "$run_id" --name ramplotr-interface-preview --dir benchmarks/output/ui-preview
echo "RUN_ID=$run_id" >> "$GITHUB_ENV"
- name: Create image crops
run: python scripts/curate-readme-screenshots.py
- name: Record screenshot provenance
shell: bash
run: |
cat > docs/screenshots/README.md <<EOF
# Example screenshots

The screenshots are cropped from real Shiny browser tests, not mock-up renders.
Source: https://github.com/BiKC/RamplotR/actions/runs/$RUN_ID

- Overview and linked inspection: uploaded experimental 1CRN structure.
- Multi-chain sequence: 1BBB multimer.
- Prediction PAE: synthetic AlphaFold 2/ColabFold-style confidence test data (illustrative only).
- Ensemble: 1D3Z NMR multi-model structure.

To regenerate, extract a recent successful interface browser-test artifact
to benchmarks/output/ui-preview, then run
python scripts/curate-readme-screenshots.py.
Review the crops after layout changes.
EOF
- name: Commit screenshots to documentation branch
shell: bash
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add docs/screenshots/
if ! git diff --cached --quiet; then
git commit -m "docs: add current tested screenshots to the project README"
git push origin "HEAD:$GITHUB_REF_NAME"
fi
140 changes: 70 additions & 70 deletions README.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions docs/screenshots/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Example screenshots

The screenshots are cropped from real Shiny browser tests, not mock-up renders.
Source: https://github.com/BiKC/RamplotR/actions/runs/36488764177

- Overview and linked inspection: uploaded experimental 1CRN structure.
- Multi-chain sequence: 1BBB multimer.
- Prediction PAE: synthetic AlphaFold 2/ColabFold-style confidence test data (illustrative only).
- Ensemble: 1D3Z NMR multi-model structure.

To regenerate, extract a recent successful interface browser-test artifact
to benchmarks/output/ui-preview, then run
python scripts/curate-readme-screenshots.py.
Review the crops after layout changes.
Binary file added docs/screenshots/all-chains.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/ensemble.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/prediction-pae.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/residue-inspection.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions scripts/curate-readme-screenshots.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env python3
"""Curate real browser-test screenshots for the project README.

Input: screenshots in benchmarks/output/ui-preview from a successful UI run.
Output: cropped, optimised PNGs in docs/screenshots.

Review the resulting images before committing them after interface changes.
Prediction examples may use synthetic fixtures; captions must disclose this.
"""
from pathlib import Path
from PIL import Image

SOURCE = Path("benchmarks/output/ui-preview")
DEST = Path("docs/screenshots")

# Coordinates refer to the tested 1440x940 / 1366x900 full-page captures.
# Crop the relevant analysis panel, not the compact structure-input toolbar.
EXAMPLES = {
"overview.png": ("desktop-loaded.png", (355, 232, 1405, 1205)),
"residue-inspection.png": ("desktop-residue-zoom.png", (5, 165, 1420, 1120)),
"all-chains.png": ("all-chains-expanded.png", (380, 1030, 1040, 1690)),
"prediction-pae.png": ("prediction-af2-pae.png", (355, 1390, 1300, 2180)),
"ensemble.png": ("phase-c-ensemble.png", (380, 812, 1340, 1570)),
}

def main():
DEST.mkdir(parents=True, exist_ok=True)
for name, (original, bounds) in EXAMPLES.items():
path = SOURCE / original
if not path.is_file():
raise FileNotFoundError(f"Missing {path}; rerun the real browser tests.")
with Image.open(path) as picture:
if picture.width < bounds[2] or picture.height < bounds[3]:
raise ValueError(f"{original}: unexpected {picture.size}; update crop after reviewing UI.")
crop = picture.convert("RGB").crop(bounds)
crop.thumbnail((1150, 1500), Image.Resampling.LANCZOS)
crop.save(DEST / name, format="PNG", optimize=True)
print(f"{name}: {crop.width}x{crop.height}")

if __name__ == "__main__":
main()
Loading